diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..27f588f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,23 @@ +sudo: false + +language: php +php: + - 7.0 + +before_script: + - phpenv config-rm xdebug.ini + - pecl install channel://pecl.php.net/pthreads-3.1.6 + - pecl install channel://pecl.php.net/weakref-0.3.2 + - echo | pecl install channel://pecl.php.net/yaml-2.0.0 + +script: + - ./tests/ci.sh + +notifications: + email: false + webhooks: + urls: + - https://webhooks.gitter.im/e/e51c4708fdbca6d5ee37 + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: never # options: [always|never|change] default: always diff --git a/README.md b/README.md index e8673ca..3d9fed8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # DevMine The new mcpe software that does not use pm code base! +## IMPORTANT NOTICE: +For the purpose of this Beta Program, the yml and properties files are already pasted. When it becomes stable, we will remove them. + # Why is it called DevMine? Simply because you need to understand php in order to convert PocketMine plugins into DevMine plugins! @@ -15,24 +18,24 @@ pocketmine\block --> devmine\inventory\blocks
pocketmine\item --> devmine\inventory\items
pocketmine\inventory --> devmine\inventory\layout
pocketmine\tile --> devmine\inventory\solidentity
-pocketmine\updater --> devmine\server\updater
-pocketmine\utils --> devmine\utilities\main
-pocketmine not in folder (exclude player and iplayer) --> devmine\server
-pocketmine\network --> devmine\server\network
-pocketmine\lang --> devmine\utilities\languages
-pocketmine\wizard --> devmine\utilities\installer
+pocketmine\plugin --> devmine\consumer\plugin
+pocketmine\resourcepacks --> devmine\consumer\resourcepacks
pocketmine\nbt--> devmine\creatures\player
-player.php and iplayer.php --> devmine\creatures\player
+player.php and iplayer.php and offlineplayer.php --> devmine\creatures\player
pocketmine\entity --> devmine\creatures\entities
+pocketmine not in folder (exclude player and iplayer and offlineplayer) --> devmine\server
+pocketmine\network --> devmine\server\network
+pocketmine\permission --> devmine\server\perms
+pocketmine\resources --> devmine\server\resources
+pocketmine\scheduler --> devmine\server\tasks
pocketmine\command --> devmine\server\commands
-pocketmine\plugin --> devmine\plugin-features
-pocketmine\level --> devmine\levels
-pocketmine\metadata --> devmine\server\epilogos
+pocketmine\metadata --> devmine\server\meta
pocketmine\math --> devmine\server\calculations
+pocketmine\lang --> devmine\utilities\languages
+pocketmine\wizard --> devmine\utilities\installer
+pocketmine\utils --> devmine\utilities\main
+pocketmine\level --> devmine\worlds
pocketmine\event --> devmine\events
-pocketmine\permission --> devmine\server\permissions
-pocketmine\resources --> devmine\server\resources
-pocketmine\scheduler --> devmine\server\tasks
raklib --> raklib
spl --> spl
@@ -42,20 +45,10 @@ pocketmine\tile\Tile.php --> devmine\inventory\solidentity\SolidEntity.php
pocketmine\player.php --> devmine\creatures\player\Player.php
pocketmine\iplayer.php --> devmine\creatures\player\iPlayer.php
pocketmine\OfflinePlayer.php --> devmine\creatures\player\OfflinePlayer.php
-Achievement.php -CompatibleClassLoader.php -CrashDump.php -MemoryManager.php -OfflinePlayer.php -Server.php -Thread.php -ThreadManager.php -Worker.php # THINGS TO CHANGE remove all instances of pocketmine, rename to devmine
-remove all instances of tiles, rename to solidentity -remove all instances of genysis, rename to devmine -remove all instances of scheduler, rename to tasks -remove all instances of metadata, rename to epilogos -Everybody plz tell me if any other things i need to change. +remove all instances of tiles, rename to solidentity
+remove all instances of genysis and tesseract and pocketmine, rename to devmine
+remove all instances of scheduler, rename to tasks
+remove all instances of metadata, rename to meta
diff --git a/bin/cygwin-console-helper.exe b/bin/cygwin-console-helper.exe new file mode 100644 index 0000000..221ed5d Binary files /dev/null and b/bin/cygwin-console-helper.exe differ diff --git a/bin/cygwin1.dll b/bin/cygwin1.dll new file mode 100644 index 0000000..5b4d2f5 Binary files /dev/null and b/bin/cygwin1.dll differ diff --git a/bin/mintty.exe b/bin/mintty.exe new file mode 100644 index 0000000..0e904d1 Binary files /dev/null and b/bin/mintty.exe differ diff --git a/bin/php/deplister.exe b/bin/php/deplister.exe new file mode 100644 index 0000000..d3c79d7 Binary files /dev/null and b/bin/php/deplister.exe differ diff --git a/bin/php/dev/php7ts.lib b/bin/php/dev/php7ts.lib new file mode 100644 index 0000000..b6e30a0 Binary files /dev/null and b/bin/php/dev/php7ts.lib differ diff --git a/bin/php/ext/php_bz2.dll b/bin/php/ext/php_bz2.dll new file mode 100644 index 0000000..6d8d3d0 Binary files /dev/null and b/bin/php/ext/php_bz2.dll differ diff --git a/bin/php/ext/php_com_dotnet.dll b/bin/php/ext/php_com_dotnet.dll new file mode 100644 index 0000000..0bd6394 Binary files /dev/null and b/bin/php/ext/php_com_dotnet.dll differ diff --git a/bin/php/ext/php_curl.dll b/bin/php/ext/php_curl.dll new file mode 100644 index 0000000..cea57c2 Binary files /dev/null and b/bin/php/ext/php_curl.dll differ diff --git a/bin/php/ext/php_enchant.dll b/bin/php/ext/php_enchant.dll new file mode 100644 index 0000000..9622d66 Binary files /dev/null and b/bin/php/ext/php_enchant.dll differ diff --git a/bin/php/ext/php_exif.dll b/bin/php/ext/php_exif.dll new file mode 100644 index 0000000..1c66cc1 Binary files /dev/null and b/bin/php/ext/php_exif.dll differ diff --git a/bin/php/ext/php_fileinfo.dll b/bin/php/ext/php_fileinfo.dll new file mode 100644 index 0000000..3eb2d72 Binary files /dev/null and b/bin/php/ext/php_fileinfo.dll differ diff --git a/bin/php/ext/php_ftp.dll b/bin/php/ext/php_ftp.dll new file mode 100644 index 0000000..eedde38 Binary files /dev/null and b/bin/php/ext/php_ftp.dll differ diff --git a/bin/php/ext/php_gd2.dll b/bin/php/ext/php_gd2.dll new file mode 100644 index 0000000..7ed3fbb Binary files /dev/null and b/bin/php/ext/php_gd2.dll differ diff --git a/bin/php/ext/php_gettext.dll b/bin/php/ext/php_gettext.dll new file mode 100644 index 0000000..138db2e Binary files /dev/null and b/bin/php/ext/php_gettext.dll differ diff --git a/bin/php/ext/php_gmp.dll b/bin/php/ext/php_gmp.dll new file mode 100644 index 0000000..41296d6 Binary files /dev/null and b/bin/php/ext/php_gmp.dll differ diff --git a/bin/php/ext/php_imap.dll b/bin/php/ext/php_imap.dll new file mode 100644 index 0000000..d5c0ba7 Binary files /dev/null and b/bin/php/ext/php_imap.dll differ diff --git a/bin/php/ext/php_interbase.dll b/bin/php/ext/php_interbase.dll new file mode 100644 index 0000000..145555f Binary files /dev/null and b/bin/php/ext/php_interbase.dll differ diff --git a/bin/php/ext/php_intl.dll b/bin/php/ext/php_intl.dll new file mode 100644 index 0000000..48db483 Binary files /dev/null and b/bin/php/ext/php_intl.dll differ diff --git a/bin/php/ext/php_ldap.dll b/bin/php/ext/php_ldap.dll new file mode 100644 index 0000000..05cffda Binary files /dev/null and b/bin/php/ext/php_ldap.dll differ diff --git a/bin/php/ext/php_mbstring.dll b/bin/php/ext/php_mbstring.dll new file mode 100644 index 0000000..78a327f Binary files /dev/null and b/bin/php/ext/php_mbstring.dll differ diff --git a/bin/php/ext/php_mysqli.dll b/bin/php/ext/php_mysqli.dll new file mode 100644 index 0000000..200cd52 Binary files /dev/null and b/bin/php/ext/php_mysqli.dll differ diff --git a/bin/php/ext/php_oci8_12c.dll b/bin/php/ext/php_oci8_12c.dll new file mode 100644 index 0000000..c5aa4ca Binary files /dev/null and b/bin/php/ext/php_oci8_12c.dll differ diff --git a/bin/php/ext/php_odbc.dll b/bin/php/ext/php_odbc.dll new file mode 100644 index 0000000..3d1da03 Binary files /dev/null and b/bin/php/ext/php_odbc.dll differ diff --git a/bin/php/ext/php_opcache.dll b/bin/php/ext/php_opcache.dll new file mode 100644 index 0000000..85d642a Binary files /dev/null and b/bin/php/ext/php_opcache.dll differ diff --git a/bin/php/ext/php_openssl.dll b/bin/php/ext/php_openssl.dll new file mode 100644 index 0000000..f1862ce Binary files /dev/null and b/bin/php/ext/php_openssl.dll differ diff --git a/bin/php/ext/php_pdo_firebird.dll b/bin/php/ext/php_pdo_firebird.dll new file mode 100644 index 0000000..b19e157 Binary files /dev/null and b/bin/php/ext/php_pdo_firebird.dll differ diff --git a/bin/php/ext/php_pdo_mysql.dll b/bin/php/ext/php_pdo_mysql.dll new file mode 100644 index 0000000..af8b21b Binary files /dev/null and b/bin/php/ext/php_pdo_mysql.dll differ diff --git a/bin/php/ext/php_pdo_oci.dll b/bin/php/ext/php_pdo_oci.dll new file mode 100644 index 0000000..8cfc3b0 Binary files /dev/null and b/bin/php/ext/php_pdo_oci.dll differ diff --git a/bin/php/ext/php_pdo_odbc.dll b/bin/php/ext/php_pdo_odbc.dll new file mode 100644 index 0000000..62da60e Binary files /dev/null and b/bin/php/ext/php_pdo_odbc.dll differ diff --git a/bin/php/ext/php_pdo_pgsql.dll b/bin/php/ext/php_pdo_pgsql.dll new file mode 100644 index 0000000..2e24dfa Binary files /dev/null and b/bin/php/ext/php_pdo_pgsql.dll differ diff --git a/bin/php/ext/php_pdo_sqlite.dll b/bin/php/ext/php_pdo_sqlite.dll new file mode 100644 index 0000000..02f74bd Binary files /dev/null and b/bin/php/ext/php_pdo_sqlite.dll differ diff --git a/bin/php/ext/php_pgsql.dll b/bin/php/ext/php_pgsql.dll new file mode 100644 index 0000000..4ba758a Binary files /dev/null and b/bin/php/ext/php_pgsql.dll differ diff --git a/bin/php/ext/php_phpdbg_webhelper.dll b/bin/php/ext/php_phpdbg_webhelper.dll new file mode 100644 index 0000000..9dda997 Binary files /dev/null and b/bin/php/ext/php_phpdbg_webhelper.dll differ diff --git a/bin/php/ext/php_pthreads.dll b/bin/php/ext/php_pthreads.dll new file mode 100644 index 0000000..c315a2e Binary files /dev/null and b/bin/php/ext/php_pthreads.dll differ diff --git a/bin/php/ext/php_shmop.dll b/bin/php/ext/php_shmop.dll new file mode 100644 index 0000000..c47a55d Binary files /dev/null and b/bin/php/ext/php_shmop.dll differ diff --git a/bin/php/ext/php_snmp.dll b/bin/php/ext/php_snmp.dll new file mode 100644 index 0000000..b0328e1 Binary files /dev/null and b/bin/php/ext/php_snmp.dll differ diff --git a/bin/php/ext/php_soap.dll b/bin/php/ext/php_soap.dll new file mode 100644 index 0000000..2b2da43 Binary files /dev/null and b/bin/php/ext/php_soap.dll differ diff --git a/bin/php/ext/php_sockets.dll b/bin/php/ext/php_sockets.dll new file mode 100644 index 0000000..0d6f098 Binary files /dev/null and b/bin/php/ext/php_sockets.dll differ diff --git a/bin/php/ext/php_sqlite3.dll b/bin/php/ext/php_sqlite3.dll new file mode 100644 index 0000000..9106bb3 Binary files /dev/null and b/bin/php/ext/php_sqlite3.dll differ diff --git a/bin/php/ext/php_sysvshm.dll b/bin/php/ext/php_sysvshm.dll new file mode 100644 index 0000000..9f376e9 Binary files /dev/null and b/bin/php/ext/php_sysvshm.dll differ diff --git a/bin/php/ext/php_tidy.dll b/bin/php/ext/php_tidy.dll new file mode 100644 index 0000000..7972b27 Binary files /dev/null and b/bin/php/ext/php_tidy.dll differ diff --git a/bin/php/ext/php_weakref.dll b/bin/php/ext/php_weakref.dll new file mode 100644 index 0000000..2ecae1a Binary files /dev/null and b/bin/php/ext/php_weakref.dll differ diff --git a/bin/php/ext/php_xmlrpc.dll b/bin/php/ext/php_xmlrpc.dll new file mode 100644 index 0000000..1cdf13d Binary files /dev/null and b/bin/php/ext/php_xmlrpc.dll differ diff --git a/bin/php/ext/php_xsl.dll b/bin/php/ext/php_xsl.dll new file mode 100644 index 0000000..c3d4179 Binary files /dev/null and b/bin/php/ext/php_xsl.dll differ diff --git a/bin/php/ext/php_yaml.dll b/bin/php/ext/php_yaml.dll new file mode 100644 index 0000000..a721437 Binary files /dev/null and b/bin/php/ext/php_yaml.dll differ diff --git a/bin/php/extras/ssl/openssl.cnf b/bin/php/extras/ssl/openssl.cnf new file mode 100644 index 0000000..1eb86c4 --- /dev/null +++ b/bin/php/extras/ssl/openssl.cnf @@ -0,0 +1,350 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = AU +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = ./demoCA # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) + +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = md5, sha1 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) diff --git a/bin/php/glib-2.dll b/bin/php/glib-2.dll new file mode 100644 index 0000000..9dac826 Binary files /dev/null and b/bin/php/glib-2.dll differ diff --git a/bin/php/gmodule-2.dll b/bin/php/gmodule-2.dll new file mode 100644 index 0000000..005eefd Binary files /dev/null and b/bin/php/gmodule-2.dll differ diff --git a/bin/php/icudt57.dll b/bin/php/icudt57.dll new file mode 100644 index 0000000..72433a8 Binary files /dev/null and b/bin/php/icudt57.dll differ diff --git a/bin/php/icuin57.dll b/bin/php/icuin57.dll new file mode 100644 index 0000000..d57005e Binary files /dev/null and b/bin/php/icuin57.dll differ diff --git a/bin/php/icuio57.dll b/bin/php/icuio57.dll new file mode 100644 index 0000000..9769c07 Binary files /dev/null and b/bin/php/icuio57.dll differ diff --git a/bin/php/icule57.dll b/bin/php/icule57.dll new file mode 100644 index 0000000..9d06741 Binary files /dev/null and b/bin/php/icule57.dll differ diff --git a/bin/php/iculx57.dll b/bin/php/iculx57.dll new file mode 100644 index 0000000..66d3403 Binary files /dev/null and b/bin/php/iculx57.dll differ diff --git a/bin/php/icuuc57.dll b/bin/php/icuuc57.dll new file mode 100644 index 0000000..09a7b8b Binary files /dev/null and b/bin/php/icuuc57.dll differ diff --git a/bin/php/install.txt b/bin/php/install.txt new file mode 100644 index 0000000..be87921 --- /dev/null +++ b/bin/php/install.txt @@ -0,0 +1,1797 @@ +Installing PHP + __________________________________________________________________ + + Table of Contents + Preface + 1. General Installation Considerations + 2. Installation on Windows systems + + Manual Installation Steps + ActiveScript + Microsoft IIS + Apache 1.3.x on Microsoft Windows + Apache 2.0.x on Microsoft Windows + Sun, iPlanet and Netscape servers on Microsoft Windows + OmniHTTPd Server + Sambar Server on Microsoft Windows + Xitami on Microsoft Windows + Installation of extensions on Windows + + 3. Installation of PECL extensions + + Introduction to PECL Installations + Downloading PECL extensions + PECL for Windows users + Compiling shared PECL extensions with the pecl command + Compiling shared PECL extensions with phpize + Compiling PECL extensions statically into PHP + + 4. Problems? + + Read the FAQ + Other problems + Bug reports + + 5. Runtime Configuration + + The configuration file + How to change configuration settings + + 6. Installation FAQ + __________________________________________________________________ + +Preface + + These installation instructions were generated from the HTML version of + the PHP Manual so formatting and linking have been altered. See the + online and updated version at: http://php.net/install.windows + __________________________________________________________________ + +Chapter 1. General Installation Considerations + + Before starting the installation, first you need to know what do you + want to use PHP for. There are three main fields you can use PHP, as + described in the What can PHP do? section: + + * Websites and web applications (server-side scripting) + * Command line scripting + * Desktop (GUI) applications + + For the first and most common form, you need three things: PHP itself, + a web server and a web browser. You probably already have a web + browser, and depending on your operating system setup, you may also + have a web server (e.g. Apache on Linux and MacOS X; IIS on Windows). + You may also rent webspace at a company. This way, you don't need to + set up anything on your own, only write your PHP scripts, upload it to + the server you rent, and see the results in your browser. + + In case of setting up the server and PHP on your own, you have two + choices for the method of connecting PHP to the server. For many + servers PHP has a direct module interface (also called SAPI). These + servers include Apache, Microsoft Internet Information Server, Netscape + and iPlanet servers. Many other servers have support for ISAPI, the + Microsoft module interface (OmniHTTPd for example). If PHP has no + module support for your web server, you can always use it as a CGI or + FastCGI processor. This means you set up your server to use the CGI + executable of PHP to process all PHP file requests on the server. + + If you are also interested to use PHP for command line scripting (e.g. + write scripts autogenerating some images for you offline, or processing + text files depending on some arguments you pass to them), you always + need the command line executable. For more information, read the + section about writing command line PHP applications. In this case, you + need no server and no browser. + + With PHP you can also write desktop GUI applications using the PHP-GTK + extension. This is a completely different approach than writing web + pages, as you do not output any HTML, but manage Windows and objects + within them. For more information about PHP-GTK, please visit the site + dedicated to this extension. PHP-GTK is not included in the official + PHP distribution. + + From now on, this section deals with setting up PHP for web servers on + Unix and Windows with server module interfaces and CGI executables. You + will also find information on the command line executable in the + following sections. + + PHP source code and binary distributions for Windows can be found at + http://www.php.net/downloads.php. We recommend you to choose a mirror + nearest to you for downloading the distributions. + __________________________________________________________________ + +Chapter 2. Installation on Windows systems + + This section applies to Windows 98/Me and Windows NT/2000/XP/2003. PHP + will not work on 16 bit platforms such as Windows 3.1 and sometimes we + refer to the supported Windows platforms as Win32. Windows 95 is no + longer supported as of PHP 4.3.0. + + If you have Microsoft Visual Studio, you can also build PHP from the + original source code. + + Once you have PHP installed on your Windows system, you may also want + to load various extensions for added functionality. + + Warning + + There are several all-in-one installers over the Internet, but none of + those are endorsed by PHP.net, as we believe that the manual + installation is the best choice to have your system secure and + optimised. + __________________________________________________________________ + +Manual Installation Steps + + This install guide will help you manually install and configure PHP + with a web server on Microsoft Windows. To get started you'll need to + download the zip binary distribution from the downloads page at + http://www.php.net/downloads.php. + + Although there are many all-in-one installation kits, we recommend you + take the time to setup PHP yourself as this will provide you with a + better understanding of the system, and enables you to install PHP + extensions easily when needed. + + Upgrading from a previous PHP version: Previous editions of the + manual suggest moving various ini and DLL files into your SYSTEM + (i.e. C:\WINDOWS) folder and while this simplifies the installation + procedure it makes upgrading difficult. We advise you remove all of + these files (like php.ini and PHP related DLLs from the Windows + SYSTEM folder) before moving on with a new PHP installation. Be sure + to backup these files as you might break the entire system. The old + php.ini might be useful in setting up the new PHP as well. And as + you'll soon learn, the preferred method for installing PHP is to + keep all PHP related files in one directory and have this directory + available to your systems PATH. + + MDAC requirements: If you use Microsoft Windows 98/NT4 download the + latest version of the Microsoft Data Access Components (MDAC) for + your platform. MDAC is available at http://msdn.microsoft.com/data/. + This requirement exists because ODBC is built into the distributed + Windows binaries. + + The following steps should be completed on all installations before any + server specific instructions are performed: + + Extract the distribution file into a directory of your choice. If you + are installing PHP 4, extract to C:\, as the zip file expands to a + foldername like php-4.3.7-Win32. If you are installing PHP 7, extract + to C:\php as the zip file doesn't expand as in PHP 4. You may choose a + different location but do not have spaces in the path (like C:\Program + Files\PHP) as some web servers will crash if you do. + + The directory structure extracted from the zip is different for PHP + versions 4 and 5 and look like as follows: + + Example 2-2. PHP 7 package structure +c:\php + | + +--dev + | | + | |-php7ts.lib + | + +--ext -- extension DLLs for PHP + | | + | |-php_bz2.dll + | | + | |-php_cpdf.dll + | | + | |-.. + | + +--extras + | | + | +--mibs -- support files for SNMP + | | + | +--openssl -- support files for Openssl + | | + | +--pdf-related -- support files for PDF + | | + | |-mime.magic + | + +--pear -- initial copy of PEAR + | + | + |-go-pear.bat -- PEAR setup script + | + |-fdftk.dll + | + |-.. + | + |-php-cgi.exe -- CGI executable + | + |-php-win.exe -- executes scripts without an opened command prompt + | + |-php.exe -- CLI executable - ONLY for command line scripting + | + |-.. + | + |-php.ini-development -- development php.ini settings + | + |-php.ini-production -- recommended php.ini settings for production + | + |-php5activescript.dll + | + |-php7apache2_4.dll + | + |-.. + | + |-php5ts.dll -- core PHP DLL + | + |-... + + Notice the differences and similarities. Both PHP 4 and PHP 5 have a + CGI executable, a CLI executable, and server modules, but they are + located in different folders and/or have different names. While PHP 4 + packages have the server modules in the sapi folder, PHP 5 + distributions have no such directory and instead they're in the PHP + folder root. The supporting DLLs for the PHP 5 extensions are also not + in a separate directory. + + Note: In PHP 4, you should move all files located in the dll and + sapi folders to the main folder (e.g. C:\php). + + Here is a list of server modules shipped with PHP 5: + + * php7apache2_4.dll - Apache 2.4.x module. + + Server modules provide significantly better performance and additional + functionality compared to the CGI binary. The FastCGI is significantly + more stable and can be faster than the ISAPI module with IIS. + The CLI version is designed to let you use PHP for command line + scripting. More information about CLI is available in the chapter + about using PHP from the command line. + + Warning + + The SAPI modules have been significantly improved as of the 4.1 + release, however, in older systems you may encounter server errors or + other server modules failing, such as ASP. + + The CGI and CLI binaries, and the web server modules all require the + php7ts.dll file to be available to them. You have to make + sure that this file can be found by your PHP installation. The search + order for this DLL is as follows: + + * The same directory from where php.exe is called, or in case you use + a SAPI module, the web server's directory (e.g. C:\Program + Files\Apache Group\Apache2\bin). + * Any directory in your Windows PATH environment variable. + + To make php7ts.dll available you have three options: copy + the file to the Windows system directory, copy the file to the web + server's directory, or add your PHP directory, C:\php to the PATH. For + better maintenance, we advise you to follow the last option, add C:\php + to the PATH, because it will be simpler to upgrade PHP in the future. + Read more about how to add your PHP directory to PATH in the + corresponding FAQ entry (and then don't forget to restart the computer + - logoff isn't enough). + + The next step is to set up a valid configuration file for PHP, php.ini. + There are two ini files distributed in the zip file, php.ini-development + and php.ini-production. We advise you to use php.ini-production, + because we optimized the default settings in this file for performance, + and security. Read this well documented file carefully because it has + changes from php.ini-production that will drastically affect your setup. + Some examples are display_errors being off and magic_quotes_gpc being off. + In addition to reading these, study the ini settings and set every + element manually yourself. If you would like to achieve the best + security, then this is the way for you, although PHP works fine with + these default ini files. Copy your chosen ini-file to a directory that + PHP is able to find and rename it to php.ini. PHP searches for php.ini + in the locations described in the Section called The configuration file + in Chapter 5 section. + + If you are running Apache 2, the simpler option is to use the PHPIniDir + directive (read the installation on Apache 2 page), otherwise your best + option is to set the PHPRC environment variable. This process is + explained in the following FAQ entry. + + Note: If you're using NTFS on Windows NT, 2000, XP or 2003, make + sure that the user running the web server has read permissions to + your php.ini (e.g. make it readable by Everyone). + + The following steps are optional: + + * Edit your new php.ini file. If you plan to use OmniHTTPd, do not + follow the next step. Set the doc_root to point to your web servers + document_root. For example: + +doc_root = c:\inetpub\wwwroot // for IIS + +doc_root = c:\apache\htdocs // for Apache + + * Choose the extensions you would like to load when PHP starts. See + the section about Windows extensions, about how to set up one, and + what is already built in. Note that on a new installation it is + advisable to first get PHP working and tested without any + extensions before enabling them in php.ini. + + PHP is now setup on your system. The next step is to choose a web + server, and enable it to run PHP. Choose a web server from the table of + contents. + __________________________________________________________________ + +ActiveScript + + This section contains notes specific to the ActiveScript installation. + + ActiveScript is a Windows only SAPI that enables you to use PHP script + in any ActiveScript compliant host, like Windows Script Host, + ASP/ASP.NET, Windows Script Components or Microsoft Scriptlet control. + + As of PHP 5.0.1, ActiveScript has been moved to the PECL repository. + The DLL for this PECL extension may be downloaded from either the PHP + Downloads page or from http://pecl4win.php.net/ + + Note: You should read the manual installation steps first! + + After installing PHP, you should download the ActiveScript DLL + (php7activescript.dll) and place it in the main PHP folder (e.g. + C:\php). + + After having all the files needed, you must register the DLL on your + system. To achieve this, open a Command Prompt window (located in the + Start Menu). Then go to your PHP directory by typing something like cd + C:\php. To register the DLL just type regsvr32 php7activescript.dll. + + To test if ActiveScript is working, create a new file, named test.wsf + (the extension is very important) and type: + + + + + + + Save and double-click on the file. If you receive a little window + saying "Hello World!" you're done. + + Note: In PHP 4, the engine was named 'ActivePHP', so if you are + using PHP 4, you should replace 'PHPScript' with 'ActivePHP' in the + above example. + + Note: ActiveScript doesn't use the default php.ini file. Instead, it + will look only in the same directory as the .exe that caused it to + load. You should create php-activescript.ini and place it in that + folder, if you wish to load extensions, etc. + __________________________________________________________________ + +Microsoft IIS + + This section contains notes and hints specific to IIS (Microsoft + Internet Information Server). + + Warning + + By using the CGI setup, your server is open to several possible + attacks. Please read our CGI security section to learn how to defend + yourself from those attacks. + __________________________________________________________________ + +General considerations for all installations of PHP with IIS + + * First, read the Manual Installation Instructions. Do not skip this + step as it provides crucial information for installing PHP on + Windows. + * CGI users must set the cgi.force_redirect PHP directive to 0 inside + php.ini. Read the faq on cgi.force_redirect for important details. + Also, CGI users may want to set the cgi.redirect_status_env + directive. When using directives, be sure these directives aren't + commented out inside php.ini. + * The PHP 4 CGI is named php.exe while in PHP 7 it's php-cgi.exe. In + PHP 7, php.exe is the CLI, and not the CGI. + * Modify the Windows PATH environment variable to include the PHP + directory. This way the PHP DLL files and PHP executables can all + remain in the PHP directory without cluttering up the Windows + system directory. For more details, see the FAQ on Setting the + PATH. + * The IIS user (usually IUSR_MACHINENAME) needs permission to read + various files and directories, such as php.ini, docroot, and the + session tmp directory. + * Be sure the extension_dir and doc_root PHP directives are + appropriately set in php.ini. These directives depend on the system + that PHP is being installed on. In PHP 4, the extension_dir is + extensions while with PHP 7 it's ext. So, an example PHP 7 + extensions_dir value is "c:\php\ext" and an example IIS doc_root + value is "c:\Inetpub\wwwroot". + * PHP extension DLL files, such as php_mysql.dll and php_curl.dll, + are found in the zip package of the PHP download. In PHP 7, many + extensions are part of PECL and can be downloaded in the + "Collection of PECL modules" package. Files such as php_zip.dll and + php_ssh2.dll. Download PHP files here. + * When defining the executable, the 'check that file exists' box may + also be checked. For a small performance penalty, the IIS + will check that the script file exists and sort out authentication + before firing up PHP. This means that the web server will provide + sensible 404 style error messages instead of CGI errors complaining + that PHP did not output any data. + __________________________________________________________________ + +Windows NT/200x/XP and IIS 4 or newer + + PHP may be installed as a CGI binary, or with the ISAPI module. In + either case, you need to start the Microsoft Management Console (may + appear as 'Internet Services Manager', either in your Windows NT 4.0 + Option Pack branch or the Control Panel=>Administrative Tools under + Windows 2000/XP). Then right click on your Web server node (this will + most probably appear as 'Default Web Server'), and select 'Properties'. + + If you want to use the CGI binary, do the following: + + * Under 'Home Directory', 'Virtual Directory', or 'Directory', do the + following: + * Change the Execute Permissions to 'Scripts only' + * Click on the 'Configuration' button, and choose the Application + Mappings tab. Click Add and set the Executable path to the + appropriate CGI file. An example PHP 7 value is: C:\php\php-cgi.exe + Supply .php as the extension. Leave 'Method exclusions' blank, and + check the 'Script engine' checkbox. Now, click OK a few times. + * Set up the appropriate security. (This is done in Internet Service + Manager), and if your NT Server uses NTFS file system, add execute + rights for I_USR_ to the directory that contains php.exe / + php-cgi.exe. + + To use the ISAPI module, do the following: + + * If you don't want to perform HTTP Authentication using PHP, you can + (and should) skip this step. Under ISAPI Filters, add a new ISAPI + filter. Use PHP as the filter name, and supply a path to the + php7isapi.dll. + * Under 'Home Directory', 'Virtual Directory', or 'Directory', do the + following: + * Change the Execute Permissions to 'Scripts only' + * Click on the 'Configuration' button, and choose the Application + Mappings tab. Click Add and set the Executable path to the + appropriate ISAPI DLL. An example PHP 7 value is: + C:\php\php7isapi.dll Supply .php as the extension. Leave 'Method + exclusions' blank, and check the 'Script engine' checkbox. Now, + click OK a few times. + * Stop IIS completely (NET STOP iisadmin) + * Start IIS again (NET START w3svc) + + With IIS 6 (2003 Server), open up the IIS Manager, go to Web Service + Extensions, choose "Add a new Web service extension", enter in a name + such as PHP, choose the Add button and for the value browse to either + the ISAPI file (php7isapi.dll) or CGI (php.exe or + php-cgi.exe) then check "Set extension status to Allowed" and click OK. + + In order to use index.php as a default content page, do the following: + From within the Documents tab, choose Add. Type in index.php and click + OK. Adjust the order by choosing Move Up or Move Down. This is similar + to setting DirectoryIndex with Apache. + + The steps above must be repeated for each extension that is to be + associated with PHP scripts. .php is the most common although .php3 may + be required for legacy applications. + + If you experience 100% CPU usage after some time, turn off the IIS + setting Cache ISAPI Application. + __________________________________________________________________ + +Windows and IIS + +See http://www.php.net/install.windows + __________________________________________________________________ + +Apache 1.3.x on Microsoft Windows + + This section contains notes and hints specific to Apache 1.3.x installs + of PHP on Microsoft Windows systems. There are also instructions and + notes for Apache 2 on a separate page. + + Note: Please read the manual installation steps first! + + There are two ways to set up PHP to work with Apache 1.3.x on Windows. + One is to use the CGI binary (php.exe for PHP 4 and php-cgi.exe for PHP + 5), the other is to use the Apache Module DLL. In either case you need + to edit your httpd.conf to configure Apache to work with PHP, and then + restart the server. + + It is worth noting here that now the SAPI module has been made more + stable under Windows, we recommend it's use above the CGI binary, since + it is more transparent and secure. + + Although there can be a few variations of configuring PHP under Apache, + these are simple enough to be used by the newcomer. Please consult the + Apache Documentation for further configuration directives. + + After changing the configuration file, remember to restart the server, + for example, NET STOP APACHE followed by NET START APACHE, if you run + Apache as a Windows Service, or use your regular shortcuts. + + Note: Remember that when adding path values in the Apache + configuration files on Windows, all backslashes such as + c:\directory\file.ext must be converted to forward slashes, as + c:/directory/file.ext. A trailing slash may also be necessary for + directories. + __________________________________________________________________ + +Installing as an Apache module + + You should add the following lines to your Apache httpd.conf file: + + Example 2-3. PHP as an Apache 1.3.x module + + This assumes PHP is installed to c:\php. Adjust the path if this is not + the case. + + For PHP 7: +# Add to the end of the LoadModule section +LoadModule php7_module "C:/php/php7apache.dll" + +# Add to the end of the AddModule section +AddModule mod_php7.c + + For both: +# Add this line inside the conditional brace +AddType application/x-httpd-php .php + +# For syntax highlighted .phps files, also add +AddType application/x-httpd-php-source .phps + __________________________________________________________________ + +Installing as a CGI binary + + If you unzipped the PHP package to C:\php\ as described in the Manual + Installation Steps section, you need to insert these lines to your + Apache configuration file to set up the CGI binary: + + Example 2-4. PHP and Apache 1.3.x as CGI +ScriptAlias /php/ "c:/php/" +AddType application/x-httpd-php .php + +# For PHP 4 +Action application/x-httpd-php "/php/php.exe" + +# For PHP 7 +Action application/x-httpd-php "/php/php-cgi.exe" + +# specify the directory where php.ini is +SetEnv PHPRC C:/php + + Note that the second line in the list above can be found in the actual + versions of httpd.conf, but it is commented out. Remember also to + substitute the c:/php/ for your actual path to PHP. + + Warning + + By using the CGI setup, your server is open to several possible + attacks. Please read our CGI security section to learn how to defend + yourself from those attacks. + + If you would like to present PHP source files syntax highlighted, there + is no such convenient option as with the module version of PHP. If you + chose to configure Apache to use PHP as a CGI binary, you will need to + use the highlight_file() function. To do this simply create a PHP + script file and add this code: . + __________________________________________________________________ + +Apache 2.0.x on Microsoft Windows + + This section contains notes and hints specific to Apache 2.0.x installs + of PHP on Microsoft Windows systems. We also have instructions and + notes for Apache 1.3.x users on a separate page. + + Note: You should read the manual installation steps first! + + Apache 2.2.x Support: Users of Apache 2.2.x may use the + documentation below except the appropriate DLL file is named + php7apache2_2.dll and it only exists as of PHP 7.2.0. See also + http://snaps.php.net/ + + Warning + + We do not recommend using a threaded MPM in production with Apache2. + Use the prefork MPM instead, or use Apache1. For information on why, + read the related FAQ entry on using Apache2 with a threaded MPM + + You are highly encouraged to take a look at the Apache Documentation to + get a basic understanding of the Apache 2.0.x Server. Also consider to + read the Windows specific notes for Apache 2.0.x before reading on + here. + + PHP and Apache 2.0.x compatibility notes: The following versions of + PHP are known to work with the most recent version of Apache 2.0.x: + + * PHP 4.3.0 or later available at http://www.php.net/downloads.php. + * the latest stable development version. Get the source code + http://snaps.php.net/php7-latest.tar.gz or download binaries for + Windows http://snaps.php.net/win32/php7-win32-latest.zip. + * a prerelease version downloadable from http://qa.php.net/. + * you have always the option to obtain PHP through SVN. + + These versions of PHP are compatible to Apache 2.0.40 and later. + + Apache 2.0 SAPI-support started with PHP 4.2.0. PHP 4.2.3 works with + Apache 2.0.39, don't use any other version of Apache with PHP 4.2.3. + However, the recommended setup is to use PHP 4.3.0 or later with the + most recent version of Apache2. + + All mentioned versions of PHP will work still with Apache 1.3.x. + + Warning + + Apache 2.0.x is designed to run on Windows NT 4.0, Windows 2000 or + Windows XP. At this time, support for Windows 9x is incomplete. Apache + 2.0.x is not expected to work on those platforms at this time. + + Download the most recent version of Apache 2.0.x and a fitting PHP + version. Follow the Manual Installation Steps and come back to go on + with the integration of PHP and Apache. + + There are two ways to set up PHP to work with Apache 2.0.x on Windows. + One is to use the CGI binary the other is to use the Apache module DLL. + In either case you need to edit your httpd.conf to configure Apache to + work with PHP and then restart the server. + + Note: Remember that when adding path values in the Apache + configuration files on Windows, all backslashes such as + c:\directory\file.ext must be converted to forward slashes, as + c:/directory/file.ext. A trailing slash may also be necessary for + directories. + __________________________________________________________________ + +Installing as a CGI binary + + You need to insert these three lines to your Apache httpd.conf + configuration file to set up the CGI binary: + + Example 2-5. PHP and Apache 2.0 as CGI +ScriptAlias /php/ "c:/php/" +AddType application/x-httpd-php .php + +# For PHP 4 +Action application/x-httpd-php "/php/php.exe" + +# For PHP 7 +Action application/x-httpd-php "/php/php-cgi.exe" + + Warning + + By using the CGI setup, your server is open to several possible + attacks. Please read our CGI security section to learn how to defend + yourself from those attacks. + __________________________________________________________________ + +Installing as an Apache module + + You need to insert these two lines to your Apache httpd.conf + configuration file to set up the PHP module for Apache 2.0: + + Example 2-6. PHP and Apache 2.0 as Module + +# For PHP 7 do something like this: +LoadModule php7_module "c:/php/php7apache2.dll" +AddType application/x-httpd-php .php + +# configure the path to php.ini +PHPIniDir "C:/php" + + Note: Remember to substitute your actual path to PHP for the c:/php/ + in the above examples. Take care to use either + php5apache2.dll in your LoadModule directive and not php5apache.dll + as the latter ones are designed to run with Apache 1.3.x. + + Note: If you want to use content negotiation, read related FAQ. + + Warning + + Don't mix up your installation with DLL files from different PHP + versions. You have the only choice to use the DLL's and extensions that + ship with your downloaded PHP version. + __________________________________________________________________ + +Sun, iPlanet and Netscape servers on Microsoft Windows + + This section contains notes and hints specific to Sun Java System Web + Server, Sun ONE Web Server, iPlanet and Netscape server installs of PHP + on Windows. + + From PHP 4.3.3 on you can use PHP scripts with the NSAPI module to + generate custom directory listings and error pages. Additional + functions for Apache compatibility are also available. For support in + current web servers read the note about subrequests. + __________________________________________________________________ + +CGI setup on Sun, iPlanet and Netscape servers + + To install PHP as a CGI handler, do the following: + + * Copy php7ts.dll to your systemroot (the directory where you + installed Windows) + * Make a file association from the command line. Type the following + two lines: + +assoc .php=PHPScript +ftype PHPScript=c:\php\php.exe %1 %* + + * In the Netscape Enterprise Administration Server create a dummy + shellcgi directory and remove it just after (this step creates 5 + important lines in obj.conf and allow the web server to handle + shellcgi scripts). + * In the Netscape Enterprise Administration Server create a new mime + type (Category: type, Content-Type: magnus-internal/shellcgi, File + Suffix:php). + * Do it for each web server instance you want PHP to run + + More details about setting up PHP as a CGI executable can be found + here: http://benoit.noss.free.fr/php/install-php.html + __________________________________________________________________ + +NSAPI setup on Sun, iPlanet and Netscape servers + + To install PHP with NSAPI, do the following: + + * Copy php7ts.dll to your systemroot (the directory where you + installed Windows) + * Make a file association from the command line. Type the following + two lines: + +assoc .php=PHPScript +ftype PHPScript=c:\php\php.exe %1 %* + + * In the Netscape Enterprise Administration Server create a new mime + type (Category: type, Content-Type: magnus-internal/x-httpd-php, + File Suffix: php). + * Edit magnus.conf (for servers >= 6) or obj.conf (for servers < 6) + and add the following: You should place the lines after mime types + init. + +Init fn="load-modules" funcs="php7_init,php7_execute,php7_auth_trans" shlib="c:/ +php/sapi/php7nsapi.dll" +Init fn="php7_init" LateInit="yes" errorString="Failed to initialise PHP!" [php_ +ini="c:/path/to/php.ini"] + + The php_ini parameter is optional but with it you + can place your php.ini in your web server configuration directory. + * Configure the default object in obj.conf (for virtual server + classes [Sun Web Server 6.0+] in their vserver.obj.conf): In the + section, place this line necessarily after + all 'ObjectType' and before all 'AddLog' lines: + +Service fn="php7_execute" type="magnus-internal/x-httpd-php" [inikey=value inike +y=value ...] + + As additional parameters you can add some special + php.ini-values, for example you can set a + docroot="/path/to/docroot" specific to the context php7_execute is + called. For boolean ini-keys please use 0/1 as value, not + "On","Off",... (this will not work correctly), e.g. + zlib.output_compression=1 instead of zlib.output_compression="On" + * This is only needed if you want to configure a directory that only + consists of PHP scripts (same like a cgi-bin directory): + + +ObjectType fn="force-type" type="magnus-internal/x-httpd-php" +Service fn=php7_execute [inikey=value inikey=value ...] + + + After that you can configure a directory in the Administration + server and assign it the style x-httpd-php. All files in it will + get executed as PHP. This is nice to hide PHP usage by renaming + files to .html. + * Restart your web service and apply changes + * Do it for each web server instance you want PHP to run + + Note: More details about setting up PHP as an NSAPI filter can be + found here: http://benoit.noss.free.fr/php/install-php4.html + + Note: The stacksize that PHP uses depends on the configuration of + the web server. If you get crashes with very large PHP scripts, it + is recommended to raise it with the Admin Server (in the section + "MAGNUS EDITOR"). + __________________________________________________________________ + +CGI environment and recommended modifications in php.ini + + Important when writing PHP scripts is the fact that Sun JSWS/Sun ONE + WS/iPlanet/Netscape is a multithreaded web server. Because of that all + requests are running in the same process space (the space of the web + server itself) and this space has only one environment. If you want to + get CGI variables like PATH_INFO, HTTP_HOST etc. it is not the correct + way to try this in the old PHP 3.x way with getenv() or a similar way + (register globals to environment, $_ENV). You would only get the + environment of the running web server without any valid CGI variables! + + Note: Why are there (invalid) CGI variables in the environment? + + Answer: This is because you started the web server process from the + admin server which runs the startup script of the web server, you + wanted to start, as a CGI script (a CGI script inside of the admin + server!). This is why the environment of the started web server has + some CGI environment variables in it. You can test this by starting + the web server not from the administration server. Use the command + line as root user and start it manually - you will see there are no + CGI-like environment variables. + __________________________________________________________________ + +Special use for error pages or self-made directory listings (PHP >= 4.3.3) + + You can use PHP to generate the error pages for "404 Not Found" or + similar. Add the following line to the object in obj.conf for every + error page you want to overwrite: +Error fn="php7_execute" code=XXX script="/path/to/script.php" [inikey=value inik +ey=value...] + + where XXX is the HTTP error code. Please delete any other Error + directives which could interfere with yours. If you want to place a + page for all errors that could exist, leave the code parameter out. + Your script can get the HTTP status code with $_SERVER['ERROR_TYPE']. + + Another possibility is to generate self-made directory listings. Just + create a PHP script which displays a directory listing and replace the + corresponding default Service line for type="magnus-internal/directory" + in obj.conf with the following: +Service fn="php7_execute" type="magnus-internal/directory" script="/path/to/scri +pt.php" [inikey=value inikey=value...] + + For both error and directory listing pages the original URI and + translated URI are in the variables $_SERVER['PATH_INFO'] and + $_SERVER['PATH_TRANSLATED']. + __________________________________________________________________ + +Note about nsapi_virtual() and subrequests (PHP >= 4.3.3) + + The NSAPI module now supports the nsapi_virtual() function (alias: + virtual()) to make subrequests on the web server and insert the result + in the web page. The problem is, that this function uses some + undocumented features from the NSAPI library. + + Under Unix this is not a problem, because the module automatically + looks for the needed functions and uses them if available. If not, + nsapi_virtual() is disabled. + + Under Windows limitations in the DLL handling need the use of a + automatic detection of the most recent ns-httpdXX.dll file. This is + tested for servers till version 6.1. If a newer version of the Sun + server is used, the detection fails and nsapi_virtual() is disabled. + + If this is the case, try the following: Add the following parameter to + php7_init in magnus.conf/obj.conf: + Init fn=php7_init ... server_lib="ns-httpdXX.dll" + + where XX is the correct DLL version number. To get it, look in the + server-root for the correct DLL name. The DLL with the biggest filesize + is the right one. + + You can check the status by using the phpinfo() function. + + Note: But be warned: Support for nsapi_virtual() is EXPERIMENTAL!!! + __________________________________________________________________ + +OmniHTTPd Server + + This section contains notes and hints specific to OmniHTTPd on Windows. + + Note: You should read the manual installation steps first! + + Warning + + By using the CGI setup, your server is open to several possible + attacks. Please read our CGI security section to learn how to defend + yourself from those attacks. + + You need to complete the following steps to make PHP work with + OmniHTTPd. This is a CGI executable setup. SAPI is supported by + OmniHTTPd, but some tests have shown that it is not so stable to use + PHP as an ISAPI module. + + Important for CGI users: Read the faq on cgi.force_redirect for + important details. This directive needs to be set to 0. + + 1. Install OmniHTTPd server. + 2. Right click on the blue OmniHTTPd icon in the system tray and + select Properties + 3. Click on Web Server Global Settings + 4. On the 'External' tab, enter: virtual = .php | actual = + c:\php\php.exe (use php-cgi.exe if installing PHP 7), and use the + Add button. + 5. On the Mime tab, enter: virtual = wwwserver/stdcgi | actual = .php, + and use the Add button. + 6. Click OK + + Repeat steps 2 - 6 for each extension you want to associate with PHP. + + __________________________________________________________________ + +Xitami on Microsoft Windows + + This section contains notes and hints specific to Xitami on Windows. + + Note: You should read the manual installation steps first! + + This list describes how to set up the PHP CGI binary to work with + Xitami on Windows. + + Important for CGI users: Read the faq on cgi.force_redirect for + important details. This directive needs to be set to 0. If you want + to use $_SERVER['PHP_SELF'] you have to enable the cgi.fix_pathinfo + directive. + + Warning + + By using the CGI setup, your server is open to several possible + attacks. Please read our CGI security section to learn how to defend + yourself from those attacks. + + * Make sure the web server is running, and point your browser to + xitamis admin console (usually http://127.0.0.1/admin), and click + on Configuration. + * Navigate to the Filters, and put the extension which PHP should + parse (i.e. .php) into the field File extensions (.xxx). + * In Filter command or script put the path and name of your PHP CGI + executable i.e. C:\php\php-cgi.exe. + * Press the 'Save' icon. + * Restart the server to reflect changes. + __________________________________________________________________ + +Installation of extensions on Windows + + After installing PHP and a web server on Windows, you will probably + want to install some extensions for added functionality. You can choose + which extensions you would like to load when PHP starts by modifying + your php.ini. You can also load a module dynamically in your script + using dl(). + + The DLLs for PHP extensions are prefixed with php_. + + Many extensions are built into the Windows version of PHP. This means + additional DLL files, and the extension directive, are not used to load + these extensions. The Windows PHP Extensions table lists extensions + that require, or used to require, additional PHP DLL files. Here's a + list of built in extensions: + + In PHP 7 (updated PHP 5.0.4), the following changes exist. Built in: + DOM, LibXML, Iconv, SimpleXML, SPL and SQLite. And the following are no + longer built in: MySQL and Overload. + + The default location PHP searches for extensions is C:\php7 in PHP 7. + To change this setting to reflect your setup of PHP edit your php.ini + file: + + * You will need to change the extension_dir setting to point to the + directory where your extensions lives, or where you have placed + your php_*.dll files. For example: + +extension_dir = C:\php\extensions + + * Enable the extension(s) in php.ini you want to use by uncommenting + the extension=php_*.dll lines in php.ini. This is done by deleting + the leading ; from the extension you want to load. + + Example 2-8. Enable Bzip2 extension for PHP-Windows +// change the following line from ... +;extension=php_bz2.dll + +// ... to +extension=php_bz2.dll + + * Some of the extensions need extra DLLs to work. Couple of them can + be found in the distribution package, in in the main folder in PHP 5, + but some, for example Oracle (php_oci8.dll) require DLLs which are + not bundled with the distribution package. + * Some of these DLLs are not bundled with the PHP distribution. See + each extensions documentation page for details. Also, read the + manual section titled Installation of PECL extensions for details + on PECL. An increasingly large number of PHP extensions are found + in PECL, and these extensions require a separate download. + + Note: If you are running a server module version of PHP remember to + restart your web server to reflect your changes to php.ini. + + The following table describes some of the extensions available and + required additional dlls. + + Table 2-1. PHP Extensions + Extension Description Notes + php_bz2.dll bzip2 compression functions None + php_calendar.dll Calendar conversion functions + php_cpdf.dll ClibPDF functions None + php_crack.dll Crack functions None + php_ctype.dll ctype family functions + php_curl.dll CURL, Client URL library functions Requires: libeay32.dll, + ssleay32.dll (bundled) + php_db.dll DBM functions Deprecated. Use DBA instead (php_dba.dll) + php_dba.dll DBA: DataBase (dbm-style) Abstraction layer functions None + php_dbase.dll dBase functions None + php_dbx.dll dbx functions + php_exif.dll EXIF functions php_mbstring.dll. And, php_exif.dll must be + loaded after php_mbstring.dll in php.ini. + php_fdf.dll FDF: Forms Data Format functions. Requires: fdftk.dll + (bundled) + php_filepro.dll filePro functions Read-only access + php_ftp.dll FTP functions + php_gd2.dll GD library image functions GD2 + php_gettext.dll Gettext functions, requires libintl-1.dll, + iconv.dll (bundled). + php_iconv.dll ICONV characterset conversion Requires: iconv.dll + php_imap.dll IMAP POP3 and NNTP functions None + php_interbase.dll InterBase functions Requires: gds32.dll (bundled) + php_ldap.dll LDAP functions requires libeay32.dll, ssleay32.dll (bundled) + php_mbstring.dll Multi-Byte String functions None + php_mcrypt.dll Mcrypt Encryption functions Requires: libmcrypt.dll + php_mime_magic.dll Mimetype functions Requires: magic.mime (bundled) + php_ming.dll Ming functions for Flash None + php_msql.dll mSQL functions Requires: msql.dll (bundled) + php_mssql.dll MSSQL functions Requires: ntwdblib.dll (bundled) + php_mysql.dll MySQL functions PHP >= 5.0.0, requires libmysql.dll + (bundled) + php_mysqli.dll MySQLi functions PHP >= 5.0.0, requires libmysql.dll + (libmysqli.dll in PHP <= 5.0.2) (bundled) + php_oci8.dll Oracle 8 functions Requires: Oracle 8.1+ client libraries + php_openssl.dll OpenSSL functions Requires: libeay32.dll (bundled) + php_oracle.dll Oracle functions Requires: Oracle 7 client libraries + php_pgsql.dll PostgreSQL functions None + php_printer.dll Printer functions None + php_shmop.dll Shared Memory functions None + php_snmp.dll SNMP get and walk functions NT only! + php_soap.dll SOAP functions PHP >= 5.0.0 + php_sockets.dll Socket functions None + php_sybase_ct.dll Sybase functions Requires: Sybase client libraries + php_tidy.dll Tidy functions PHP >= 5.0.0 + php_tokenizer.dll Tokenizer functions Built in since PHP 4.3.0 + php_xmlrpc.dll XML-RPC functions PHP >= 4.2.1 requires: iconv.dll + (bundled) + php_xslt.dll XSLT requires libxslt.dll, iconv.dll (bundled). + php_zip.dll Zip File functions + php_zlib.dll ZLib compression functions + __________________________________________________________________ + +Chapter 3. Installation of PECL extensions + +Introduction to PECL Installations + + PECL is a repository of PHP extensions that are made available to you + via the PEAR packaging system. This section of the manual is intended + to demonstrate how to obtain and install PECL extensions. + + These instructions assume /your/phpsrcdir/ is the path to the PHP + source distribution, and that extname is the name of the PECL + extension. Adjust accordingly. These instructions also assume a + familiarity with the pear command. The information in the PEAR manual + for the pear command also applies to the pecl command. + + To be useful, a shared extension must be built, installed, and loaded. + The methods described below provide you with various instructions on + how to build and install the extensions, but they do not automatically + load them. Extensions can be loaded by adding an extension directive. + To this php.ini file, or through the use of the dl() function. + + When building PHP modules, it's important to have known-good versions + of the required tools (autoconf, automake, libtool, etc.) See the + SVN Instructions for details on the required tools, and required + versions. + __________________________________________________________________ + +Downloading PECL extensions + + There are several options for downloading PECL extensions, such as: + + * http://pecl.php.net + The PECL web site contains information about the different + extensions that are offered by the PHP Development Team. The + information available here includes: ChangeLog, release notes, + requirements and other similar details. + * pecl download extname + PECL extensions that have releases listed on the PECL web site are + available for download and installation using the pecl command. + Specific revisions may also be specified. + * SVN + Most PECL extensions also reside in SVN. A web-based view may be + seen at http://svn.php.net/pecl/. To download straight from SVN, + the following sequence of commands may be used. + +$ svn co http://svn.php.net/repository/pecl//trunk + + * Windows downloads + Windows users may find compiled PECL binaries by downloading the + Collection of PECL modules from the PHP Downloads page, or by + retrieving a PECL Snapshot or an extension DLL on PECL4WIN. To + compile PHP under Windows, read the appropriate chapter. + __________________________________________________________________ + +PECL for Windows users + + As with any other PHP extension DLL, installation is as simple as + copying the PECL extension DLLs into the extension_dir folder and + loading them from php.ini. For example, add the following line to your + php.ini: + + extension=php_extname.dll + + After doing this, restart the web server. + __________________________________________________________________ + +Compiling shared PECL extensions with the pecl command + + PECL makes it easy to create shared PHP extensions. Using the pecl + command, do the following: + + $ pecl install extname + + This will download the source for extname, compile, and install + extname.so into your extension_dir. extname.so may then be loaded via + php.ini + + By default, the pecl command will not install packages that are marked + with the alpha or beta state. If no stable packages are available, you + may install a beta package using the following command: + + $ pecl install extname-beta + + You may also install a specific version using this variant: + + $ pecl install extname-0.1 + __________________________________________________________________ + +Compiling shared PECL extensions with phpize + + Sometimes, using the pecl installer is not an option. This could be + because you're behind a firewall, or it could be because the extension + you want to install is not available as a PECL compatible package, such + as unreleased extensions from SVN. If you need to build such an + extension, you can use the lower-level build tools to perform the build + manually. + + The phpize command is used to prepare the build environment for a PHP + extension. In the following sample, the sources for an extension are in + a directory named extname: + +$ cd extname +$ phpize +$ ./configure +$ make +# make install + + A successful install will have created extname.so and put it into the + PHP extensions directory. You'll need to and adjust php.ini and add an + extension=extname.so line before you can use the extension. + + If the system is missing the phpize command, and precompiled packages + (like RPM's) are used, be sure to also install the appropriate devel + version of the PHP package as they often include the phpize command + along with the appropriate header files to build PHP and its + extensions. + + Execute phpize --help to display additional usage information. + __________________________________________________________________ + +Compiling PECL extensions statically into PHP + + You might find that you need to build a PECL extension statically into + your PHP binary. To do this, you'll need to place the extension source + under the php-src/ext/ directory and tell the PHP build system to + regenerate its configure script. + +$ cd /your/phpsrcdir/ext +$ pecl download extname +$ gzip -d < extname.tgz | tar -xvf - +$ mv extname-x.x.x extname + + This will result in the following directory: + + /your/phpsrcdir/ext/extname + + From here, force PHP to rebuild the configure script, and then build + PHP as normal: + +$ cd /your/phpsrcdir +$ rm configure +$ ./buildconf --force +$ ./configure --help +$ ./configure --with-extname --enable-someotherext --with-foobar +$ make +$ make install + + Note: To run the 'buildconf' script you need autoconf 2.13 and + automake 1.4+ (newer versions of autoconf may work, but are not + supported). + + Whether --enable-extname or --with-extname is used depends on the + extension. Typically an extension that does not require external + libraries uses --enable. To be sure, run the following after buildconf: + + $ ./configure --help | grep extname + __________________________________________________________________ + +Chapter 4. Problems? + +Read the FAQ + + Some problems are more common than others. The most common ones are + listed in the PHP FAQ, part of this manual. + __________________________________________________________________ + +Other problems + + If you are still stuck, someone on the PHP installation mailing list + may be able to help you. You should check out the archive first, in + case someone already answered someone else who had the same problem as + you. The archives are available from the support page on + http://www.php.net/support.php. To subscribe to the PHP installation + mailing list, send an empty mail to + php-install-subscribe@lists.php.net. The mailing list address is + php-install@lists.php.net. + + If you want to get help on the mailing list, please try to be precise + and give the necessary details about your environment (which operating + system, what PHP version, what web server, if you are running PHP as + CGI or a server module, safe mode, etc...), and preferably enough code + to make others able to reproduce and test your problem. + __________________________________________________________________ + +Bug reports + + If you think you have found a bug in PHP, please report it. The PHP + developers probably don't know about it, and unless you report it, + chances are it won't be fixed. You can report bugs using the + bug-tracking system at http://bugs.php.net/. Please do not send bug + reports in mailing list or personal letters. The bug system is also + suitable to submit feature requests. + + Read the How to report a bug document before submitting any bug + reports! + __________________________________________________________________ + +Chapter 5. Runtime Configuration + +The configuration file + + The configuration file (called php3.ini in PHP 3, and simply php.ini as + of PHP 4) is read when PHP starts up. For the server module versions of + PHP, this happens only once when the web server is started. For the CGI + and CLI version, it happens on every invocation. + + php.ini is searched in these locations (in order): + + * SAPI module specific location (PHPIniDir directive in Apache 2, -c + command line option in CGI and CLI, php_ini parameter in NSAPI, + PHP_INI_PATH environment variable in THTTPD) + * The PHPRC environment variable. Before PHP 5.2.0 this was checked + after the registry key mentioned below. + * As of PHP 5.2.0, the following registry locations are searched in + order: HKEY_LOCAL_MACHINE\SOFTWARE\PHP\x.y.z\IniFilePath, + HKEY_LOCAL_MACHINE\SOFTWARE\PHP\x.y\IniFilePath and + HKEY_LOCAL_MACHINE\SOFTWARE\PHP\x\IniFilePath, where x, y and z + mean the PHP major, minor and release versions. + * HKEY_LOCAL_MACHINE\SOFTWARE\PHP\IniFilePath (Windows Registry + location) + * Current working directory (except CLI) + * The web server's directory (for SAPI modules), or directory of PHP + (otherwise in Windows) + * Windows directory (C:\windows or C:\winnt) (for Windows), or + --with-config-file-path compile time option + + If php-SAPI.ini exists (where SAPI is used SAPI, so the filename is + e.g. php-cli.ini or php-apache.ini), it's used instead of php.ini. SAPI + name can be determined by php_sapi_name(). + + Note: The Apache web server changes the directory to root at startup + causing PHP to attempt to read php.ini from the root filesystem if + it exists. + + The php.ini directives handled by extensions are documented + respectively on the pages of the extensions themselves. The list of the + core directives is available in the appendix. Probably not all PHP + directives are documented in the manual though. For a complete list of + directives available in your PHP version, please read your well + commented php.ini file. Alternatively, you may find the latest + php.ini from SVN helpful too. + + Example 5-1. php.ini example +; any text on a line after an unquoted semicolon (;) is ignored +[php] ; section markers (text within square brackets) are also ignored +; Boolean values can be set to either: +; true, on, yes +; or false, off, no, none +html_errors = off +track_errors = yes + +; you can enclose strings in double-quotes +include_path = ".:/usr/local/lib/php" + +; backslashes are treated the same as any other character +include_path = ".;c:\php\lib" + + Since PHP 5.1.0, it is possible to refer to existing .ini variables + from within .ini files. Example: open_basedir = ${open_basedir} + ":/new/dir". + __________________________________________________________________ + +How to change configuration settings + +Running PHP as an Apache module + + When using PHP as an Apache module, you can also change the + configuration settings using directives in Apache configuration files + (e.g. httpd.conf) and .htaccess files. You will need "AllowOverride + Options" or "AllowOverride All" privileges to do so. + + With PHP 4 and PHP 7, there are several Apache directives that allow + you to change the PHP configuration from within the Apache + configuration files. For a listing of which directives are PHP_INI_ALL, + PHP_INI_PERDIR, or PHP_INI_SYSTEM, have a look at the List of php.ini + directives appendix. + + Note: With PHP 3, there are Apache directives that correspond to + each configuration setting in the php3.ini name, except the name is + prefixed by "php3_". + + php_value name value + Sets the value of the specified directive. Can be used only with + PHP_INI_ALL and PHP_INI_PERDIR type directives. To clear a + previously set value use none as the value. + + Note: Don't use php_value to set boolean values. php_flag (see + below) should be used instead. + + php_flag name on|off + Used to set a boolean configuration directive. Can be used only + with PHP_INI_ALL and PHP_INI_PERDIR type directives. + + php_admin_value name value + Sets the value of the specified directive. This can not be used + in .htaccess files. Any directive type set with php_admin_value + can not be overridden by .htaccess or virtualhost directives. To + clear a previously set value use none as the value. + + php_admin_flag name on|off + Used to set a boolean configuration directive. This can not be + used in .htaccess files. Any directive type set with + php_admin_flag can not be overridden by .htaccess or virtualhost + directives. + + Example 5-2. Apache configuration example + + php_value include_path ".:/usr/local/lib/php" + php_admin_flag engine on + + + Caution + + PHP constants do not exist outside of PHP. For example, in httpd.conf + you can not use PHP constants such as E_ALL or E_NOTICE to set the + error_reporting directive as they will have no meaning and will + evaluate to 0. Use the associated bitmask values instead. These + constants can be used in php.ini + __________________________________________________________________ + +Changing PHP configuration via the Windows registry + + When running PHP on Windows, the configuration values can be modified + on a per-directory basis using the Windows registry. The configuration + values are stored in the registry key HKLM\SOFTWARE\PHP\Per Directory + Values, in the sub-keys corresponding to the path names. For example, + configuration values for the directory c:\inetpub\wwwroot would be + stored in the key HKLM\SOFTWARE\PHP\Per Directory + Values\c\inetpub\wwwroot. The settings for the directory would be + active for any script running from this directory or any subdirectory + of it. The values under the key should have the name of the PHP + configuration directive and the string value. PHP constants in the + values are not parsed. However, only configuration values changeable in + PHP_INI_USER can be set this way, PHP_INI_PERDIR values can not. + __________________________________________________________________ + +Other interfaces to PHP + + Regardless of how you run PHP, you can change certain values at runtime + of your scripts through ini_set(). See the documentation on the + ini_set() page for more information. + + If you are interested in a complete list of configuration settings on + your system with their current values, you can execute the phpinfo() + function, and review the resulting page. You can also access the values + of individual configuration directives at runtime using ini_get() or + get_cfg_var(). + __________________________________________________________________ + +Chapter 6. Installation FAQ + + This section holds common questions about the way to install PHP. PHP + is available for almost any OS (except maybe for MacOS before OSX), and + almost any web server. + + To install PHP, follow the instructions in Installing PHP. + + 1. Why shouldn't I use Apache2 with a threaded MPM in a production + environment? + + 2. Unix/Windows: Where should my php.ini file be located? + 3. Unix: I installed PHP, but every time I load a document, I get the + message 'Document Contains No Data'! What's going on here? + + 4. Unix: I installed PHP using RPMS, but Apache isn't processing the + PHP pages! What's going on here? + + 5. Unix: I installed PHP 3 using RPMS, but it doesn't compile with the + database support I need! What's going on here? + + 6. Unix: I patched Apache with the FrontPage extensions patch, and + suddenly PHP stopped working. Is PHP incompatible with the + Apache FrontPage extensions? + + 7. Unix/Windows: I have installed PHP, but when I try to access a PHP + script file via my browser, I get a blank screen. + + 8. Unix/Windows: I have installed PHP, but when try to access a PHP + script file via my browser, I get a server 500 error. + + 9. Some operating systems: I have installed PHP without errors, but + when I try to start apache I get undefined symbol errors: + +[mybox:user /src/php7] root# apachectl configtest + apachectl: /usr/local/apache/bin/httpd Undefined symbols: + _compress + _uncompress + + 10. Windows: I have installed PHP, but when I to access a PHP script + file via my browser, I get the error: + +cgi error: + The specified CGI application misbehaved by not + returning a complete set of HTTP headers. + The headers it did return are: + + 11. Windows: I've followed all the instructions, but still can't get + PHP and IIS to work together! + + 12. When running PHP as CGI with IIS, OmniHTTPD or Xitami, I get + the following error: Security Alert! PHP CGI cannot be accessed + directly.. + + 13. How do I know if my php.ini is being found and read? It seems like + it isn't as my changes aren't being implemented. + + 14. How do I add my PHP directory to the PATH on Windows? + 15. How do I make the php.ini file available to PHP on windows? + 16. Is it possible to use Apache content negotiation (MultiViews + option) with PHP? + + 17. Is PHP limited to process GET and POST request methods only? + + 1. Why shouldn't I use Apache2 with a threaded MPM in a production + environment? + + PHP is glue. It is the glue used to build cool web applications by + sticking dozens of 3rd-party libraries together and making it all + appear as one coherent entity through an intuitive and easy to learn + language interface. The flexibility and power of PHP relies on the + stability and robustness of the underlying platform. It needs a working + OS, a working web server and working 3rd-party libraries to glue + together. When any of these stop working PHP needs ways to identify the + problems and fix them quickly. When you make the underlying framework + more complex by not having completely separate execution threads, + completely separate memory segments and a strong sandbox for each + request to play in, feet of clay are introduced into PHP's system. + + If you feel you have to use a threaded MPM, look at a FastCGI + configuration where PHP is running in its own memory space. + + And finally, this warning against using a threaded MPM is not as strong + for Windows systems because most libraries on that platform tend to be + threadsafe. + + 2. Unix/Windows: Where should my php.ini file be located? + + By default on Unix it should be in /usr/local/lib which is + /lib. Most people will want to change this at + compile-time with the --with-config-file-path flag. You would, for + example, set it with something like: + --with-config-file-path=/etc + + And then you would copy php.ini-production from the distribution to + /etc/php.ini and edit it to make any local changes you want. + --with-config-file-scan-dir=PATH + + On Windows the default path for the php.ini file is the Windows + directory. If you're using the Apache webserver, php.ini is first + searched in the Apaches install directory, e.g. c:\program files\apache + group\apache. This way you can have different php.ini files for + different versions of Apache on the same machine. + + See also the chapter about the configuration file. + + 3. Unix: I installed PHP, but every time I load a document, I get the + message 'Document Contains No Data'! What's going on here? + + This probably means that PHP is having some sort of problem and is + core-dumping. Look in your server error log to see if this is the case, + and then try to reproduce the problem with a small test case. If you + know how to use 'gdb', it is very helpful when you can provide a + backtrace with your bug report to help the developers pinpoint the + problem. If you are using PHP as an Apache module try something like: + + * Stop your httpd processes + * gdb httpd + * Stop your httpd processes + * > run -X -f /path/to/httpd.conf + * Then fetch the URL causing the problem with your browser + * > run -X -f /path/to/httpd.conf + * If you are getting a core dump, gdb should inform you of this now + * type: bt + * You should include your backtrace in your bug report. This should + be submitted to http://bugs.php.net/ + + If your script uses the regular expression functions (ereg() and + friends), you should make sure that you compiled PHP and Apache with + the same regular expression package. This should happen automatically + with PHP and Apache 1.3.x + + 4. Unix: I installed PHP using RPMS, but Apache isn't processing the + PHP pages! What's going on here? + + Assuming you installed both Apache and PHP from RPM packages, you need + to uncomment or add some or all of the following lines in your + httpd.conf file: +# Extra Modules +AddModule mod_php.c +AddModule mod_php3.c +AddModule mod_perl.c + +# Extra Modules +LoadModule php_module modules/mod_php.so +LoadModule perl_module modules/libperl.so + + And add: +AddType application/x-httpd-php3 .php3 # for PHP 3 +AddType application/x-httpd-php .php # for PHP 4 + + ... to the global properties, or to the properties of the VirtualDomain + you want to have PHP support added to. + + 5. Unix: I installed PHP 3 using RPMS, but it doesn't compile with the + database support I need! What's going on here? + + Due to the way PHP 3 built, it is not easy to build a complete flexible + PHP RPM. This issue is addressed in PHP 4. For PHP 3, we currently + suggest you use the mechanism described in the INSTALL.REDHAT file in + the PHP distribution. If you insist on using an RPM version of PHP 3, + read on... + + The RPM packagers are setting up the RPMS to install without database + support to simplify installations and because RPMS use /usr/ instead of + the standard /usr/local/ directory for files. You need to tell the RPM + spec file which databases to support and the location of the top-level + of your database server. + + This example will explain the process of adding support for the popular + MySQL database server, using the mod installation for Apache. + + Of course all of this information can be adjusted for any database + server that PHP supports. We will assume you installed MySQL and Apache + completely with RPMS for this example as well. + + * First remove mod_php3 : + +rpm -e mod_php3 + + * Then get the source rpm and INSTALL it, NOT --rebuild + +rpm -Uvh mod_php3-3.0.5-2.src.rpm + + * Then edit the /usr/src/redhat/SPECS/mod_php3.spec file + In the %build section add the database support you want, and the + path. + For MySQL you would add --with-mysql=/usr The %build section will + look something like this: + +./configure --prefix=/usr \ +--with-apxs=/usr/sbin/apxs \ +--with-config-file-path=/usr/lib \ +--enable-debug=no \ +--enable-safe-mode \ +--with-exec-dir=/usr/bin \ +--with-mysql=/usr \ +--with-system-regex + + * Once this modification is made then build the binary rpm as + follows: + +rpm -bb /usr/src/redhat/SPECS/mod_php3.spec + + * Then install the rpm + +rpm -ivh /usr/src/redhat/RPMS/i386/mod_php3-3.0.5-2.i386.rpm + + Make sure you restart Apache, and you now have PHP 3 with MySQL support + using RPM's. Note that it is probably much easier to just build from + the distribution tarball of PHP 3 and follow the instructions in + INSTALL.REDHAT found in that distribution. + + 6. Unix: I patched Apache with the FrontPage extensions patch, and + suddenly PHP stopped working. Is PHP incompatible with the Apache + FrontPage extensions? + + No, PHP works fine with the FrontPage extensions. The problem is that + the FrontPage patch modifies several Apache structures, that PHP relies + on. Recompiling PHP (using 'make clean ; make') after the FP patch is + applied would solve the problem. + + 7. Unix/Windows: I have installed PHP, but when I try to access a PHP + script file via my browser, I get a blank screen. + + Do a 'view source' in the web browser and you will probably find that + you can see the source code of your PHP script. This means that the web + server did not send the script to PHP for interpretation. Something is + wrong with the server configuration - double check the server + configuration against the PHP installation instructions. + + 8. Unix/Windows: I have installed PHP, but when try to access a PHP + script file via my browser, I get a server 500 error. + + Something went wrong when the server tried to run PHP. To get to see a + sensible error message, from the command line, change to the directory + containing the PHP executable (php.exe on Windows) and run php -i. If + PHP has any problems running, then a suitable error message will be + displayed which will give you a clue as to what needs to be done next. + If you get a screen full of HTML codes (the output of the phpinfo() + function) then PHP is working, and your problem may be related to your + server configuration which you should double check. + + 9. Some operating systems: I have installed PHP without errors, but + when I try to start apache I get undefined symbol errors: +[mybox:user /src/php7] root# apachectl configtest + apachectl: /usr/local/apache/bin/httpd Undefined symbols: + _compress + _uncompress + + This has actually nothing to do with PHP, but with the MySQL client + libraries. Some need --with-zlib, others do not. This is also covered + in the MySQL FAQ. + + 10. Windows: I have installed PHP, but when I to access a PHP script + file via my browser, I get the error: +cgi error: + The specified CGI application misbehaved by not + returning a complete set of HTTP headers. + The headers it did return are: + + This error message means that PHP failed to output anything at all. To + get to see a sensible error message, from the command line, change to + the directory containing the PHP executable (php.exe on Windows) and + run php -i. If PHP has any problems running, then a suitable error + message will be displayed which will give you a clue as to what needs + to be done next. If you get a screen full of HTML codes (the output of + the phpinfo() function) then PHP is working. + + Once PHP is working at the command line, try accessing the script via + the browser again. If it still fails then it could be one of the + following: + + * File permissions on your PHP script, php.exe, php7ts.dll, php.ini + or any PHP extensions you are trying to load are such that the + anonymous internet user ISUR_ cannot access them. + * The script file does not exist (or possibly isn't where you think + it is relative to your web root directory). Note that for IIS you + can trap this error by ticking the 'check file exists' box when + setting up the script mappings in the Internet Services Manager. If + a script file does not exist then the server will return a 404 + error instead. There is also the additional benefit that IIS will + do any authentication required for you based on the NTLanMan + permissions on your script file. + + 11. Windows: I've followed all the instructions, but still can't get + PHP and IIS to work together! + + Make sure any user who needs to run a PHP script has the rights to run + php.exe! IIS uses an anonymous user which is added at the time IIS is + installed. This user needs rights to php.exe. Also, any authenticated + user will also need rights to execute php.exe. And for IIS4 you need to + tell it that PHP is a script engine. Also, you will want to read this + faq. + + 12. When running PHP as CGI with IIS, OmniHTTPD or Xitami, I get + the following error: Security Alert! PHP CGI cannot be accessed + directly.. + + You must set the cgi.force_redirect directive to 0. It defaults to 1 so + be sure the directive isn't commented out (with a ;). Like all + directives, this is set in php.ini + + Because the default is 1, it's critical that you're 100% sure that the + correct php.ini file is being read. Read this faq for details. + + 13. How do I know if my php.ini is being found and read? It seems like + it isn't as my changes aren't being implemented. + + To be sure your php.ini is being read by PHP, make a call to phpinfo() + and near the top will be a listing called Configuration File (php.ini). + This will tell you where PHP is looking for php.ini and whether or not + it's being read. If just a directory PATH exists than it's not being + read and you should put your php.ini in that directory. If php.ini is + included within the PATH than it is being read. + + If php.ini is being read and you're running PHP as a module, then be + sure to restart your web server after making changes to php.ini + + 14. How do I add my PHP directory to the PATH on Windows? + + On Windows NT, 2000, XP and 2003: + + * Go to Control Panel and open the System icon (Start -> Settings -> + Control Panel -> System, or just Start -> Control Panel -> System + for Windows XP/2003) + * Go to the Advanced tab + * Click on the 'Environment Variables' button + * Look into the 'System Variables' pane + * Find the Path entry (you may need to scroll to find it) + * Double click on the Path entry + * Enter your PHP directory at the end, including ';' before (e.g. + ;C:\php) + * Press OK and restart your computer + + On Windows 98/Me you need to edit the autoexec.bat file: + + * Open the Notepad (Start -> Run and enter notepad) + * Open the C:\autoexec.bat file + * Locate the line with PATH=C:\WINDOWS;C:\WINDOWS\COMMAND;..... and + add: ;C:\php to the end of the line + * Save the file and restart your computer + + Note: Be sure to reboot after following the steps above to ensure + that the PATH changes are applied. + + The PHP manual used to promote the copying of files into the Windows + system directory, this is because this directory (C:\Windows, C:\WINNT, + etc.) is by default in the systems PATH. Copying files into the Windows + system directory has long since been deprecated and may cause problems. + + 15. How do I make the php.ini file available to PHP on windows? + + There are several ways of doing this. If you are using Apache, read + their installation specific instructions (Apache 1, Apache 2), + otherwise you must set the PHPRC environment variable: + + On Windows NT, 2000, XP and 2003: + + * Go to Control Panel and open the System icon (Start -> Settings -> + Control Panel -> System, or just Start -> Control Panel -> System + for Windows XP/2003) + * Go to the Advanced tab + * Click on the 'Environment Variables' button + * Look into the 'System variables' pane + * Click on 'New' and enter 'PHPRC' as the variable name and the + directory where php.ini is located as the variable value (e.g. + C:\php) + * Press OK and restart your computer + + On Windows 98/Me you need to edit the autoexec.bat file: + + * Open the Notepad (Start -> Run and enter notepad) + * Open the C:\autoexec.bat file + * Add a new line to the end of the file: set PHPRC=C:\php (replace + C:\php with the directory where php.ini is located). Please note + that the path cannot contain spaces. For instance, if you have + installed PHP in C:\Program Files\PHP, you would enter + C:\PROGRA~1\PHP instead. + * Save the file and restart your computer + + 16. Is it possible to use Apache content negotiation (MultiViews + option) with PHP? + + If links to PHP files include extension, everything works perfect. This + FAQ is only for the case when links to PHP files don't include + extension and you want to use content negotiation to choose PHP files + from URL with no extension. In this case, replace the line AddType + application/x-httpd-php .php with: +# PHP 4 +AddHandler php-script php +AddType text/html php + +# PHP 7 +AddHandler php7-script php +AddType text/html php + + This solution doesn't work for Apache 1 as PHP module doesn't catch + php-script. + + 17. Is PHP limited to process GET and POST request methods only? + + No, it is possible to handle any request method, e.g. CONNECT. Proper + response status can be sent with header(). If only GET and POST methods + should be handled, it can be achieved with this Apache configuration: + +Deny from all + diff --git a/bin/php/lib/enchant/libenchant_ispell.dll b/bin/php/lib/enchant/libenchant_ispell.dll new file mode 100644 index 0000000..b35e9e5 Binary files /dev/null and b/bin/php/lib/enchant/libenchant_ispell.dll differ diff --git a/bin/php/lib/enchant/libenchant_myspell.dll b/bin/php/lib/enchant/libenchant_myspell.dll new file mode 100644 index 0000000..62150cb Binary files /dev/null and b/bin/php/lib/enchant/libenchant_myspell.dll differ diff --git a/bin/php/libeay32.dll b/bin/php/libeay32.dll new file mode 100644 index 0000000..b744cee Binary files /dev/null and b/bin/php/libeay32.dll differ diff --git a/bin/php/libenchant.dll b/bin/php/libenchant.dll new file mode 100644 index 0000000..5fce850 Binary files /dev/null and b/bin/php/libenchant.dll differ diff --git a/bin/php/libpq.dll b/bin/php/libpq.dll new file mode 100644 index 0000000..4c42959 Binary files /dev/null and b/bin/php/libpq.dll differ diff --git a/bin/php/libsasl.dll b/bin/php/libsasl.dll new file mode 100644 index 0000000..de90ca8 Binary files /dev/null and b/bin/php/libsasl.dll differ diff --git a/bin/php/libssh2.dll b/bin/php/libssh2.dll new file mode 100644 index 0000000..84f91b6 Binary files /dev/null and b/bin/php/libssh2.dll differ diff --git a/bin/php/license.txt b/bin/php/license.txt new file mode 100644 index 0000000..e0bc44c --- /dev/null +++ b/bin/php/license.txt @@ -0,0 +1,68 @@ +-------------------------------------------------------------------- + The PHP License, version 3.01 +Copyright (c) 1999 - 2016 The PHP Group. All rights reserved. +-------------------------------------------------------------------- + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. The name "PHP" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact group@php.net. + + 4. Products derived from this software may not be called "PHP", nor + may "PHP" appear in their name, without prior written permission + from group@php.net. You may indicate that your software works in + conjunction with PHP by saying "Foo for PHP" instead of calling + it "PHP Foo" or "phpfoo" + + 5. The PHP Group may publish revised and/or new versions of the + license from time to time. Each version will be given a + distinguishing version number. + Once covered code has been published under a particular version + of the license, you may always continue to use it under the terms + of that version. You may also choose to use such covered code + under the terms of any subsequent version of the license + published by the PHP Group. No one other than the PHP Group has + the right to modify the terms applicable to covered code created + under this License. + + 6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes PHP software, freely available from + ". + +THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND +ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP +DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------- + +This software consists of voluntary contributions made by many +individuals on behalf of the PHP Group. + +The PHP Group can be contacted via Email at group@php.net. + +For more information on the PHP Group and the PHP project, +please see . + +PHP includes the Zend Engine, freely available at +. diff --git a/bin/php/news.txt b/bin/php/news.txt new file mode 100644 index 0000000..657f585 --- /dev/null +++ b/bin/php/news.txt @@ -0,0 +1,1525 @@ +PHP NEWS +||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +21 Jul 2016 PHP 7.0.9 + +- Core: + . Fixed bug #72508 (strange references after recursive function call and + "switch" statement). (Laruence) + . Fixed bug #72513 (Stack-based buffer overflow vulnerability in + virtual_file_ex). (Stas) + . Fixed bug #72573 (HTTP_PROXY is improperly trusted by some PHP libraries + and applications). (Stas) + +- bz2: + . Fixed bug #72613 (Inadequate error handling in bzread()). (Stas) + +- CLI: + . Fixed bug #72484 (SCRIPT_FILENAME shows wrong path if the user specify + router.php). (Laruence) + +- COM: + . Fixed bug #72498 (variant_date_from_timestamp null dereference). (Anatol) + +- Curl: + . Fixed bug #72541 (size_t overflow lead to heap corruption). (Stas) + +- Exif: + . Fixed bug #72603 (Out of bound read in exif_process_IFD_in_MAKERNOTE). + (Stas) + . Fixed bug #72618 (NULL Pointer Dereference in exif_process_user_comment). + (Stas) + +- GD: + . Fixed bug #43475 (Thick styled lines have scrambled patterns). (cmb) + . Fixed bug #53640 (XBM images require width to be multiple of 8). (cmb) + . Fixed bug #64641 (imagefilledpolygon doesn't draw horizontal line). (cmb) + . Fixed bug #72512 (gdImageTrueColorToPaletteBody allows arbitrary write/read + access). (Pierre) + . Fixed bug #72519 (imagegif/output out-of-bounds access). (Pierre) + . Fixed bug #72558 (Integer overflow error within _gdContributionsAlloc()). + (Pierre) + . Fixed bug #72482 (Ilegal write/read access caused by gdImageAALine + overflow). (Pierre) + . Fixed bug #72494 (imagecropauto out-of-bounds access). (Pierre) + +- Intl: + . Fixed bug #72533 (locale_accept_from_http out-of-bounds access). (Stas) + +- Mbstring: + . Fixed bug #72405 (mb_ereg_replace - mbc_to_code (oniguruma) - + oob read access). (Laruence) + . Fixed bug #72399 (Use-After-Free in MBString (search_re)). (Laruence) + +- mcrypt: + . Fixed bug #72551, bug #72552 (In correct casting from size_t to int lead to + heap overflow in mdecrypt_generic). (Stas) + +- PDO_pgsql: + . Fixed bug #72570 (Segmentation fault when binding parameters on a query + without placeholders). (Matteo) + +- PCRE: + . Fixed bug #72476 (Memleak in jit_stack). (Laruence) + . Fixed bug #72463 (mail fails with invalid argument). (Anatol) + +- Readline: + . Fixed bug #72538 (readline_redisplay crashes php). (Laruence) + +- Standard: + . Fixed bug #72505 (readfile() mangles files larger than 2G). (Cschneid) + . Fixed bug #72306 (Heap overflow through proc_open and $env parameter). + (Laruence) + +- Session: + . Fixed bug #72531 (ps_files_cleanup_dir Buffer overflow). (Laruence) + . Fixed bug #72562 (Use After Free in unserialize() with Unexpected Session + Deserialization). (Stas) + +- SNMP: + . Fixed bug #72479 (Use After Free Vulnerability in SNMP with GC and + unserialize()). (Stas) + +- Streams: + . Fixed bug #72439 (Stream socket with remote address leads to a segmentation + fault). (Laruence) + +- XMLRPC: + . Fixed bug #72606 (heap-buffer-overflow (write) simplestring_addn + simplestring.c). (Stas) + +- Zip: + . Fixed bug #72520 (Stack-based buffer overflow vulnerability in + php_stream_zip_opener). (Stas) + +23 Jun 2016 PHP 7.0.8 + +- Core: + . Fixed bug #72218 (If host name cannot be resolved then PHP 7 crashes). + (Esminis at esminis dot lt) + . Fixed bug #72221 (segfault, past-the-end access). (Lauri Kenttä) + . Fixed bug #72268 (Integer Overflow in nl2br()). (Stas) + . Fixed bug #72275 (Integer Overflow in json_encode()/json_decode()/ + json_utf8_to_utf16()). (Stas) + . Fixed bug #72400 (Integer Overflow in addcslashes/addslashes). (Stas) + . Fixed bug #72403 (Integer Overflow in Length of String-typed ZVAL). (Stas) + +- Date: + . Fixed bug #63740 (strtotime seems to use both sunday and monday as start of + week). (Derick) + +- FPM: + . Fixed bug #72308 (fastcgi_finish_request and logging environment + variables). (Laruence) + +- GD: + . Fixed bug #66387 (Stack overflow with imagefilltoborder). (CVE-2015-8874) + (cmb) + . Fixed bug #72298 (pass2_no_dither out-of-bounds access). (Stas) + . Fixed bug #72337 (invalid dimensions can lead to crash). (Pierre) + . Fixed bug #72339 (Integer Overflow in _gd2GetHeader() resulting in heap + overflow). (CVE-2016-5766) (Pierre) + . Fixed bug #72407 (NULL Pointer Dereference at _gdScaleVert). (Stas) + . Fixed bug #72446 (Integer Overflow in gdImagePaletteToTrueColor() resulting + in heap overflow). (CVE-2016-5767) (Pierre) + +- Intl: + . Fixed bug #70484 (selectordinal doesn't work with named parameters). + (Anatol) + +- mbstring: + . Fixed bug #72402 (_php_mb_regex_ereg_replace_exec - double free). + (CVE-2016-5768) (Stas) + +- mcrypt: + . Fixed bug #72455 (Heap Overflow due to integer overflows). (CVE-2016-5769) + (Stas) + +- OpenSSL: + . Fixed bug #72140 (segfault after calling ERR_free_strings()). + (Jakub Zelenka) + +- PCRE: + . Fixed bug #72143 (preg_replace uses int instead of size_t). (Joe) + +- PDO_pgsql: + . Fixed bug #71573 (Segfault (core dumped) if paramno beyond bound). + (Laruence) + . Fixed bug #72294 (Segmentation fault/invalid pointer in connection + with pgsql_stmt_dtor). (Anatol) + +- Phar: + . Fixed bug #72321 (invalid free in phar_extract_file()). + (hji at dyntopia dot com) + +- Phpdbg: + . Fixed bug #72284 (phpdbg fatal errors with coverage). (Bob) + +- Postgres: + . Fixed bug #72195 (pg_pconnect/pg_connect cause use-after-free). (Laruence) + . Fixed bug #72197 (pg_lo_create arbitrary read). (Anatol) + +- Standard: + . Fixed bug #72369 (array_merge() produces references in PHP7). (Dmitry) + . Fixed bug #72300 (ignore_user_abort(false) has no effect). (Laruence) + . Fixed bug #72229 (Wrong reference when serialize/unserialize an object). + (Laruence) + . Fixed bug #72193 (dns_get_record returns array containing elements of + type 'unknown'). (Laruence) + . Fixed bug #72017 (range() with float step produces unexpected result). + (Thomas Punt) + +- WDDX: + . Fixed bug #72340 (Double Free Courruption in wddx_deserialize). + (CVE-2016-5772) (Stas) + +- XML: + . Fixed bug #72206 (xml_parser_create/xml_parser_free leaks mem). (Joe) + +- XMLRPC: + . Fixed bug #72155 (use-after-free caused by get_zval_xmlrpc_type). + (Joe, Laruence) + +- Zip: + . Fixed ug #72258 (ZipArchive converts filenames to unrecoverable form). + (Anatol) + . Fixed bug #72434 (ZipArchive class Use After Free Vulnerability in PHP's GC + algorithm and unserialize). (CVE-2016-5773) (Dmitry) + +26 May 2016 PHP 7.0.7 + +- Core: + . Fixed bug #72162 (use-after-free - error_reporting). (Laruence) + . Add compiler option to disable special case function calls. (Joe) + . Fixed bug #72101 (crash on complex code). (Dmitry) + . Fixed bug #72100 (implode() inserts garbage into resulting string when + joins very big integer). (Mikhail Galanin) + . Fixed bug #72057 (PHP Hangs when using custom error handler and typehint). + (Nikita Nefedov) + . Fixed bug #72038 (Function calls with values to a by-ref parameter don't + always throw a notice). (Bob) + . Fixed bug #71737 (Memory leak in closure with parameter named $this). + (Nikita) + . Fixed bug #72059 (?? is not allowed on constant expressions). (Bob, Marcio) + . Fixed bug #72159 (Imported Class Overrides Local Class Name). (Nikita) + +- Curl: + . Fixed bug #68658 (Define CURLE_SSL_CACERT_BADFILE). (Pierrick) + +- DBA: + . Fixed bug #72157 (use-after-free caused by dba_open). (Shm, Laruence) + +- GD: + . Fixed bug #72227 (imagescale out-of-bounds read). (Stas) + +- Intl: + . Fixed bug #64524 (Add intl.use_exceptions to php.ini-*). (Anatol) + . Fixed bug #72241 (get_icu_value_internal out-of-bounds read). (Stas) + +- JSON: + . Fixed bug #72069 (Behavior \JsonSerializable different from json_encode). + (Laruence) + +- Mbstring: + . Fixed bug #72164 (Null Pointer Dereference - mb_ereg_replace). (Laruence) + +- OCI8: + . Fixed bug #71600 (oci_fetch_all segfaults when selecting more than eight + columns). (Tian Yang) + +- Opcache: + . Fixed bug #72014 (Including a file with anonymous classes multiple times + leads to fatal error). (Laruence) + +- OpenSSL: + . Fixed bug #72165 (Null pointer dereference - openssl_csr_new). (Anatol) + +- PCNTL: + . Fixed bug #72154 (pcntl_wait/pcntl_waitpid array internal structure + overwrite). (Laruence) + +- POSIX: + . Fixed bug #72133 (php_posix_group_to_array crashes if gr_passwd is NULL). + (esminis at esminis dot lt) + +- Postgres: + . Fixed bug #72028 (pg_query_params(): NULL converts to empty string). + (Laruence) + . Fixed bug #71062 (pg_convert() doesn't accept ISO 8601 for datatype + timestamp). (denver at timothy dot io) + . Fixed bug #72151 (mysqli_fetch_object changed behaviour). (Anatol) + +- Reflection: + . Fixed bug #72174 (ReflectionProperty#getValue() causes __isset call). + (Nikita) + +- Session: + . Fixed bug #71972 (Cyclic references causing session_start(): Failed to + decode session object). (Laruence) + +- Sockets: + . Added socket_export_stream() function for getting a stream compatible + resource from a socket resource. (Chris Wright, Bob) + +- SPL: + . Fixed bug #72051 (The reference in CallbackFilterIterator doesn't work as + expected). (Laruence) + +- SQLite3: + . Fixed bug #68849 (bindValue is not using the right data type). (Anatol) + +- Standard: + . Fixed bug #72075 (Referencing socket resources breaks stream_select). + (Laruence) + . Fixed bug #72031 (array_column() against an array of objects discards all + values matching null). (Nikita) + +28 Apr 2016 PHP 7.0.6 + +- Core: + . Fixed bug #71930 (_zval_dtor_func: Assertion `(arr)->gc.refcount <= 1' + failed). (Laruence) + . Fixed bug #71922 (Crash on assert(new class{})). (Nikita) + . Fixed bug #71914 (Reference is lost in "switch"). (Laruence) + . Fixed bug #71871 (Interfaces allow final and abstract functions). (Nikita) + . Fixed Bug #71859 (zend_objects_store_call_destructors operates on realloced + memory, crashing). (Laruence) + . Fixed bug #71841 (EG(error_zval) is not handled well). (Laruence) + . Fixed bug #71750 (Multiple Heap Overflows in php_raw_url_encode/ + php_url_encode). (Stas) + . Fixed bug #71731 (Null coalescing operator and ArrayAccess). (Nikita) + . Fixed bug #71609 (Segmentation fault on ZTS with gethostbyname). (krakjoe) + . Fixed bug #71414 (Inheritance, traits and interfaces). (krakjoe) + . Fixed bug #71359 (Null coalescing operator and magic). (krakjoe) + . Fixed bug #71334 (Cannot access array keys while uksort()). (Nikita) + . Fixed bug #69659 (ArrayAccess, isset() and the offsetExists method). + (Nikita) + . Fixed bug #69537 (__debugInfo with empty string for key gives error). + (krakjoe) + . Fixed bug #62059 (ArrayObject and isset are not friends). (Nikita) + . Fixed bug #71980 (Decorated/Nested Generator is Uncloseable in Finally). + (Nikita) + +- BCmath: + . Fixed bug #72093 (bcpowmod accepts negative scale and corrupts + _one_ definition). (Stas) + +- Curl: + . Fixed bug #71831 (CURLOPT_NOPROXY applied as long instead of string). + (Michael Sierks) + +- Date: + . Fixed bug #71889 (DateInterval::format Segmentation fault). (Thomas Punt) + +- EXIF: + . Fixed bug #72094 (Out of bounds heap read access in exif header processing). (Stas) + +- GD: + . Fixed bug #71912 (libgd: signedness vulnerability). (CVE-2016-3074) (Stas) + +- Intl: + . Fixed bug #71516 (IntlDateFormatter looses locale if pattern is set via + constructor). (Anatol) + . Fixed bug #70455 (Missing constant: IntlChar::NO_NUMERIC_VALUE). (Anatol) + . Fixed bug #70451, #70452 (Inconsistencies in return values of IntlChar + methods). (Daniel Persson) + . Fixed bug #68893 (Stackoverflow in datefmt_create). (Anatol) + . Fixed bug #66289 (Locale::lookup incorrectly returns en or en_US if locale + is empty). (Anatol) + . Fixed bug #70484 (selectordinal doesn't work with named parameters). + (Anatol) + . Fixed bug #72061 (Out-of-bounds reads in zif_grapheme_stripos with negative + offset). (Stas) + +- ODBC: + . Fixed bug #63171 (Script hangs after max_execution_time). (Remi) + +- Opcache: + . Fixed bug #71843 (null ptr deref ZEND_RETURN_SPEC_CONST_HANDLER). + (Laruence) + +- PDO: + . Fixed bug #52098 (Own PDOStatement implementation ignore __call()). + (Daniel kalaspuffar, Julien) + . Fixed bug #71447 (Quotes inside comments not properly handled). (Matteo) + +- PDO_DBlib: + . Fixed bug #71943 (dblib_handle_quoter needs to allocate an extra byte). + (Adam Baratz) + . Add DBLIB-specific attributes for controlling timeouts. (Adam Baratz) + +- PDO_pgsql: + . Fixed bug #62498 (pdo_pgsql inefficient when getColumnMeta() is used). + (Joseph Bylund) + +- Postgres: + . Fixed bug #71820 (pg_fetch_object binds parameters before call + constructor). (Anatol) + . Fixed bug #71998 (Function pg_insert does not insert when column + type = inet). (Anatol) + +- SOAP: + . Fixed bug #71986 (Nested foreach assign-by-reference creates broken + variables). (Laruence) + +- SPL: + . Fixed bug #71838 (Deserializing serialized SPLObjectStorage-Object can't + access properties in PHP). (Nikita) + . Fixed bug #71735 (Double-free in SplDoublyLinkedList::offsetSet). (Stas) + . Fixed bug #67582 (Cloned SplObjectStorage with overwritten getHash fails + offsetExists()). (Nikita) + . Fixed bug #52339 (SPL autoloader breaks class_exists()). (Nikita) + +- Standard: + . Fixed bug #71995 (Returning the same var twice from __sleep() produces + broken serialized data). (Laruence) + . Fixed bug #71940 (Unserialize crushes on restore object reference). + (Laruence) + . Fixed bug #71969 (str_replace returns an incorrect resulting array after + a foreach by reference). (Laruence) + . Fixed bug #71891 (header_register_callback() and + register_shutdown_function()). (Laruence) + . Fixed bug #71884 (Null pointer deref (segfault) in + stream_context_get_default). (Laruence) + . Fixed bug #71840 (Unserialize accepts wrongly data). (Ryat, Laruence) + . Fixed bug #71837 (Wrong arrays behaviour). (Laruence) + . Fixed bug #71827 (substr_replace bug, string length). (krakjoe) + . Fixed bug #67512 (php_crypt() crashes if crypt_r() does not exist or + _REENTRANT is not defined). (Nikita) + . Fixed bug #72116 (array_fill optimization breaks implementation). (Bob) + +- XML: + . Fixed bug #72099 (xml_parse_into_struct segmentation fault). (Stas) + +- Zip: + . Fixed bug #71923 (integer overflow in ZipArchive::getFrom*). + (CVE-2016-3078) (Stas) + +31 Mar 2016 PHP 7.0.5 + +- Core: + . Huge pages disabled by default. (Rasmus) + . Added ability to enable huge pages in Zend Memory Manager through + the environment variable USE_ZEND_ALLOC_HUGE_PAGES=1. (Dmitry) + . Fixed bug #71756 (Call-by-reference widens scope to uninvolved functions + when used in switch). (Laruence) + . Fixed bug #71729 (Possible crash in zend_bin_strtod, zend_oct_strtod, + zend_hex_strtod). (Laruence) + . Fixed bug #71695 (Global variables are reserved before execution). + (Laruence) + . Fixed bug #71629 (Out-of-bounds access in php_url_decode in context + php_stream_url_wrap_rfc2397). (mt at debian dot org) + . Fixed bug #71622 (Strings used in pass-as-reference cannot be used to + invoke C::$callable()). (Bob) + . Fixed bug #71596 (Segmentation fault on ZTS with date function + (setlocale)). (Anatol) + . Fixed bug #71535 (Integer overflow in zend_mm_alloc_heap()). (Dmitry) + . Fixed bug #71470 (Leaked 1 hashtable iterators). (Nikita) + . Fixed bug #71575 (ISO C does not allow extra ‘;’ outside of a function). + (asgrim) + . Fixed bug #71724 (yield from does not count EOLs). (Nikita) + . Fixed bug #71767 (ReflectionMethod::getDocComment returns the wrong + comment). (Grigorii Sokolik) + . Fixed bug #71806 (php_strip_whitespace() fails on some numerical values). + (Nikita) + . Fixed bug #71624 (`php -R` (PHP_MODE_PROCESS_STDIN) is broken). + (Sean DuBois) + +- CLI Server: + . Fixed bug #69953 (Support MKCALENDAR request method). (Christoph) + +- Curl: + . Fixed bug #71694 (Support constant CURLM_ADDED_ALREADY). (mpyw) + +- Date: + . Fixed bug #71635 (DatePeriod::getEndDate segfault). (Thomas Punt) + +- Fileinfo: + . Fixed bug #71527 (Buffer over-write in finfo_open with malformed magic + file). (CVE-2015-8865) (Anatol) + +- libxml: + . Fixed bug #71536 (Access Violation crashes php-cgi.exe). (Anatol) + +- mbstring: + . Fixed bug #71906 (AddressSanitizer: negative-size-param (-1) in + mbfl_strcut). (CVE-2016-4073) (Stas) + +- ODBC: + . Fixed bug #47803, #69526 (Executing prepared statements is succesfull only + for the first two statements). (einavitamar at gmail dot com, Anatol) + +- PCRE: + . Fixed bug #71659 (segmentation fault in pcre running twig tests). + (nish dot aravamudan at canonical dot com) + +- PDO_DBlib: + . Fixed bug #54648 (PDO::MSSQL forces format of datetime fields). + (steven dot lambeth at gmx dot de, Anatol) + +- Phar: + . Fixed bug #71625 (Crash in php7.dll with bad phar filename). (Anatol) + . Fixed bug #71317 (PharData fails to open specific file). (Jos Elstgeest) + . Fixed bug #71860 (Invalid memory write in phar on filename with \0 in + name). (CVE-2016-4072) (Stas) + +- phpdbg: + . Fixed crash when advancing (except step) inside an internal function. (Bob) + +- Session: + . Fixed bug #71683 (Null pointer dereference in zend_hash_str_find_bucket). + (Yasuo) + +- SNMP: + . Fixed bug #71704 (php_snmp_error() Format String Vulnerability). + (CVE-2016-4071) (andrew at jmpesp dot org) + +- SPL: + . Fixed bug #71617 (private properties lost when unserializing ArrayObject). + (Nikita) + +- Standard: + . Fixed bug #71660 (array_column behaves incorrectly after foreach by + reference). (Laruence) + . Fixed bug #71798 (Integer Overflow in php_raw_url_encode). (CVE-2016-4070) + (taoguangchen at icloud dot com, Stas) + +- Zip: + . Update bundled libzip to 1.1.2. (Remi, Anatol) + +03 Mar 2016 PHP 7.0.4 + +- Core: + . Fixed bug (Low probability segfault in zend_arena). (Laruence) + . Fixed bug #71441 (Typehinted Generator with return in try/finally crashes). + (Bob) + . Fixed bug #71442 (forward_static_call crash). (Laruence) + . Fixed bug #71443 (Segfault using built-in webserver with intl using + symfony). (Laruence) + . Fixed bug #71449 (An integer overflow bug in php_implode()). (Stas) + . Fixed bug #71450 (An integer overflow bug in php_str_to_str_ex()). (Stas) + . Fixed bug #71474 (Crash because of VM stack corruption on Magento2). + (Dmitry) + . Fixed bug #71485 (Return typehint on internal func causes Fatal error + when it throws exception). (Laruence) + . Fixed bug #71529 (Variable references on array elements don't work when + using count). (Nikita) + . Fixed bug #71601 (finally block not executed after yield from). (Bob) + . Fixed bug #71637 (Multiple Heap Overflow due to integer overflows in + xml/filter_url/addcslashes). (CVE-2016-4344, CVE-2016-4345, CVE-2016-4346) + (Stas) + +- CLI server: + . Fixed bug #71559 (Built-in HTTP server, we can download file in web by bug). + (Johannes, Anatol) + +- CURL: + . Fixed bug #71523 (Copied handle with new option CURLOPT_HTTPHEADER crashes + while curl_multi_exec). (Laruence) + . Fixed memory leak in curl_getinfo(). (Leigh) + +- Date: + . Fixed bug #71525 (Calls to date_modify will mutate timelib_rel_time, + causing date_date_set issues). (Sean DuBois) + +- Fileinfo: + . Fixed bug #71434 (finfo throws notice for specific python file). (Laruence) + +- FPM: + . Fixed bug #62172 (FPM not working with Apache httpd 2.4 balancer/fcgi + setup). (Matt Haught, Remi) + . Fixed bug #71269 (php-fpm dumped core). (Mickaël) + +- Opcache: + . Fixed bug #71584 (Possible use-after-free of ZCG(cwd) in Zend Opcache). + (Yussuf Khalil) + +- PCRE: + . Fixed bug #71537 (PCRE segfault from Opcache). (Laruence) + +- phpdbg: + . Fixed inherited functions from unspecified files being included in + phpdbg_get_executable(). (Bob) + +- SOAP: + . Fixed bug #71610 (Type Confusion Vulnerability - SOAP / + make_http_soap_request()). (CVE-2016-3185) (Stas) + +- Standard: + . Fixed bug #71603 (compact() maintains references in php7). (Laruence) + . Fixed bug #70720 (strip_tags improper php code parsing). (Julien) + +- XMLRPC: + . Fixed bug #71501 (xmlrpc_encode_request ignores encoding option). (Hieu Le) + +- Zip: + . Fixed bug #71561 (NULL pointer dereference in Zip::ExtractTo). (Laruence) + +04 Feb 2016 PHP 7.0.3 + +- Core: + . Added support for new HTTP 451 code. (Julien) + . Fixed bug #71039 (exec functions ignore length but look for NULL + termination). (Anatol) + . Fixed bug #71089 (No check to duplicate zend_extension). (Remi) + . Fixed bug #71201 (round() segfault on 64-bit builds). (Anatol) + . Fixed bug #71221 (Null pointer deref (segfault) in get_defined_vars via + ob_start). (hugh at allthethings dot co dot nz) + . Fixed bug #71248 (Wrong interface is enforced). (Dmitry) + . Fixed bug #71273 (A wrong ext directory setup in php.ini leads to crash). + (Anatol) + . Fixed Bug #71275 (Bad method called on cloning an object having a trait). + (Bob) + . Fixed bug #71297 (Memory leak with consecutive yield from). (Bob) + . Fixed bug #71300 (Segfault in zend_fetch_string_offset). (Laruence) + . Fixed bug #71314 (var_export(INF) prints INF.0). (Andrea) + . Fixed bug #71323 (Output of stream_get_meta_data can be falsified by its + input). (Leo Gaspard) + . Fixed bug #71336 (Wrong is_ref on properties as exposed via + get_object_vars()). (Laruence) + . Fixed bug #71459 (Integer overflow in iptcembed()). (Stas) + +- Apache2handler: + . Fix >2G Content-Length headers in apache2handler. (Adam Harvey) + +- CURL: + . Fixed bug #71227 (Can't compile php_curl statically). (Anatol) + . Fixed bug #71225 (curl_setopt() fails to set CURLOPT_POSTFIELDS with + reference to CURLFile). (Laruence) + +- GD: + . Improved fix for bug #70976. (Remi) + +- Interbase: + . Fixed Bug #71305 (Crash when optional resource is omitted). + (Laruence, Anatol) + +- LDAP: + . Fixed bug #71249 (ldap_mod_replace/ldap_mod_add store value as string + "Array"). (Laruence) + +- mbstring: + . Fixed bug #71397 (mb_send_mail segmentation fault). (Andrea, Yasuo) + +- OpenSSL: + . Fixed bug #71475 (openssl_seal() uninitialized memory usage). (Stas) + +- PCRE: + . Upgraded pcrelib to 8.38. (CVE-2015-8383, CVE-2015-8386, CVE-2015-8387, + CVE-2015-8389, CVE-2015-8390, CVE-2015-8391, CVE-2015-8393, CVE-2015-8394) + +- Phar: + . Fixed bug #71354 (Heap corruption in tar/zip/phar parser). (CVE-2016-4342) + (Stas) + . Fixed bug #71331 (Uninitialized pointer in phar_make_dirstream()). + (CVE-2016-4343) (Stas) + . Fixed bug #71391 (NULL Pointer Dereference in phar_tar_setupmetadata()). + (Stas) + . Fixed bug #71488 (Stack overflow when decompressing tar archives). + (CVE-2016-2554) (Stas) + +- SOAP: + . Fixed bug #70979 (crash with bad soap request). (Anatol) + +- SPL: + . Fixed bug #71204 (segfault if clean spl_autoload_funcs while autoloading). + (Laruence) + . Fixed bug #71202 (Autoload function registered by another not activated + immediately). (Laruence) + . Fixed bug #71311 (Use-after-free vulnerability in SPL(ArrayObject, + unserialize)). (Sean Heelan) + . Fixed bug #71313 (Use-after-free vulnerability in SPL(SplObjectStorage, + unserialize)). (Sean Heelan) + +- Standard: + . Fixed bug #71287 (Error message contains hexadecimal instead of decimal + number). (Laruence) + . Fixed bug #71264 (file_put_contents() returns unexpected value when + filesystem runs full). (Laruence) + . Fixed bug #71245 (file_get_contents() ignores "header" context option if + it's a reference). (Laruence) + . Fixed bug #71220 (Null pointer deref (segfault) in compact via ob_start). + (hugh at allthethings dot co dot nz) + . Fixed bug #71190 (substr_replace converts integers in original $search + array to strings). (Laruence) + . Fixed bug #71188 (str_replace converts integers in original $search array + to strings). (Laruence) + . Fixed bug #71132, #71197 (range() segfaults). (Thomas Punt) + +- WDDX: + . Fixed bug #71335 (Type Confusion in WDDX Packet Deserialization). (Stas) + +07 Jan 2016 PHP 7.0.2 + +- Core: + . Fixed bug #71165 (-DGC_BENCH=1 doesn't work on PHP7). + (y dot uchiyama dot 1015 at gmail dot com) + . Fixed bug #71163 (Segmentation Fault: cleanup_unfinished_calls). (Laruence) + . Fixed bug #71109 (ZEND_MOD_CONFLICTS("xdebug") doesn't work). (Laruence) + . Fixed bug #71092 (Segmentation fault with return type hinting). (Laruence) + . Fixed bug memleak in header_register_callback. (Laruence) + . Fixed bug #71067 (Local object in class method stays in memory for each + call). (Laruence) + . Fixed bug #66909 (configure fails utf8_to_mutf7 test). (Michael Orlitzky) + . Fixed bug #70781 (Extension tests fail on dynamic ext dependency). + (Francois Laupretre) + . Fixed bug #71089 (No check to duplicate zend_extension). (Remi) + . Fixed bug #71086 (Invalid numeric literal parse error within + highlight_string() function). (Nikita) + . Fixed bug #71154 (Incorrect HT iterator invalidation causes iterator reuse). + (Nikita) + . Fixed bug #52355 (Negating zero does not produce negative zero). (Andrea) + . Fixed bug #66179 (var_export() exports float as integer). (Andrea) + . Fixed bug #70804 (Unary add on negative zero produces positive zero). + (Andrea) + +- CURL: + . Fixed bug #71144 (Sementation fault when using cURL with ZTS). + (Michael Maroszek, Laruence) + +- DBA: + . Fixed key leak with invalid resource. (Laruence) + +- Filter: + . Fixed bug #71063 (filter_input(INPUT_ENV, ..) does not work). (Reeze Xia) + +- FPM: + . Fixed bug #70755 (fpm_log.c memory leak and buffer overflow). (Stas) + +- FTP: + . Implemented FR #55651 (Option to ignore the returned FTP PASV address). + (abrender at elitehosts dot com) + +- GD: + . Fixed bug #70976 (Memory Read via gdImageRotateInterpolated Array Index + Out of Bounds). (CVE-2016-1903) (emmanuel dot law at gmail dot com) + +- Mbstring: + . Fixed bug #71066 (mb_send_mail: Program terminated with signal SIGSEGV, + Segmentation fault). (Laruence) + +- Opcache: + . Fixed bug #71127 (Define in auto_prepend_file is overwrite). (Laruence) + +- PCRE: + . Fixed bug #71178 (preg_replace with arrays creates [0] in replace array + if not already set). (Laruence) + +- Readline: + . Fixed bug #71094 (readline_completion_function corrupts static array on + second TAB). (Nikita) + +- Session: + . Fixed bug #71122 (Session GC may not remove obsolete session data). (Yasuo) + +- SPL: + . Fixed bug #71077 (ReflectionMethod for ArrayObject constructor returns + wrong number of parameters). (Laruence) + . Fixed bug #71153 (Performance Degradation in ArrayIterator with large + arrays). (Nikita) + +- Standard: + . Fixed bug #71270 (Heap BufferOver Flow in escapeshell functions). + (CVE-2016-1904) (emmanuel dot law at gmail dot com) + +- WDDX: + . Fixed bug #70661 (Use After Free Vulnerability in WDDX Packet + Deserialization). (taoguangchen at icloud dot com) + . Fixed bug #70741 (Session WDDX Packet Deserialization Type Confusion + Vulnerability). (taoguangchen at icloud dot com) + +- XMLRPC: + . Fixed bug #70728 (Type Confusion Vulnerability in PHP_to_XMLRPC_worker). + (Julien) + +17 Dec 2015, PHP 7.0.1 + +- Core: + . Fixed bug #71105 (Format String Vulnerability in Class Name Error Message). + (CVE-2015-8617) (andrew at jmpesp dot org) + . Fixed bug #70831 (Compile fails on system with 160 CPUs). (Daniel Axtens) + . Fixed bug #71006 (symbol referencing errors on Sparc/Solaris). (Dmitry) + . Fixed bug #70997 (When using parentClass:: instead of parent::, static + context changed). (Dmitry) + . Fixed bug #70970 (Segfault when combining error handler with output + buffering). (Laruence) + . Fixed bug #70967 (Weird error handling for __toString when Error is + thrown). (Laruence) + . Fixed bug #70958 (Invalid opcode while using ::class as trait method + paramater default value). (Laruence) + . Fixed bug #70944 (try{ } finally{} can create infinite chains of + exceptions). (Laruence) + . Fixed bug #70931 (Two errors messages are in conflict). (dams, Laruence) + . Fixed bug #70904 (yield from incorrectly marks valid generator as + finished). (Bob) + . Fixed bug #70899 (buildconf failure in extensions). (Bob, Reeze) + . Fixed bug #61751 (SAPI build problem on AIX: Undefined symbol: + php_register_internal_extensions). (Lior Kaplan) + . Fixed \int (or generally every scalar type name with leading backslash) + to not be accepted as type name. (Bob) + . Fixed exception not being thrown immediately into a generator yielding + from an array. (Bob) + . Fixed bug #70987 (static::class within Closure::call() causes segfault). + (Andrea) + . Fixed bug #71013 (Incorrect exception handler with yield from). (Bob) + . Fixed double free in error condition of format printer. (Bob) + +- CLI server: + . Fixed bug #71005 (Segfault in php_cli_server_dispatch_router()). (Adam) + +- Intl: + . Fixed bug #71020 (Use after free in Collator::sortWithSortKeys). + (CVE-2015-8616) (emmanuel dot law at gmail dot com, Laruence) + +- Mysqlnd: + . Fixed bug #68077 (LOAD DATA LOCAL INFILE / open_basedir restriction). + (Laruence) + . Fixed bug #68344 (MySQLi does not provide way to disable peer certificate + validation) by introducing MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT + connection flag. (Andrey) + +- OCI8: + . Fixed LOB implementation size_t/zend_long mismatch reported by gcov. + (Senthil) + +- Opcache: + . Fixed bug #71024 (Unable to use PHP 7.0 x64 side-by-side with PHP 5.6 x32 + on the same server). (Anatol) + . Fixed bug #70991 (zend_file_cache.c:710: error: array type has incomplete + element type). (Laruence) + . Fixed bug #70977 (Segmentation fault with opcache.huge_code_pages=1). + (Laruence) + +- PDO_Firebird: + . Fixed bug #60052 (Integer returned as a 64bit integer on X64_86). (Mariuz) + +- Phpdbg: + . Fixed stderr being written to stdout. (Bob) + +- Reflection: + . Fixed bug #71018 (ReflectionProperty::setValue() behavior changed). + (Laruence) + . Fixed bug #70982 (setStaticPropertyValue behaviors inconsistently with + 5.6). (Laruence) + +- Soap: + . Fixed bug #70993 (Array key references break argument processing). + (Laruence) + +- SPL: + . Fixed bug #71028 (Undefined index with ArrayIterator). (Laruence) + +- SQLite3: + . Fixed bug #71049 (SQLite3Stmt::execute() releases bound parameter instead + of internal buffer). (Laruence) + +- Standard: + . Fixed bug #70999 (php_random_bytes: called object is not a function). + (Scott) + . Fixed bug #70960 (ReflectionFunction for array_unique returns wrong number + of parameters). (Laruence) + +- Streams/Socket: + . Add IPV6_V6ONLY constant / make it usable in stream contexts. (Bob) + +03 Dec 2015, PHP 7.0.0 + +- Core: + . Fixed bug #70947 (INI parser segfault with INI_SCANNER_TYPED). (Laruence) + . Fixed bug #70914 (zend_throw_or_error() format string vulnerability). + (Taoguang Chen) + . Fixed bug #70912 (Null ptr dereference instantiating class with invalid + array property). (Laruence) + . Fixed bug #70895, #70898 (null ptr deref and segfault with crafted calable). + (Anatol, Laruence) + . Fixed bug #70249 (Segmentation fault while running PHPUnit tests on + phpBB 3.2-dev). (Laruence) + . Fixed bug #70805 (Segmentation faults whilst running Drupal 8 test suite). + (Dmitry, Laruence) + . Fixed bug #70842 (Persistent Stream Segmentation Fault). (Caleb Champlin) + . Fixed bug #70862 (Several functions do not check return code of + php_stream_copy_to_mem()). (Anatol) + . Fixed bug #70863 (Incorect logic to increment_function for proxy objects). + (Anatol) + . Fixed bug #70323 (Regression in zend_fetch_debug_backtrace() can cause + segfaults). (Aharvey, Laruence) + . Fixed bug #70873 (Regression on private static properties access). + (Laruence) + . Fixed bug #70748 (Segfault in ini_lex () at Zend/zend_ini_scanner.l). + (Laruence) + . Fixed bug #70689 (Exception handler does not work as expected). (Laruence) + . Fixed bug #70430 (Stack buffer overflow in zend_language_parser()). (Nikita) + . Fixed bug #70782 (null ptr deref and segfault (zend_get_class_fetch_type)). + (Nikita) + . Fixed bug #70785 (Infinite loop due to exception during identical + comparison). (Laruence) + . Fixed bug #70630 (Closure::call/bind() crash with ReflectionFunction-> + getClosure()). (Dmitry, Bob) + . Fixed bug #70662 (Duplicate array key via undefined index error handler). + (Nikita) + . Fixed bug #70681 (Segfault when binding $this of internal instance method + to null). (Nikita) + . Fixed bug #70685 (Segfault for getClosure() internal method rebind with + invalid $this). (Nikita) + . Added zend_internal_function.reserved[] fields. (Dmitry) + . Fixed bug #70557 (Memleak on return type verifying failed). (Laruence) + . Fixed bug #70555 (fun_get_arg() on unsetted vars return UNKNOW). (Laruence) + . Fixed bug #70548 (Redundant information printed in case of uncaught engine + exception). (Laruence) + . Fixed bug #70547 (unsetting function variables corrupts backtrace). + (Laruence) + . Fixed bug #70528 (assert() with instanceof adds apostrophes around class + name). (Laruence) + . Fixed bug #70481 (Memory leak in auto_global_copy_ctor() in ZTS build). + (Laruence) + . Fixed bug #70431 (Memory leak in php_ini.c). (Senthil, Laruence) + . Fixed bug #70478 (**= does no longer work). (Bob) + . Fixed bug #70398 (SIGSEGV, Segmentation fault zend_ast_destroy_ex). + (Dmitry, Bob, Laruence) + . Fixed bug #70332 (Wrong behavior while returning reference on object). + (Laruence, Dmitry) + . Fixed bug #70300 (Syntactical inconsistency with new group use syntax). + (marcio dot web2 at gmail dot com) + . Fixed bug #70321 (Magic getter breaks reference to array property). + (Laruence) + . Fixed bug #70187 (Notice: unserialize(): Unexpected end of serialized + data). (Dmitry) + . Fixed bug #70145 (From field incorrectly parsed from headers). (Anatol) + . Fixed bug #70370 (Bundled libtool.m4 doesn't handle FreeBSD 10 when + building extensions). (Adam) + . Fixed bug causing exception traces with anon classes to be truncated. (Bob) + . Fixed bug #70397 (Segmentation fault when using Closure::call and yield). + (Bob) + . Fixed bug #70299 (Memleak while assigning object offsetGet result). + (Laruence) + . Fixed bug #70288 (Apache crash related to ZEND_SEND_REF). (Laruence) + . Fixed bug #70262 (Accessing array crashes PHP 7.0beta3). + (Laruence, Dmitry) + . Fixed bug #70258 (Segfault if do_resize fails to allocated memory). + (Laruence) + . Fixed bug #70253 (segfault at _efree () in zend_alloc.c:1389). (Laruence) + . Fixed bug #70240 (Segfault when doing unset($var());). (Laruence) + . Fixed bug #70223 (Incrementing value returned by magic getter). (Laruence) + . Fixed bug #70215 (Segfault when __invoke is static). (Bob) + . Fixed bug #70207 (Finally is broken with opcache). (Laruence, Dmitry) + . Fixed bug #70173 (ZVAL_COPY_VALUE_EX broken for 32bit Solaris Sparc). + (Laruence, cmb) + . Fixed bug #69487 (SAPI may truncate POST data). (cmb) + . Fixed bug #70198 (Checking liveness does not work as expected). + (Shafreeck Sea, Anatol Belski) + . Fixed bug #70241,#70293 (Skipped assertions affect Generator returns). (Bob) + . Fixed bug #70239 (Creating a huge array doesn't result in exhausted, + but segfault). (Laruence, Anatol) + . Fixed "finally" issues. (Nikita, Dmitry) + . Fixed bug #70098 (Real memory usage doesn't decrease). (Dmitry) + . Fixed bug #70159 (__CLASS__ is lost in closures). (Julien) + . Fixed bug #70156 (Segfault in zend_find_alias_name). (Laruence) + . Fixed bug #70124 (null ptr deref / seg fault in ZEND_HANDLE_EXCEPTION). + (Laruence) + . Fixed bug #70117 (Unexpected return type error). (Laruence) + . Fixed bug #70106 (Inheritance by anonymous class). (Bob) + . Fixed bug #69674 (SIGSEGV array.c:953). (cmb) + . Fixed bug #70164 (__COMPILER_HALT_OFFSET__ under namespace is not defined). + (Bob) + . Fixed bug #70108 (sometimes empty $_SERVER['QUERY_STRING']). (Anatol) + . Fixed bug #70179 ($this refcount issue). (Bob) + . Fixed bug #69896 ('asm' operand has impossible constraints). (Anatol) + . Fixed bug #70183 (null pointer deref (segfault) in zend_eval_const_expr). + (Hugh Davenport) + . Fixed bug #70182 (Segfault in ZEND_ASSIGN_DIV_SPEC_CV_UNUSED_HANDLER). + (Hugh Davenport) + . Fixed bug #69793 (Remotely triggerable stack exhaustion via recursive + method calls). (Stas) + . Fixed bug #69892 (Different arrays compare indentical due to integer key + truncation). (Nikita) + . Fixed bug #70121 (unserialize() could lead to unexpected methods execution + / NULL pointer deref). (Stas) + . Fixed bug #70089 (segfault at ZEND_FETCH_DIM_W_SPEC_VAR_CONST_HANDLER ()). + (Laruence) + . Fixed bug #70057 (Build failure on 32-bit Mac OS X 10.6.8: recursive + inlining). (Laruence) + . Fixed bug #70012 (Exception lost with nested finally block). (Laruence) + . Fixed bug #69996 (Changing the property of a cloned object affects the + original). (Dmitry, Laruence) + . Fixed bug #70083 (Use after free with assign by ref to overloaded objects). + (Bob) + . Fixed bug #70006 (cli - function with default arg = STDOUT crash output). + (Laruence) + . Fixed bug #69521 (Segfault in gc_collect_cycles()). + (arjen at react dot com, Laruence) + . Improved zend_string API. (Francois Laupretre) + . Fixed bug #69955 (Segfault when trying to combine [] and assign-op on + ArrayAccess object). (Laruence) + . Fixed bug #69957 (Different ways of handling div/mod/intdiv). (Bob) + . Fixed bug #69900 (Too long timeout on pipes). (Anatol) + . Fixed bug #69872 (uninitialised value in strtr with array). (Laruence) + . Fixed bug #69868 (Invalid read of size 1 in zend_compile_short_circuiting). + (Laruence) + . Fixed bug #69849 (Broken output of apache_request_headers). (Kalle) + . Fixed bug #69840 (iconv_substr() doesn't work with UTF-16BE). (Kalle) + . Fixed bug #69823 (PHP 7.0.0alpha1 segmentation fault when exactly 33 + extensions are loaded). (Laruence) + . Fixed bug #69805 (null ptr deref and seg fault in zend_resolve_class_name). + (Laruence) + . Fixed bug #69802 (Reflection on Closure::__invoke borks type hint class + name). (Dmitry) + . Fixed bug #69761 (Serialization of anonymous classes should be prevented). + (Laruence) + . Fixed bug #69551 (parse_ini_file() and parse_ini_string() segmentation + fault). (Christoph M. Becker) + . Fixed bug #69781 (phpinfo() reports Professional Editions of Windows + 7/8/8.1/10 as "Business"). (Christian Wenz) + . Fixed bug #69835 (phpinfo() does not report many Windows SKUs). + (Christian Wenz) + . Fixed bug #69889 (Null coalesce operator doesn't work for string offsets). + (Nikita) + . Fixed bug #69891 (Unexpected array comparison result). (Nikita) + . Fixed bug #69892 (Different arrays compare indentical due to integer key + truncation). (Nikita) + . Fixed bug #69893 (Strict comparison between integer and empty string keys + crashes). (Nikita) + . Fixed bug #69767 (Default parameter value with wrong type segfaults). + (cmb, Laruence) + . Fixed bug #69756 (Fatal error: Nesting level too deep - recursive dependency + ? with ===). (Dmitry, Laruence) + . Fixed bug #69758 (Item added to array not being removed by array_pop/shift + ). (Laruence) + . Fixed bug #68475 (Add support for $callable() sytnax with 'Class::method'). + (Julien, Aaron Piotrowski) + . Fixed bug #69485 (Double free on zend_list_dtor). (Laruence) + . Fixed bug #69427 (Segfault on magic method __call of private method in + superclass). (Laruence) + . Improved __call() and __callStatic() magic method handling. Now they are + called in a stackless way using ZEND_CALL_TRAMPOLINE opcode, without + additional stack frame. (Laruence, Dmitry) + . Optimized strings concatenation. (Dmitry, Laruence) + . Fixed weird operators behavior. Division by zero now emits warning and + returns +/-INF, modulo by zero and intdid() throws an exception, shifts + by negative offset throw exceptions. Compile-time evaluation of division + by zero is disabled. (Dmitry, Andrea, Nikita) + . Fixed bug #69371 (Hash table collision leads to inaccessible array keys). + (Laruence) + . Fixed bug #68933 (Invalid read of size 8 in zend_std_read_property). + (Laruence, arjen at react dot com) + . Fixed bug #68252 (segfault in Zend/zend_hash.c in function + _zend_hash_del_el). (Laruence) + . Fixed bug #65598 (Closure executed via static autoload incorrectly marked as + static). (Nikita) + . Fixed bug #66811 (Cannot access static::class in lambda, writen outside of a + class). (Nikita) + . Fixed bug #69568 (call a private function in closure failed). (Nikita) + . Added PHP_INT_MIN constant. (Andrea) + . Added Closure::call() method. (Andrea) + . Fixed bug #67959 (Segfault when calling phpversion('spl')). (Florian) + . Implemented the RFC `Catchable "Call to a member function bar() on a + non-object"`. (Timm) + . Added options parameter for unserialize allowing to specify acceptable + classes (https://wiki.php.net/rfc/secure_unserialize). (Stas) + . Fixed bug #63734 (Garbage collector can free zvals that are still + referenced). (Dmitry) + . Removed ZEND_ACC_FINAL_CLASS, promoting ZEND_ACC_FINAL as final class + modifier. (Guilherme Blanco) + . is_long() & is_integer() is now an alias of is_int(). (Kalle) + . Implemented FR #55467 (phpinfo: PHP Variables with $ and single quotes). (Kalle) + . Added ?? operator. (Andrea) + . Added <=> operator. (Andrea) + . Added \u{xxxxx} Unicode Codepoint Escape Syntax. (Andrea) + . Fixed oversight where define() did not support arrays yet const syntax did. + (Andrea, Dmitry) + . Use "integer" and "float" instead of "long" and "double" in ZPP, type hint + and conversion error messages. (Andrea) + . Implemented FR #55428 (E_RECOVERABLE_ERROR when output buffering in output + buffering handler). (Kalle) + . Removed scoped calls of non-static methods from an incompatible $this + context. (Nikita) + . Removed support for #-style comments in ini files. (Nikita) + . Removed support for assigning the result of new by reference. (Nikita) + . Invalid octal literals in source code now produce compile errors, fixes + PHPSadness #31. (Andrea) + . Removed dl() function on fpm-fcgi. (Nikita) + . Removed support for hexadecimal numeric strings. (Nikita) + . Removed obsolete extensions and SAPIs. See the full list in UPGRADING. (Anatol) + . Added NULL byte protection to exec, system and passthru. (Yasuo) + . Added error_clear_last() function. (Reeze Xia) + . Fixed bug #68797 (Number 2.2250738585072012e-308 converted incorrectly). + (Anatol) + . Improved zend_qsort(using hybrid sorting algo) for better performance, + and also renamed zend_qsort to zend_sort. (Laruence) + . Added stable sorting algo zend_insert_sort. (Laruence) + . Improved zend_memnchr(using sunday algo) for better performance. (Laruence) + . Implemented the RFC `Scalar Type Decalarations v0.5`. (Anthony) + . Implemented the RFC `Group Use Declarations`. (Marcio) + . Implemented the RFC `Continue Output Buffering`. (Mike) + . Implemented the RFC `Constructor behaviour of internal classes`. (Dan, Dmitry) + . Implemented the RFC `Fix "foreach" behavior`. (Dmitry) + . Implemented the RFC `Generator Delegation`. (Bob) + . Implemented the RFC `Anonymous Class Support`. (Joe, Nikita, Dmitry) + . Implemented the RFC `Context Sensitive Lexer`. (Marcio Almada) + . Fixed bug #69511 (Off-by-one buffer overflow in php_sys_readlink). + (Jan Starke, Anatol) + +- CLI server: + . Fixed bug #68291 (404 on urls with '+'). (cmb) + . Fixed bug #66606 (Sets HTTP_CONTENT_TYPE but not CONTENT_TYPE). + (wusuopu, cmb) + . Fixed bug #70264 (CLI server directory traversal). (cmb) + . Fixed bug #69655 (php -S changes MKCALENDAR request method to MKCOL). (cmb) + . Fixed bug #64878 (304 responses return Content-Type header). (cmb) + . Refactor MIME type handling to use a hash table instead of linear search. + (Adam) + . Update the MIME type list from the one shipped by Apache HTTPD. (Adam) + . Added support for SEARCH WebDav method. (Mats Lindh) + +- COM: + . Fixed bug #69939 (Casting object to bool returns false). (Kalle) + +- Curl: + . Fixed bug #70330 (Segmentation Fault with multiple "curl_copy_handle"). + (Laruence) + . Fixed bug #70163 (curl_setopt_array() type confusion). (Laruence) + . Fixed bug #70065 (curl_getinfo() returns corrupted values). (Anatol) + . Fixed bug #69831 (Segmentation fault in curl_getinfo). (im dot denisenko at + yahoo dot com) + . Fixed bug #68937 (Segfault in curl_multi_exec). (Laruence) + . Removed support for unsafe file uploads. (Nikita) + +- Date: + . Fixed bug #70245 (strtotime does not emit warning when 2nd parameter is + object or string). (cmb) + . Fixed bug #70266 (DateInterval::__construct.interval_spec is not supposed to + be optional). (cmb) + . Fixed bug #70277 (new DateTimeZone($foo) is ignoring text after null byte). + (cmb) + . Fixed day_of_week function as it could sometimes return negative values + internally. (Derick) + . Removed $is_dst parameter from mktime() and gmmktime(). (Nikita) + . Removed date.timezone warning + (https://wiki.php.net/rfc/date.timezone_warning_removal). (Bob) + . Added "v" DateTime format modifier to get the 3-digit version of fraction + of seconds. (Mariano Iglesias) + . Implemented FR #69089 (Added DateTime::RFC3339_EXTENDED to output in + RFC3339 Extended format which includes fraction of seconds). (Mariano + Iglesias) + +- DBA: + . Fixed bug #62490 (dba_delete returns true on missing item (inifile)). (Mike) + . Fixed bug #68711 (useless comparisons). (bugreports at internot dot info) + +- DOM: + . Fixed bug #70558 ("Couldn't fetch" error in + DOMDocument::registerNodeClass()). (Laruence) + . Fixed bug #70001 (Assigning to DOMNode::textContent does additional entity + encoding). (cmb) + . Fixed bug #69846 (Segmenation fault (access violation) when iterating over + DOMNodeList). (Anatol Belski) + . Made DOMNode::textContent writeable. (Tjerk) + +- EXIF: + . Fixed bug #70385 (Buffer over-read in exif_read_data with TIFF IFD tag byte + value of 32 bytes). (Stas) + +- Fileinfo: + . Fixed bug #66242 (libmagic: don't assume char is signed). (ArdB) + +- Filter: + . New FILTER_VALIDATE_DOMAIN and better RFC conformance for FILTER_VALIDATE_URL. (Kevin Dunglas) + +- FPM: + . Fixed bug #70538 ("php-fpm -i" crashes). (rainer dot jung at + kippdata dot de) + . Fixed bug #70279 (HTTP Authorization Header is sometimes passed to newer + reqeusts). (Laruence) + . Fixed bug #68945 (Unknown admin values segfault pools). (Laruence) + . Fixed bug #65933 (Cannot specify config lines longer than 1024 bytes). (Chris Wright) + . Implemented FR #67106 (Split main fpm config). (Elan Ruusamäe, Remi) + +- FTP: + . Fixed bug #69082 (FTPS support on Windows). (Anatol) + +- GD: + . Fixed bug #53156 (imagerectangle problem with point ordering). (cmb) + . Fixed bug #66387 (Stack overflow with imagefilltoborder). (CVE-2015-8874) + (cmb) + . Fixed bug #70102 (imagecreatefromwebm() shifts colors). (cmb) + . Fixed bug #66590 (imagewebp() doesn't pad to even length). (cmb) + . Fixed bug #66882 (imagerotate by -90 degrees truncates image by 1px). (cmb) + . Fixed bug #70064 (imagescale(..., IMG_BICUBIC) leaks memory). (cmb) + . Fixed bug #69024 (imagescale segfault with palette based image). (cmb) + . Fixed bug #53154 (Zero-height rectangle has whiskers). (cmb) + . Fixed bug #67447 (imagecrop() add a black line when cropping). (cmb) + . Fixed bug #68714 (copy 'n paste error). (cmb) + . Fixed bug #66339 (PHP segfaults in imagexbm). (cmb) + . Fixed bug #70047 (gd_info() doesn't report WebP support). (cmb) + . Replace libvpx with libwebp for bundled libgd. (cmb, Anatol) + . Fixed bug #61221 (imagegammacorrect function loses alpha channel). (cmb) + . Made fontFetch's path parser thread-safe. (Sara) + . Removed T1Lib support. (Kalle) + +- GMP: + . Fixed bug #70284 (Use after free vulnerability in unserialize() with GMP). + (stas) + +- hash: + . Fixed bug #70312 (HAVAL gives wrong hashes in specific cases). (letsgolee + at naver dot com) + +- IMAP: + . Fixed bug #70158 (Building with static imap fails). (cmb) + . Fixed bug #69998 (curl multi leaking memory). (Pierrick) + +- Intl: + . Fixed bug #70453 (IntlChar::foldCase() incorrect arguments and missing + constants). (cmb) + . Fixed bug #70454 (IntlChar::forDigit second parameter should be optional). + (cmb, colinodell) + . Removed deprecated aliases datefmt_set_timezone_id() and + IntlDateFormatter::setTimeZoneID(). (Nikita) + +- JSON: + . Fixed bug #62010 (json_decode produces invalid byte-sequences). + (Jakub Zelenka) + . Fixed bug #68546 (json_decode() Fatal error: Cannot access property + started with '\0'). (Jakub Zelenka) + . Replace non-free JSON parser with a parser from Jsond extension, fixes #63520 + (JSON extension includes a problematic license statement). (Jakub Zelenka) + . Fixed bug #68938 (json_decode() decodes empty string without error). + (jeremy at bat-country dot us) + +- LDAP: + . Fixed bug #47222 (Implement LDAP_OPT_DIAGNOSTIC_MESSAGE). (Andreas Heigl) + +- LiteSpeed: + . Updated LiteSpeed SAPI code from V5.5 to V6.6. (George Wang) + +- libxml: + . Fixed handling of big lines in error messages with libxml >= 2.9.0. + (Christoph M. Becker) + +- Mcrypt: + . Fixed bug #70625 (mcrypt_encrypt() won't return data when no IV was + specified under RC4). (Nikita) + . Fixed bug #69833 (mcrypt fd caching not working). (Anatol) + . Fixed possible read after end of buffer and use after free. (Dmitry) + . Removed mcrypt_generic_end() alias. (Nikita) + . Removed mcrypt_ecb(), mcrypt_cbc(), mcrypt_cfb(), mcrypt_ofb(). (Nikita) + +- Mysqli: + . Fixed bug #32490 (constructor of mysqli has wrong name). (cmb) + +- Mysqlnd: + . Fixed bug #70949 (SQL Result Sets With NULL Can Cause Fatal Memory Errors). + (Laruence) + . Fixed bug #70384 (mysqli_real_query():Unknown type 245 sent by the server). + (Andrey) + . Fixed bug #70456 (mysqlnd doesn't activate TCP keep-alive when connecting to + a server). (Sergei Turchanov) + . Fixed bug #70572 segfault in mysqlnd_connect. (Andrey, Remi) + . Fixed Bug #69796 (mysqli_stmt::fetch doesn't assign null values to + bound variables). (Laruence) + +- OCI8: + . Fixed memory leak with LOBs. (Senthil) + . Fixed bug #68298 (OCI int overflow) (Senthil). + . Corrected oci8 hash destructors to prevent segfaults, and a few other fixes. + (Cameron Porter) + +- ODBC: + . Fixed bug #69975 (PHP segfaults when accessing nvarchar(max) defined + columns). (cmb) + +- Opcache: + . Fixed bug #70656 (require() statement broken after opcache_reset() or a + few hours of use). (Laruence) + . Fixed bug #70843 (Segmentation fault on MacOSX with + opcache.file_cache_only=1). (Laruence) + . Fixed bug #70724 (Undefined Symbols from opcache.so on Mac OS X 10.10). + (Laruence) + . Fixed compatibility with Windows 10 (see also bug #70652). (Anatol) + . Attmpt to fix "Unable to reattach to base address" problem. (Matt Ficken) + . Fixed bug #70423 (Warning Internal error: wrong size calculation). (Anatol) + . Fixed bug #70237 (Empty while and do-while segmentation fault with opcode + on CLI enabled). (Dmitry, Laruence) + . Fixed bug #70111 (Segfault when a function uses both an explicit return + type and an explicit cast). (Laruence) + . Fixed bug #70058 (Build fails when building for i386). (Laruence) + . Fixed bug #70022 (Crash with opcache using opcache.file_cache_only=1). + (Anatol) + . Removed opcache.load_comments configuration directive. Now doc comments + loading costs nothing and always enabled. (Dmitry) + . Fixed bug #69838 (Wrong size calculation for function table). (Anatol) + . Fixed bug #69688 (segfault with eval and opcache fast shutdown). + (Laruence) + . Added experimental (disabled by default) file based opcode cache. + (Dmitry, Laruence, Anatol) + . Fixed bug with try blocks being removed when extended_info opcode + generation is turned on. (Laruence) + . Fixed bug #68644 (strlen incorrect : mbstring + func_overload=2 +UTF-8 + + Opcache). (Laruence) + +- OpenSSL: + . Require at least OpenSSL version 0.9.8. (Jakub Zelenka) + . Fixed bug #68312 (Lookup for openssl.cnf causes a message box). (Anatol) + . Fixed bug #55259 (openssl extension does not get the DH parameters from + DH key resource). (Jakub Zelenka) + . Fixed bug #70395 (Missing ARG_INFO for openssl_seal()). (cmb) + . Fixed bug #60632 (openssl_seal fails with AES). (Jakub Zelenka) + . Implemented FR #70438 (Add IV parameter for openssl_seal and openssl_open) + (Jakub Zelenka) + . Fixed bug #70014 (openssl_random_pseudo_bytes() is not cryptographically + secure). (CVE-2015-8867) (Stas) + . Fixed bug #69882 (OpenSSL error "key values mismatch" after + openssl_pkcs12_read with extra cert). (Tomasz Sawicki) + . Added "alpn_protocols" SSL context option allowing encrypted client/server + streams to negotiate alternative protocols using the ALPN TLS extension when + built against OpenSSL 1.0.2 or newer. Negotiated protocol information is + accessible through stream_get_meta_data() output. + . Removed "CN_match" and "SNI_server_name" SSL context options. Use automatic + detection or the "peer_name" option instead. (Nikita) + +- Pcntl: + . Fixed bug #70386 (Can't compile on NetBSD because of missing WCONTINUED + and WIFCONTINUED). (Matteo) + . Fixed bug #60509 (pcntl_signal doesn't decrease ref-count of old handler + when setting SIG_DFL). (Julien) + . Implemented FR #68505 (Added wifcontinued and wcontinued). (xilon-jul) + . Added rusage support to pcntl_wait() and pcntl_waitpid(). (Anton Stepanenko, + Tony) + +- PCRE: + . Fixed bug #70232 (Incorrect bump-along behavior with \K and empty string + match). (cmb) + . Fixed bug #70345 (Multiple vulnerabilities related to PCRE functions). + (Anatol Belski) + . Fixed bug #70232 (Incorrect bump-along behavior with \K and empty string + match). (cmb) + . Fixed bug #53823 (preg_replace: * qualifier on unicode replace garbles the + string). (cmb) + . Fixed bug #69864 (Segfault in preg_replace_callback). (cmb, ab) + +- PDO: + . Fixed bug #70861 (Segmentation fault in pdo_parse_params() during Drupal 8 + test suite). (Anatol) + . Fixed bug #70389 (PDO constructor changes unrelated variables). (Laruence) + . Fixed bug #70272 (Segfault in pdo_mysql). (Laruence) + . Fixed bug #70221 (persistent sqlite connection + custom function + segfaults). (Laruence) + . Removed support for the /e (PREG_REPLACE_EVAL) modifier. (Nikita) + . Fixed bug #59450 (./configure fails with "Cannot find php_pdo_driver.h"). + (maxime dot besson at smile dot fr) + +- PDO_DBlib: + . Fixed bug #69757 (Segmentation fault on nextRowset). + (miracle at rpz dot name) + +- PDO_mysql: + . Fixed bug #68424 (Add new PDO mysql connection attr to control multi + statements option). (peter dot wolanin at acquia dot com) + +- PDO_OCI: + . Fixed bug #70308 (PDO::ATTR_PREFETCH is ignored). (Chris Jones) + +- PDO_pgsql: + . Fixed bug #69752 (PDOStatement::execute() leaks memory with DML + Statements when closeCuror() is u). (Philip Hofstetter) + . Removed PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT attribute in favor of + ATTR_EMULATE_PREPARES). (Nikita) + +- Phar: + . Fixed bug #69720 (Null pointer dereference in phar_get_fp_offset()). (Stas) + . FIxed bug #70433 (Uninitialized pointer in phar_make_dirstream when zip + entry filename is "/"). (Stas) + . Improved fix for bug #69441. (Anatol Belski) + . Fixed bug #70019 (Files extracted from archive may be placed outside of + destination directory). (Anatol Belski) + +- Phpdbg: + . Fixed bug #70614 (incorrect exit code in -rr mode with Exceptions). (Bob) + . Fixed bug #70532 (phpdbg must respect set_exception_handler). (Bob) + . Fixed bug #70531 (Run and quit mode (-qrr) should not fallback to + interactive mode). (Bob) + . Fixed bug #70533 (Help overview (-h) does not rpint anything under Windows). + (Anatol) + . Fixed bug #70449 (PHP won't compile on 10.4 and 10.5 because of missing + constants). (Bob) + . Fixed bug #70214 (FASYNC not defined, needs sys/file.h include). (Bob) + . Fixed bug #70138 (Segfault when displaying memory leaks). (Bob) + +- Reflection: + . Fixed bug #70650 (Wrong docblock assignment). (Marcio) + . Fixed bug #70674 (ReflectionFunction::getClosure() leaks memory when used + for internal functions). (Dmitry, Bob) + . Fixed bug causing bogus traces for ReflectionGenerator::getTrace(). (Bob) + . Fixed inheritance chain of Reflector interface. (Tjerk) + . Added ReflectionGenerator class. (Bob) + . Added reflection support for return types and type declarations. (Sara, + Matteo) + +- Session: + . Fixed bug #70876 (Segmentation fault when regenerating session id with + strict mode). (Laruence) + . Fixed bug #70529 (Session read causes "String is not zero-terminated" error). + (Yasuo) + . Fixed bug #70013 (Reference to $_SESSION is lost after a call to + session_regenerate_id()). (Yasuo) + . Fixed bug #69952 (Data integrity issues accessing superglobals by + reference). (Bob) + . Fixed bug #67694 (Regression in session_regenerate_id()). (Tjerk) + . Fixed bug #68941 (mod_files.sh is a bash-script). (bugzilla at ii.nl, Yasuo) + +- SOAP: + . Fixed bug #70940 (Segfault in soap / type_to_string). (Remi) + . Fixed bug #70900 (SoapClient systematic out of memory error). (Dmitry) + . Fixed bug #70875 (Segmentation fault if wsdl has no targetNamespace + attribute). (Matteo) + . Fixed bug #70715 (Segmentation fault inside soap client). (Laruence) + . Fixed bug #70709 (SOAP Client generates Segfault). (Laruence) + . Fixed bug #70388 (SOAP serialize_function_call() type confusion / RCE). + (Stas) + . Fixed bug #70081 (SoapClient info leak / null pointer dereference via + multiple type confusions). (Stas) + . Fixed bug #70079 (Segmentation fault after more than 100 SoapClient + calls). (Laruence) + . Fixed bug #70032 (make_http_soap_request calls + zend_hash_get_current_key_ex(,,,NULL). (Laruence) + . Fixed bug #68361 (Segmentation fault on SoapClient::__getTypes). (Laruence) + +- SPL: + . Fixed bug #70959 (ArrayObject unserialize does not restore protected + fields). (Laruence) + . Fixed bug #70853 (SplFixedArray throws exception when using ref variable + as index). (Laruence) + . Fixed bug #70868 (PCRE JIT and pattern reuse segfault). (Laruence) + . Fixed bug #70730 (Incorrect ArrayObject serialization if unset is called + in serialize()). (Laruence) + . Fixed bug #70573 (Cloning SplPriorityQueue leads to memory leaks). (Dmitry) + . Fixed bug #70303 (Incorrect constructor reflection for ArrayObject). (cmb) + . Fixed bug #70068 (Dangling pointer in the unserialization of ArrayObject + items). (sean.heelan) + . Fixed bug #70166 (Use After Free Vulnerability in unserialize() with + SPLArrayObject). (taoguangchen at icloud dot com) + . Fixed bug #70168 (Use After Free Vulnerability in unserialize() with + SplObjectStorage). (taoguangchen at icloud dot com) + . Fixed bug #70169 (Use After Free Vulnerability in unserialize() with + SplDoublyLinkedList). (taoguangchen at icloud dot com) + . Fixed bug #70053 (MutlitpleIterator array-keys incompatible change in + PHP 7). (Tjerk) + . Fixed bug #69970 (Use-after-free vulnerability in + spl_recursive_it_move_forward_ex()). (Laruence) + . Fixed bug #69845 (ArrayObject with ARRAY_AS_PROPS broken). (Dmitry) + . Changed ArrayIterator implementation using zend_hash_iterator_... API. + Allowed modification of iterated ArrayObject using the same behavior + as proposed in `Fix "foreach" behavior`. Removed "Array was modified + outside object and internal position is no longer valid" hack. (Dmitry) + . Implemented FR #67886 (SplPriorityQueue/SplHeap doesn't expose extractFlags + nor curruption state). (Julien) + . Fixed bug #66405 (RecursiveDirectoryIterator::CURRENT_AS_PATHNAME + breaks the RecursiveIterator). (Paul Garvin) + +- SQLite3: + . Fixed bug #70571 (Memory leak in sqlite3_do_callback). (Adam) + . Fixed bug #69972 (Use-after-free vulnerability in + sqlite3SafetyCheckSickOrOk()). (Laruence) + . Fixed bug #69897 (segfault when manually constructing SQLite3Result). + (Kalle) + . Fixed bug #68260 (SQLite3Result::fetchArray declares wrong + required_num_args). (Julien) + +- Standard: + . Fixed count on symbol tables. (Laruence) + . Fixed bug #70963 (Unserialize shows UNKNOWN in result). (Laruence) + . Fixed bug #70910 (extract() breaks variable references). (Laruence) + . Fixed bug #70808 (array_merge_recursive corrupts memory of unset items). + (Laruence) + . Fixed bug #70667 (strtr() causes invalid writes and a crashes). (Dmitry) + . Fixed bug #70668 (array_keys() doesn't respect references when $strict is + true). (Bob, Dmitry) + . Implemented the RFC `Random Functions Throwing Exceptions in PHP 7`. + (Sammy Kaye Powers, Anthony) + . Fixed bug #70487 (pack('x') produces an error). (Nikita) + . Fixed bug #70342 (changing configuration with ignore_user_abort(true) isn't + working). (Laruence) + . Fixed bug #70295 (Segmentation fault with setrawcookie). (Bob) + . Fixed bug #67131 (setcookie() conditional for empty values not met). (cmb) + . Fixed bug #70365 (Use-after-free vulnerability in unserialize() with + SplObjectStorage). (taoguangchen at icloud dot com) + . Fixed bug #70366 (Use-after-free vulnerability in unserialize() with + SplDoublyLinkedList). (taoguangchen at icloud dot com) + . Fixed bug #70250 (extract() turns array elements to references). + (Laruence) + . Fixed bug #70211 (php 7 ZEND_HASH_IF_FULL_DO_RESIZE use after free). + (Laruence) + . Fixed bug #70208 (Assert breaking access on objects). (Bob) + . Fixed bug #70140 (str_ireplace/php_string_tolower - Arbitrary Code + Execution). (CVE-2015-6527) (Laruence) + . Implemented FR #70112 (Allow "dirname" to go up various times). (Remi) + . Fixed bug #36365 (scandir duplicates file name at every 65535th file). (cmb) + . Fixed bug #70096 (Repeated iptcembed() adds superfluous FF bytes). (cmb) + . Fixed bug #70018 (exec does not strip all whitespace). (Laruence) + . Fixed bug #69983 (get_browser fails with user agent of null). + (Kalle, cmb, Laruence) + . Fixed bug #69976 (Unable to parse "all" urls with colon char). (cmb) + . Fixed bug #69768 (escapeshell*() doesn't cater to !). (cmb) + . Fixed bug #62922 (Truncating entire string should result in string). + (Nikita) + . Fixed bug #69723 (Passing parameters by reference and array_column). + (Laruence) + . Fixed bug #69523 (Cookie name cannot be empty). (Christoph M. Becker) + . Fixed bug #69325 (php_copy_file_ex does not pass the argument). + (imbolk at gmail dot com) + . Fixed bug #69299 (Regression in array_filter's $flag argument in PHP 7). + (Laruence) + . Removed call_user_method() and call_user_method_array() functions. (Kalle) + . Fixed user session handlers (See rfc:session.user.return-value). (Sara) + . Added intdiv() function. (Andrea) + . Improved precision of log() function for base 2 and 10. (Marc Bennewitz) + . Remove string category support in setlocale(). (Nikita) + . Remove set_magic_quotes_runtime() and its alias magic_quotes_runtime(). + (Nikita) + . Fixed bug #65272 (flock() out parameter not set correctly in windows). + (Daniel Lowrey) + . Added preg_replace_callback_array function. (Wei Dai) + . Deprecated salt option to password_hash. (Anthony) + . Fixed bug #69686 (password_verify reports back error on PHP7 will null + string). (Anthony) + . Added Windows support for getrusage(). (Kalle) + . Removed hardcoded limit on number of pipes in proc_open(). (Tony) + +- Streams: + . Fixed bug #70361 (HTTP stream wrapper doesn't close keep-alive connections). + (Niklas Keller) + . Fixed bug #68532 (convert.base64-encode omits padding bytes). + (blaesius at krumedia dot de) + . Removed set_socket_blocking() in favor of its alias stream_set_blocking(). + (Nikita) + +- Tokenizer: + . Fixed bug #69430 (token_get_all has new irrecoverable errors). (Nikita) + +- XMLReader: + . Fixed bug #70309 (XmlReader read generates extra output). (Anatol) + +- XMLRPC + . Fixed bug #70526 (xmlrpc_set_type returns false on success). (Laruence) + +- XSL: + . Fixed bug #70678 (PHP7 returns true when false is expected). (Felipe) + . Fixed bug #70535 (XSLT: free(): invalid pointer). (Laruence) + . Fixed bug #69782 (NULL pointer dereference). (Stas) + . Fixed bug #64776 (The XSLT extension is not thread safe). (Mike) + . Removed xsl.security_prefs ini option. (Nikita) + +- Zlib: + . Added deflate_init(), deflate_add(), inflate_init(), inflate_add() + functions allowing incremental/streaming compression/decompression. + (Daniel Lowrey & Bob Weinand) + +- Zip: + . Fixed bug #70322 (ZipArchive::close() doesn't indicate errors). + (CVE-2014-9767) (cmb) + . Fixed bug #70350 (ZipArchive::extractTo allows for directory traversal when + creating directories). (neal at fb dot com) + . Added ZipArchive::setCompressionName and ZipArchive::setCompressionIndex + methods. (Remi, Cedric Delmas) + . Update bundled libzip to 1.0.1. (Remi, Anatol) + . Fixed bug #67161 (ZipArchive::getStream() returns NULL for certain file). + (Christoph M. Becker) + diff --git a/bin/php/phar.phar.bat b/bin/php/phar.phar.bat new file mode 100644 index 0000000..aac3f76 --- /dev/null +++ b/bin/php/phar.phar.bat @@ -0,0 +1 @@ +"%~dp0php.exe" "%~dp0pharcommand.phar" %* diff --git a/bin/php/pharcommand.phar b/bin/php/pharcommand.phar new file mode 100644 index 0000000..acc2e5d Binary files /dev/null and b/bin/php/pharcommand.phar differ diff --git a/bin/php/php-cgi.exe b/bin/php/php-cgi.exe new file mode 100644 index 0000000..5764b46 Binary files /dev/null and b/bin/php/php-cgi.exe differ diff --git a/bin/php/php-win.exe b/bin/php/php-win.exe new file mode 100644 index 0000000..8a27fb1 Binary files /dev/null and b/bin/php/php-win.exe differ diff --git a/bin/php/php.exe b/bin/php/php.exe new file mode 100644 index 0000000..4eab280 Binary files /dev/null and b/bin/php/php.exe differ diff --git a/bin/php/php.gif b/bin/php/php.gif new file mode 100644 index 0000000..f352c73 Binary files /dev/null and b/bin/php/php.gif differ diff --git a/bin/php/php.ini b/bin/php/php.ini new file mode 100644 index 0000000..ac671f4 --- /dev/null +++ b/bin/php/php.ini @@ -0,0 +1,41 @@ +;Custom DevMine php.ini file +zend.enable_gc = On +max_execution_time = 0 +memory_limit = 256M +error_reporting = -1 +display_errors = stderr +display_startup_errors = On +register_argc_argv = On + +default_charset = "EUC-KR" +internal_encoding ="EUC-KR" +output_encoding = "EUC-KR" + +include_path = ".;.\ext" +extension_dir = "ext" +enable_dl = On +allow_url_fopen = On +//extension=php_weakref.dll +extension=php_curl.dll +extension=php_mysqli.dll +extension=php_sqlite3.dll +extension=php_sockets.dll +extension=php_mbstring.dll +extension=php_yaml.dll +extension=php_pthreads.dll +extension=php_com_dotnet.dll +extension=php_gd2.dll +extension=php_weakref.dll +;zend_extension=php_xdebug.dll +cli_server.color = On +phar.readonly = Off +phar.require_hash = On +opcache.enable=1 +opcache.enable_cli=1 +opcache.memory_consumption=128 +opcache.interned_strings_buffer=8 +opcache.max_accelerated_files=4000 +opcache.save_comments=1 +opcache.load_comments=1 +opcache.fast_shutdown=0 +opcache.optimization_level=0xffffffff \ No newline at end of file diff --git a/bin/php/php.ini-development b/bin/php/php.ini-development new file mode 100644 index 0000000..604efc4 --- /dev/null +++ b/bin/php/php.ini-development @@ -0,0 +1,1873 @@ +[PHP] + +;;;;;;;;;;;;;;;;;;; +; About php.ini ; +;;;;;;;;;;;;;;;;;;; +; PHP's initialization file, generally called php.ini, is responsible for +; configuring many of the aspects of PHP's behavior. + +; PHP attempts to find and load this configuration from a number of locations. +; The following is a summary of its search order: +; 1. SAPI module specific location. +; 2. The PHPRC environment variable. (As of PHP 5.2.0) +; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) +; 4. Current working directory (except CLI) +; 5. The web server's directory (for SAPI modules), or directory of PHP +; (otherwise in Windows) +; 6. The directory from the --with-config-file-path compile time option, or the +; Windows directory (C:\windows or C:\winnt) +; See the PHP docs for more specific information. +; http://php.net/configuration.file + +; The syntax of the file is extremely simple. Whitespace and lines +; beginning with a semicolon are silently ignored (as you probably guessed). +; Section headers (e.g. [Foo]) are also silently ignored, even though +; they might mean something in the future. + +; Directives following the section heading [PATH=/www/mysite] only +; apply to PHP files in the /www/mysite directory. Directives +; following the section heading [HOST=www.example.com] only apply to +; PHP files served from www.example.com. Directives set in these +; special sections cannot be overridden by user-defined INI files or +; at runtime. Currently, [PATH=] and [HOST=] sections only work under +; CGI/FastCGI. +; http://php.net/ini.sections + +; Directives are specified using the following syntax: +; directive = value +; Directive names are *case sensitive* - foo=bar is different from FOO=bar. +; Directives are variables used to configure PHP or PHP extensions. +; There is no name validation. If PHP can't find an expected +; directive because it is not set or is mistyped, a default value will be used. + +; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one +; of the INI constants (On, Off, True, False, Yes, No and None) or an expression +; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a +; previously set variable or directive (e.g. ${foo}) + +; Expressions in the INI file are limited to bitwise operators and parentheses: +; | bitwise OR +; ^ bitwise XOR +; & bitwise AND +; ~ bitwise NOT +; ! boolean NOT + +; Boolean flags can be turned on using the values 1, On, True or Yes. +; They can be turned off using the values 0, Off, False or No. + +; An empty string can be denoted by simply not writing anything after the equal +; sign, or by using the None keyword: + +; foo = ; sets foo to an empty string +; foo = None ; sets foo to an empty string +; foo = "None" ; sets foo to the string 'None' + +; If you use constants in your value, and these constants belong to a +; dynamically loaded extension (either a PHP extension or a Zend extension), +; you may only use these constants *after* the line that loads the extension. + +;;;;;;;;;;;;;;;;;;; +; About this file ; +;;;;;;;;;;;;;;;;;;; +; PHP comes packaged with two INI files. One that is recommended to be used +; in production environments and one that is recommended to be used in +; development environments. + +; php.ini-production contains settings which hold security, performance and +; best practices at its core. But please be aware, these settings may break +; compatibility with older or less security conscience applications. We +; recommending using the production ini in production and testing environments. + +; php.ini-development is very similar to its production variant, except it is +; much more verbose when it comes to errors. We recommend using the +; development version only in development environments, as errors shown to +; application users can inadvertently leak otherwise secure information. + +; This is php.ini-development INI file. + +;;;;;;;;;;;;;;;;;;; +; Quick Reference ; +;;;;;;;;;;;;;;;;;;; +; The following are all the settings which are different in either the production +; or development versions of the INIs with respect to PHP's default behavior. +; Please see the actual settings later in the document for more details as to why +; we recommend these changes in PHP's behavior. + +; display_errors +; Default Value: On +; Development Value: On +; Production Value: Off + +; display_startup_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; error_reporting +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT + +; html_errors +; Default Value: On +; Development Value: On +; Production value: On + +; log_errors +; Default Value: Off +; Development Value: On +; Production Value: On + +; max_input_time +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) + +; output_buffering +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 + +; register_argc_argv +; Default Value: On +; Development Value: Off +; Production Value: Off + +; request_order +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" + +; session.gc_divisor +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 + +; session.hash_bits_per_character +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 + +; short_open_tag +; Default Value: On +; Development Value: Off +; Production Value: Off + +; track_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; url_rewriter.tags +; Default Value: "a=href,area=href,frame=src,form=,fieldset=" +; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" + +; variables_order +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS" + +;;;;;;;;;;;;;;;;;;;; +; php.ini Options ; +;;;;;;;;;;;;;;;;;;;; +; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" +;user_ini.filename = ".user.ini" + +; To disable this feature set this option to empty value +;user_ini.filename = + +; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) +;user_ini.cache_ttl = 300 + +;;;;;;;;;;;;;;;;;;;; +; Language Options ; +;;;;;;;;;;;;;;;;;;;; + +; Enable the PHP scripting language engine under Apache. +; http://php.net/engine +engine = On + +; This directive determines whether or not PHP will recognize code between +; tags as PHP source which should be processed as such. It is +; generally recommended that should be used and that this feature +; should be disabled, as enabling it may result in issues when generating XML +; documents, however this remains supported for backward compatibility reasons. +; Note that this directive does not control the would work. +; http://php.net/syntax-highlighting +;highlight.string = #DD0000 +;highlight.comment = #FF9900 +;highlight.keyword = #007700 +;highlight.default = #0000BB +;highlight.html = #000000 + +; If enabled, the request will be allowed to complete even if the user aborts +; the request. Consider enabling it if executing long requests, which may end up +; being interrupted by the user or a browser timing out. PHP's default behavior +; is to disable this feature. +; http://php.net/ignore-user-abort +;ignore_user_abort = On + +; Determines the size of the realpath cache to be used by PHP. This value should +; be increased on systems where PHP opens many files to reflect the quantity of +; the file operations performed. +; http://php.net/realpath-cache-size +;realpath_cache_size = 16k + +; Duration of time, in seconds for which to cache realpath information for a given +; file or directory. For systems with rarely changing files, consider increasing this +; value. +; http://php.net/realpath-cache-ttl +;realpath_cache_ttl = 120 + +; Enables or disables the circular reference collector. +; http://php.net/zend.enable-gc +zend.enable_gc = On + +; If enabled, scripts may be written in encodings that are incompatible with +; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such +; encodings. To use this feature, mbstring extension must be enabled. +; Default: Off +;zend.multibyte = Off + +; Allows to set the default encoding for the scripts. This value will be used +; unless "declare(encoding=...)" directive appears at the top of the script. +; Only affects if zend.multibyte is set. +; Default: "" +;zend.script_encoding = + +;;;;;;;;;;;;;;;;; +; Miscellaneous ; +;;;;;;;;;;;;;;;;; + +; Decides whether PHP may expose the fact that it is installed on the server +; (e.g. by adding its signature to the Web server header). It is no security +; threat in any way, but it makes it possible to determine whether you use PHP +; on your server or not. +; http://php.net/expose-php +expose_php = On + +;;;;;;;;;;;;;;;;;;; +; Resource Limits ; +;;;;;;;;;;;;;;;;;;; + +; Maximum execution time of each script, in seconds +; http://php.net/max-execution-time +; Note: This directive is hardcoded to 0 for the CLI SAPI +max_execution_time = 30 + +; Maximum amount of time each script may spend parsing request data. It's a good +; idea to limit this time on productions servers in order to eliminate unexpectedly +; long running scripts. +; Note: This directive is hardcoded to -1 for the CLI SAPI +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) +; http://php.net/max-input-time +max_input_time = 60 + +; Maximum input variable nesting level +; http://php.net/max-input-nesting-level +;max_input_nesting_level = 64 + +; How many GET/POST/COOKIE input variables may be accepted +; max_input_vars = 1000 + +; Maximum amount of memory a script may consume (128MB) +; http://php.net/memory-limit +memory_limit = 128M + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Error handling and logging ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; This directive informs PHP of which errors, warnings and notices you would like +; it to take action for. The recommended way of setting values for this +; directive is through the use of the error level constants and bitwise +; operators. The error level constants are below here for convenience as well as +; some common settings and their meanings. +; By default, PHP is set to take action on all errors, notices and warnings EXCEPT +; those related to E_NOTICE and E_STRICT, which together cover best practices and +; recommended coding standards in PHP. For performance reasons, this is the +; recommend error reporting setting. Your production server shouldn't be wasting +; resources complaining about best practices and coding standards. That's what +; development servers and development settings are for. +; Note: The php.ini-development file has this setting as E_ALL. This +; means it pretty much reports everything which is exactly what you want during +; development and early testing. +; +; Error Level Constants: +; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0) +; E_ERROR - fatal run-time errors +; E_RECOVERABLE_ERROR - almost fatal run-time errors +; E_WARNING - run-time warnings (non-fatal errors) +; E_PARSE - compile-time parse errors +; E_NOTICE - run-time notices (these are warnings which often result +; from a bug in your code, but it's possible that it was +; intentional (e.g., using an uninitialized variable and +; relying on the fact it is automatically initialized to an +; empty string) +; E_STRICT - run-time notices, enable to have PHP suggest changes +; to your code which will ensure the best interoperability +; and forward compatibility of your code +; E_CORE_ERROR - fatal errors that occur during PHP's initial startup +; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's +; initial startup +; E_COMPILE_ERROR - fatal compile-time errors +; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) +; E_USER_ERROR - user-generated error message +; E_USER_WARNING - user-generated warning message +; E_USER_NOTICE - user-generated notice message +; E_DEPRECATED - warn about code that will not work in future versions +; of PHP +; E_USER_DEPRECATED - user-generated deprecation warnings +; +; Common Values: +; E_ALL (Show all errors, warnings and notices including coding standards.) +; E_ALL & ~E_NOTICE (Show all errors, except for notices) +; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.) +; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT +; http://php.net/error-reporting +error_reporting = E_ALL + +; This directive controls whether or not and where PHP will output errors, +; notices and warnings too. Error output is very useful during development, but +; it could be very dangerous in production environments. Depending on the code +; which is triggering the error, sensitive information could potentially leak +; out of your application such as database usernames and passwords or worse. +; For production environments, we recommend logging errors rather than +; sending them to STDOUT. +; Possible Values: +; Off = Do not display any errors +; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) +; On or stdout = Display errors to STDOUT +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/display-errors +display_errors = On + +; The display of errors which occur during PHP's startup sequence are handled +; separately from display_errors. PHP's default behavior is to suppress those +; errors from clients. Turning the display of startup errors on can be useful in +; debugging configuration problems. We strongly recommend you +; set this to 'off' for production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/display-startup-errors +display_startup_errors = On + +; Besides displaying errors, PHP can also log errors to locations such as a +; server-specific log, STDERR, or a location specified by the error_log +; directive found below. While errors should not be displayed on productions +; servers they should still be monitored and logging is a great way to do that. +; Default Value: Off +; Development Value: On +; Production Value: On +; http://php.net/log-errors +log_errors = On + +; Set maximum length of log_errors. In error_log information about the source is +; added. The default is 1024 and 0 allows to not apply any maximum length at all. +; http://php.net/log-errors-max-len +log_errors_max_len = 1024 + +; Do not log repeated messages. Repeated errors must occur in same file on same +; line unless ignore_repeated_source is set true. +; http://php.net/ignore-repeated-errors +ignore_repeated_errors = Off + +; Ignore source of message when ignoring repeated messages. When this setting +; is On you will not log errors with repeated messages from different files or +; source lines. +; http://php.net/ignore-repeated-source +ignore_repeated_source = Off + +; If this parameter is set to Off, then memory leaks will not be shown (on +; stdout or in the log). This has only effect in a debug compile, and if +; error reporting includes E_WARNING in the allowed list +; http://php.net/report-memleaks +report_memleaks = On + +; This setting is on by default. +;report_zend_debug = 0 + +; Store the last error/warning message in $php_errormsg (boolean). Setting this value +; to On can assist in debugging and is appropriate for development servers. It should +; however be disabled on production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/track-errors +track_errors = On + +; Turn off normal error reporting and emit XML-RPC error XML +; http://php.net/xmlrpc-errors +;xmlrpc_errors = 0 + +; An XML-RPC faultCode +;xmlrpc_error_number = 0 + +; When PHP displays or logs an error, it has the capability of formatting the +; error message as HTML for easier reading. This directive controls whether +; the error message is formatted as HTML or not. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: On +; Development Value: On +; Production value: On +; http://php.net/html-errors +html_errors = On + +; If html_errors is set to On *and* docref_root is not empty, then PHP +; produces clickable error messages that direct to a page describing the error +; or function causing the error in detail. +; You can download a copy of the PHP manual from http://php.net/docs +; and change docref_root to the base URL of your local copy including the +; leading '/'. You must also specify the file extension being used including +; the dot. PHP's default behavior is to leave these settings empty, in which +; case no links to documentation are generated. +; Note: Never use this feature for production boxes. +; http://php.net/docref-root +; Examples +;docref_root = "/phpmanual/" + +; http://php.net/docref-ext +;docref_ext = .html + +; String to output before an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-prepend-string +; Example: +;error_prepend_string = "" + +; String to output after an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-append-string +; Example: +;error_append_string = "" + +; Log errors to specified file. PHP's default behavior is to leave this value +; empty. +; http://php.net/error-log +; Example: +;error_log = php_errors.log +; Log errors to syslog (Event Log on Windows). +;error_log = syslog + +;windows.show_crt_warning +; Default value: 0 +; Development value: 0 +; Production value: 0 + +;;;;;;;;;;;;;;;;; +; Data Handling ; +;;;;;;;;;;;;;;;;; + +; The separator used in PHP generated URLs to separate arguments. +; PHP's default setting is "&". +; http://php.net/arg-separator.output +; Example: +;arg_separator.output = "&" + +; List of separator(s) used by PHP to parse input URLs into variables. +; PHP's default setting is "&". +; NOTE: Every character in this directive is considered as separator! +; http://php.net/arg-separator.input +; Example: +;arg_separator.input = ";&" + +; This directive determines which super global arrays are registered when PHP +; starts up. G,P,C,E & S are abbreviations for the following respective super +; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty +; paid for the registration of these arrays and because ENV is not as commonly +; used as the others, ENV is not recommended on productions servers. You +; can still get access to the environment variables through getenv() should you +; need to. +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS"; +; http://php.net/variables-order +variables_order = "GPCS" + +; This directive determines which super global data (G,P & C) should be +; registered into the super global array REQUEST. If so, it also determines +; the order in which that data is registered. The values for this directive +; are specified in the same manner as the variables_order directive, +; EXCEPT one. Leaving this value empty will cause PHP to use the value set +; in the variables_order directive. It does not mean it will leave the super +; globals array REQUEST empty. +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" +; http://php.net/request-order +request_order = "GP" + +; This directive determines whether PHP registers $argv & $argc each time it +; runs. $argv contains an array of all the arguments passed to PHP when a script +; is invoked. $argc contains an integer representing the number of arguments +; that were passed when the script was invoked. These arrays are extremely +; useful when running scripts from the command line. When this directive is +; enabled, registering these variables consumes CPU cycles and memory each time +; a script is executed. For performance reasons, this feature should be disabled +; on production servers. +; Note: This directive is hardcoded to On for the CLI SAPI +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-argc-argv +register_argc_argv = Off + +; When enabled, the ENV, REQUEST and SERVER variables are created when they're +; first used (Just In Time) instead of when the script starts. If these +; variables are not used within a script, having this directive on will result +; in a performance gain. The PHP directive register_argc_argv must be disabled +; for this directive to have any affect. +; http://php.net/auto-globals-jit +auto_globals_jit = On + +; Whether PHP will read the POST data. +; This option is enabled by default. +; Most likely, you won't want to disable this option globally. It causes $_POST +; and $_FILES to always be empty; the only way you will be able to read the +; POST data will be through the php://input stream wrapper. This can be useful +; to proxy requests or to process the POST data in a memory efficient fashion. +; http://php.net/enable-post-data-reading +;enable_post_data_reading = Off + +; Maximum size of POST data that PHP will accept. +; Its value may be 0 to disable the limit. It is ignored if POST data reading +; is disabled through enable_post_data_reading. +; http://php.net/post-max-size +post_max_size = 8M + +; Automatically add files before PHP document. +; http://php.net/auto-prepend-file +auto_prepend_file = + +; Automatically add files after PHP document. +; http://php.net/auto-append-file +auto_append_file = + +; By default, PHP will output a media type using the Content-Type header. To +; disable this, simply set it to be empty. +; +; PHP's built-in default media type is set to text/html. +; http://php.net/default-mimetype +default_mimetype = "text/html" + +; PHP's default character set is set to UTF-8. +; http://php.net/default-charset +default_charset = "UTF-8" + +; PHP internal character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/internal-encoding +;internal_encoding = + +; PHP input character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/input-encoding +;input_encoding = + +; PHP output character encoding is set to empty. +; If empty, default_charset is used. +; mbstring or iconv output handler is used. +; See also output_buffer. +; http://php.net/output-encoding +;output_encoding = + +;;;;;;;;;;;;;;;;;;;;;;;;; +; Paths and Directories ; +;;;;;;;;;;;;;;;;;;;;;;;;; + +; UNIX: "/path1:/path2" +;include_path = ".:/php/includes" +; +; Windows: "\path1;\path2" +;include_path = ".;c:\php\includes" +; +; PHP's default setting for include_path is ".;/path/to/php/pear" +; http://php.net/include-path + +; The root of the PHP pages, used only if nonempty. +; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root +; if you are running php as a CGI under any web server (other than IIS) +; see documentation for security issues. The alternate is to use the +; cgi.force_redirect configuration below +; http://php.net/doc-root +doc_root = + +; The directory under which PHP opens the script using /~username used only +; if nonempty. +; http://php.net/user-dir +user_dir = + +; Directory in which the loadable extensions (modules) reside. +; http://php.net/extension-dir +; extension_dir = "./" +; On windows: +; extension_dir = "ext" + +; Directory where the temporary files should be placed. +; Defaults to the system default (see sys_get_temp_dir) +; sys_temp_dir = "/tmp" + +; Whether or not to enable the dl() function. The dl() function does NOT work +; properly in multithreaded servers, such as IIS or Zeus, and is automatically +; disabled on them. +; http://php.net/enable-dl +enable_dl = Off + +; cgi.force_redirect is necessary to provide security running PHP as a CGI under +; most web servers. Left undefined, PHP turns this on by default. You can +; turn it off here AT YOUR OWN RISK +; **You CAN safely turn this off for IIS, in fact, you MUST.** +; http://php.net/cgi.force-redirect +;cgi.force_redirect = 1 + +; if cgi.nph is enabled it will force cgi to always sent Status: 200 with +; every request. PHP's default behavior is to disable this feature. +;cgi.nph = 1 + +; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape +; (iPlanet) web servers, you MAY need to set an environment variable name that PHP +; will look for to know it is OK to continue execution. Setting this variable MAY +; cause security issues, KNOW WHAT YOU ARE DOING FIRST. +; http://php.net/cgi.redirect-status-env +;cgi.redirect_status_env = + +; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +; http://php.net/cgi.fix-pathinfo +;cgi.fix_pathinfo=1 + +; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate +; security tokens of the calling client. This allows IIS to define the +; security context that the request runs under. mod_fastcgi under Apache +; does not currently support this feature (03/17/2002) +; Set to 1 if running under IIS. Default is zero. +; http://php.net/fastcgi.impersonate +;fastcgi.impersonate = 1 + +; Disable logging through FastCGI connection. PHP's default behavior is to enable +; this feature. +;fastcgi.logging = 0 + +; cgi.rfc2616_headers configuration option tells PHP what type of headers to +; use when sending HTTP response code. If set to 0, PHP sends Status: header that +; is supported by Apache. When this option is set to 1, PHP will send +; RFC2616 compliant header. +; Default is zero. +; http://php.net/cgi.rfc2616-headers +;cgi.rfc2616_headers = 0 + +;;;;;;;;;;;;;;;; +; File Uploads ; +;;;;;;;;;;;;;;;; + +; Whether to allow HTTP file uploads. +; http://php.net/file-uploads +file_uploads = On + +; Temporary directory for HTTP uploaded files (will use system default if not +; specified). +; http://php.net/upload-tmp-dir +;upload_tmp_dir = + +; Maximum allowed size for uploaded files. +; http://php.net/upload-max-filesize +upload_max_filesize = 2M + +; Maximum number of files that can be uploaded via a single request +max_file_uploads = 20 + +;;;;;;;;;;;;;;;;;; +; Fopen wrappers ; +;;;;;;;;;;;;;;;;;; + +; Whether to allow the treatment of URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-fopen +allow_url_fopen = On + +; Whether to allow include/require to open URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-include +allow_url_include = Off + +; Define the anonymous ftp password (your email address). PHP's default setting +; for this is empty. +; http://php.net/from +;from="john@doe.com" + +; Define the User-Agent string. PHP's default setting for this is empty. +; http://php.net/user-agent +;user_agent="PHP" + +; Default timeout for socket based streams (seconds) +; http://php.net/default-socket-timeout +default_socket_timeout = 60 + +; If your scripts have to deal with files from Macintosh systems, +; or you are running on a Mac and need to deal with files from +; unix or win32 systems, setting this flag will cause PHP to +; automatically detect the EOL character in those files so that +; fgets() and file() will work regardless of the source of the file. +; http://php.net/auto-detect-line-endings +;auto_detect_line_endings = Off + +;;;;;;;;;;;;;;;;;;;;;; +; Dynamic Extensions ; +;;;;;;;;;;;;;;;;;;;;;; + +; If you wish to have an extension loaded automatically, use the following +; syntax: +; +; extension=modulename.extension +; +; For example, on Windows: +; +; extension=msql.dll +; +; ... or under UNIX: +; +; extension=msql.so +; +; ... or with a path: +; +; extension=/path/to/extension/msql.so +; +; If you only provide the name of the extension, PHP will look for it in its +; default extension directory. +; +; Windows Extensions +; Note that ODBC support is built in, so no dll is needed for it. +; Note that many DLL files are located in the extensions/ (PHP 4) ext/ (PHP 5+) +; extension folders as well as the separate PECL DLL download (PHP 5+). +; Be sure to appropriately set the extension_dir directive. +; +;extension=php_bz2.dll +;extension=php_curl.dll +;extension=php_fileinfo.dll +;extension=php_ftp.dll +;extension=php_gd2.dll +;extension=php_gettext.dll +;extension=php_gmp.dll +;extension=php_intl.dll +;extension=php_imap.dll +;extension=php_interbase.dll +;extension=php_ldap.dll +;extension=php_mbstring.dll +;extension=php_exif.dll ; Must be after mbstring as it depends on it +;extension=php_mysqli.dll +;extension=php_oci8_12c.dll ; Use with Oracle Database 12c Instant Client +;extension=php_openssl.dll +;extension=php_pdo_firebird.dll +;extension=php_pdo_mysql.dll +;extension=php_pdo_oci.dll +;extension=php_pdo_odbc.dll +;extension=php_pdo_pgsql.dll +;extension=php_pdo_sqlite.dll +;extension=php_pgsql.dll +;extension=php_shmop.dll + +; The MIBS data available in the PHP distribution must be installed. +; See http://www.php.net/manual/en/snmp.installation.php +;extension=php_snmp.dll + +;extension=php_soap.dll +;extension=php_sockets.dll +;extension=php_sqlite3.dll +;extension=php_tidy.dll +;extension=php_xmlrpc.dll +;extension=php_xsl.dll + +;;;;;;;;;;;;;;;;;;; +; Module Settings ; +;;;;;;;;;;;;;;;;;;; + +[CLI Server] +; Whether the CLI web server uses ANSI color coding in its terminal output. +cli_server.color = On + +[Date] +; Defines the default timezone used by the date functions +; http://php.net/date.timezone +;date.timezone = + +; http://php.net/date.default-latitude +;date.default_latitude = 31.7667 + +; http://php.net/date.default-longitude +;date.default_longitude = 35.2333 + +; http://php.net/date.sunrise-zenith +;date.sunrise_zenith = 90.583333 + +; http://php.net/date.sunset-zenith +;date.sunset_zenith = 90.583333 + +[filter] +; http://php.net/filter.default +;filter.default = unsafe_raw + +; http://php.net/filter.default-flags +;filter.default_flags = + +[iconv] +; Use of this INI entry is deprecated, use global input_encoding instead. +; If empty, default_charset or input_encoding or iconv.input_encoding is used. +; The precedence is: default_charset < intput_encoding < iconv.input_encoding +;iconv.input_encoding = + +; Use of this INI entry is deprecated, use global internal_encoding instead. +; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. +; The precedence is: default_charset < internal_encoding < iconv.internal_encoding +;iconv.internal_encoding = + +; Use of this INI entry is deprecated, use global output_encoding instead. +; If empty, default_charset or output_encoding or iconv.output_encoding is used. +; The precedence is: default_charset < output_encoding < iconv.output_encoding +; To use an output encoding conversion, iconv's output handler must be set +; otherwise output encoding conversion cannot be performed. +;iconv.output_encoding = + +[intl] +;intl.default_locale = +; This directive allows you to produce PHP errors when some error +; happens within intl functions. The value is the level of the error produced. +; Default is 0, which does not produce any errors. +;intl.error_level = E_WARNING +;intl.use_exceptions = 0 + +[sqlite3] +;sqlite3.extension_dir = + +[Pcre] +;PCRE library backtracking limit. +; http://php.net/pcre.backtrack-limit +;pcre.backtrack_limit=100000 + +;PCRE library recursion limit. +;Please note that if you set this value to a high number you may consume all +;the available process stack and eventually crash PHP (due to reaching the +;stack size limit imposed by the Operating System). +; http://php.net/pcre.recursion-limit +;pcre.recursion_limit=100000 + +;Enables or disables JIT compilation of patterns. This requires the PCRE +;library to be compiled with JIT support. +;pcre.jit=1 + +[Pdo] +; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" +; http://php.net/pdo-odbc.connection-pooling +;pdo_odbc.connection_pooling=strict + +;pdo_odbc.db2_instance_name + +[Pdo_mysql] +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/pdo_mysql.cache_size +pdo_mysql.cache_size = 2000 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/pdo_mysql.default-socket +pdo_mysql.default_socket= + +[Phar] +; http://php.net/phar.readonly +;phar.readonly = On + +; http://php.net/phar.require-hash +;phar.require_hash = On + +;phar.cache_list = + +[mail function] +; For Win32 only. +; http://php.net/smtp +SMTP = localhost +; http://php.net/smtp-port +smtp_port = 25 + +; For Win32 only. +; http://php.net/sendmail-from +;sendmail_from = me@example.com + +; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). +; http://php.net/sendmail-path +;sendmail_path = + +; Force the addition of the specified parameters to be passed as extra parameters +; to the sendmail binary. These parameters will always replace the value of +; the 5th parameter to mail(). +;mail.force_extra_parameters = + +; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename +mail.add_x_header = On + +; The path to a log file that will log all mail() calls. Log entries include +; the full path of the script, line number, To address and headers. +;mail.log = +; Log mail to syslog (Event Log on Windows). +;mail.log = syslog + +[SQL] +; http://php.net/sql.safe-mode +sql.safe_mode = Off + +[ODBC] +; http://php.net/odbc.default-db +;odbc.default_db = Not yet implemented + +; http://php.net/odbc.default-user +;odbc.default_user = Not yet implemented + +; http://php.net/odbc.default-pw +;odbc.default_pw = Not yet implemented + +; Controls the ODBC cursor model. +; Default: SQL_CURSOR_STATIC (default). +;odbc.default_cursortype + +; Allow or prevent persistent links. +; http://php.net/odbc.allow-persistent +odbc.allow_persistent = On + +; Check that a connection is still valid before reuse. +; http://php.net/odbc.check-persistent +odbc.check_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/odbc.max-persistent +odbc.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/odbc.max-links +odbc.max_links = -1 + +; Handling of LONG fields. Returns number of bytes to variables. 0 means +; passthru. +; http://php.net/odbc.defaultlrl +odbc.defaultlrl = 4096 + +; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. +; See the documentation on odbc_binmode and odbc_longreadlen for an explanation +; of odbc.defaultlrl and odbc.defaultbinmode +; http://php.net/odbc.defaultbinmode +odbc.defaultbinmode = 1 + +;birdstep.max_links = -1 + +[Interbase] +; Allow or prevent persistent links. +ibase.allow_persistent = 1 + +; Maximum number of persistent links. -1 means no limit. +ibase.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +ibase.max_links = -1 + +; Default database name for ibase_connect(). +;ibase.default_db = + +; Default username for ibase_connect(). +;ibase.default_user = + +; Default password for ibase_connect(). +;ibase.default_password = + +; Default charset for ibase_connect(). +;ibase.default_charset = + +; Default timestamp format. +ibase.timestampformat = "%Y-%m-%d %H:%M:%S" + +; Default date format. +ibase.dateformat = "%Y-%m-%d" + +; Default time format. +ibase.timeformat = "%H:%M:%S" + +[MySQLi] + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysqli.max-persistent +mysqli.max_persistent = -1 + +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysqli.allow_local_infile +;mysqli.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysqli.allow-persistent +mysqli.allow_persistent = On + +; Maximum number of links. -1 means no limit. +; http://php.net/mysqli.max-links +mysqli.max_links = -1 + +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/mysqli.cache_size +mysqli.cache_size = 2000 + +; Default port number for mysqli_connect(). If unset, mysqli_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysqli.default-port +mysqli.default_port = 3306 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysqli.default-socket +mysqli.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-host +mysqli.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-user +mysqli.default_user = + +; Default password for mysqli_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysqli.default-pw +mysqli.default_pw = + +; Allow or prevent reconnect +mysqli.reconnect = Off + +[mysqlnd] +; Enable / Disable collection of general statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_statistics +mysqlnd.collect_statistics = On + +; Enable / Disable collection of memory usage statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_memory_statistics +mysqlnd.collect_memory_statistics = On + +; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. +; http://php.net/mysqlnd.net_cmd_buffer_size +;mysqlnd.net_cmd_buffer_size = 2048 + +; Size of a pre-allocated buffer used for reading data sent by the server in +; bytes. +; http://php.net/mysqlnd.net_read_buffer_size +;mysqlnd.net_read_buffer_size = 32768 + +[OCI8] + +; Connection: Enables privileged connections using external +; credentials (OCI_SYSOPER, OCI_SYSDBA) +; http://php.net/oci8.privileged-connect +;oci8.privileged_connect = Off + +; Connection: The maximum number of persistent OCI8 connections per +; process. Using -1 means no limit. +; http://php.net/oci8.max-persistent +;oci8.max_persistent = -1 + +; Connection: The maximum number of seconds a process is allowed to +; maintain an idle persistent connection. Using -1 means idle +; persistent connections will be maintained forever. +; http://php.net/oci8.persistent-timeout +;oci8.persistent_timeout = -1 + +; Connection: The number of seconds that must pass before issuing a +; ping during oci_pconnect() to check the connection validity. When +; set to 0, each oci_pconnect() will cause a ping. Using -1 disables +; pings completely. +; http://php.net/oci8.ping-interval +;oci8.ping_interval = 60 + +; Connection: Set this to a user chosen connection class to be used +; for all pooled server requests with Oracle 11g Database Resident +; Connection Pooling (DRCP). To use DRCP, this value should be set to +; the same string for all web servers running the same application, +; the database pool must be configured, and the connection string must +; specify to use a pooled server. +;oci8.connection_class = + +; High Availability: Using On lets PHP receive Fast Application +; Notification (FAN) events generated when a database node fails. The +; database must also be configured to post FAN events. +;oci8.events = Off + +; Tuning: This option enables statement caching, and specifies how +; many statements to cache. Using 0 disables statement caching. +; http://php.net/oci8.statement-cache-size +;oci8.statement_cache_size = 20 + +; Tuning: Enables statement prefetching and sets the default number of +; rows that will be fetched automatically after statement execution. +; http://php.net/oci8.default-prefetch +;oci8.default_prefetch = 100 + +; Compatibility. Using On means oci_close() will not close +; oci_connect() and oci_new_connect() connections. +; http://php.net/oci8.old-oci-close-semantics +;oci8.old_oci_close_semantics = Off + +[PostgreSQL] +; Allow or prevent persistent links. +; http://php.net/pgsql.allow-persistent +pgsql.allow_persistent = On + +; Detect broken persistent links always with pg_pconnect(). +; Auto reset feature requires a little overheads. +; http://php.net/pgsql.auto-reset-persistent +pgsql.auto_reset_persistent = Off + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/pgsql.max-persistent +pgsql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +; http://php.net/pgsql.max-links +pgsql.max_links = -1 + +; Ignore PostgreSQL backends Notice message or not. +; Notice message logging require a little overheads. +; http://php.net/pgsql.ignore-notice +pgsql.ignore_notice = 0 + +; Log PostgreSQL backends Notice message or not. +; Unless pgsql.ignore_notice=0, module cannot log notice message. +; http://php.net/pgsql.log-notice +pgsql.log_notice = 0 + +[bcmath] +; Number of decimal digits for all bcmath functions. +; http://php.net/bcmath.scale +bcmath.scale = 0 + +[browscap] +; http://php.net/browscap +;browscap = extra/browscap.ini + +[Session] +; Handler used to store/retrieve data. +; http://php.net/session.save-handler +session.save_handler = files + +; Argument passed to save_handler. In the case of files, this is the path +; where data files are stored. Note: Windows users have to change this +; variable in order to use PHP's session functions. +; +; The path can be defined as: +; +; session.save_path = "N;/path" +; +; where N is an integer. Instead of storing all the session files in +; /path, what this will do is use subdirectories N-levels deep, and +; store the session data in those directories. This is useful if +; your OS has problems with many files in one directory, and is +; a more efficient layout for servers that handle many sessions. +; +; NOTE 1: PHP will not create this directory structure automatically. +; You can use the script in the ext/session dir for that purpose. +; NOTE 2: See the section on garbage collection below if you choose to +; use subdirectories for session storage +; +; The file storage module creates files using mode 600 by default. +; You can change that by using +; +; session.save_path = "N;MODE;/path" +; +; where MODE is the octal representation of the mode. Note that this +; does not overwrite the process's umask. +; http://php.net/session.save-path +;session.save_path = "/tmp" + +; Whether to use strict session mode. +; Strict session mode does not accept uninitialized session ID and regenerate +; session ID if browser sends uninitialized session ID. Strict mode protects +; applications from session fixation via session adoption vulnerability. It is +; disabled by default for maximum compatibility, but enabling it is encouraged. +; https://wiki.php.net/rfc/strict_sessions +session.use_strict_mode = 0 + +; Whether to use cookies. +; http://php.net/session.use-cookies +session.use_cookies = 1 + +; http://php.net/session.cookie-secure +;session.cookie_secure = + +; This option forces PHP to fetch and use a cookie for storing and maintaining +; the session id. We encourage this operation as it's very helpful in combating +; session hijacking when not specifying and managing your own session id. It is +; not the be-all and end-all of session hijacking defense, but it's a good start. +; http://php.net/session.use-only-cookies +session.use_only_cookies = 1 + +; Name of the session (used as cookie name). +; http://php.net/session.name +session.name = PHPSESSID + +; Initialize session on request startup. +; http://php.net/session.auto-start +session.auto_start = 0 + +; Lifetime in seconds of cookie or, if 0, until browser is restarted. +; http://php.net/session.cookie-lifetime +session.cookie_lifetime = 0 + +; The path for which the cookie is valid. +; http://php.net/session.cookie-path +session.cookie_path = / + +; The domain for which the cookie is valid. +; http://php.net/session.cookie-domain +session.cookie_domain = + +; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. +; http://php.net/session.cookie-httponly +session.cookie_httponly = + +; Handler used to serialize data. php is the standard serializer of PHP. +; http://php.net/session.serialize-handler +session.serialize_handler = php + +; Defines the probability that the 'garbage collection' process is started +; on every session initialization. The probability is calculated by using +; gc_probability/gc_divisor. Where session.gc_probability is the numerator +; and gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.gc-probability +session.gc_probability = 1 + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using the following equation: +; gc_probability/gc_divisor. Where session.gc_probability is the numerator and +; session.gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. Increasing this value to 1000 will give you +; a 0.1% chance the gc will run on any give request. For high volume production servers, +; this is a more efficient approach. +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 +; http://php.net/session.gc-divisor +session.gc_divisor = 1000 + +; After this number of seconds, stored data will be seen as 'garbage' and +; cleaned up by the garbage collection process. +; http://php.net/session.gc-maxlifetime +session.gc_maxlifetime = 1440 + +; NOTE: If you are using the subdirectory option for storing session files +; (see session.save_path above), then garbage collection does *not* +; happen automatically. You will need to do your own garbage +; collection through a shell script, cron entry, or some other method. +; For example, the following script would is the equivalent of +; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): +; find /path/to/sessions -cmin +24 -type f | xargs rm + +; Check HTTP Referer to invalidate externally stored URLs containing ids. +; HTTP_REFERER has to contain this substring for the session to be +; considered as valid. +; http://php.net/session.referer-check +session.referer_check = + +; How many bytes to read from the file. +; http://php.net/session.entropy-length +;session.entropy_length = 32 + +; Specified here to create the session id. +; http://php.net/session.entropy-file +; Defaults to /dev/urandom +; On systems that don't have /dev/urandom but do have /dev/arandom, this will default to /dev/arandom +; If neither are found at compile time, the default is no entropy file. +; On windows, setting the entropy_length setting will activate the +; Windows random source (using the CryptoAPI) +;session.entropy_file = /dev/urandom + +; Set to {nocache,private,public,} to determine HTTP caching aspects +; or leave this empty to avoid sending anti-caching headers. +; http://php.net/session.cache-limiter +session.cache_limiter = nocache + +; Document expires after n minutes. +; http://php.net/session.cache-expire +session.cache_expire = 180 + +; trans sid support is disabled by default. +; Use of trans sid may risk your users' security. +; Use this option with caution. +; - User may send URL contains active session ID +; to other person via. email/irc/etc. +; - URL that contains active session ID may be stored +; in publicly accessible computer. +; - User may access your site with the same session ID +; always using URL stored in browser's history or bookmarks. +; http://php.net/session.use-trans-sid +session.use_trans_sid = 0 + +; Select a hash function for use in generating session ids. +; Possible Values +; 0 (MD5 128 bits) +; 1 (SHA-1 160 bits) +; This option may also be set to the name of any hash function supported by +; the hash extension. A list of available hashes is returned by the hash_algos() +; function. +; http://php.net/session.hash-function +session.hash_function = 0 + +; Define how many bits are stored in each character when converting +; the binary hash data to something readable. +; Possible values: +; 4 (4 bits: 0-9, a-f) +; 5 (5 bits: 0-9, a-v) +; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 +; http://php.net/session.hash-bits-per-character +session.hash_bits_per_character = 5 + +; The URL rewriter will look for URLs in a defined set of HTML tags. +; form/fieldset are special; if you include them here, the rewriter will +; add a hidden field with the info which is otherwise appended +; to URLs. If you want XHTML conformity, remove the form entry. +; Note that all valid entries require a "=", even if no value follows. +; Default Value: "a=href,area=href,frame=src,form=,fieldset=" +; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; http://php.net/url-rewriter.tags +url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" + +; Enable upload progress tracking in $_SESSION +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.enabled +;session.upload_progress.enabled = On + +; Cleanup the progress information as soon as all POST data has been read +; (i.e. upload completed). +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.cleanup +;session.upload_progress.cleanup = On + +; A prefix used for the upload progress key in $_SESSION +; Default Value: "upload_progress_" +; Development Value: "upload_progress_" +; Production Value: "upload_progress_" +; http://php.net/session.upload-progress.prefix +;session.upload_progress.prefix = "upload_progress_" + +; The index name (concatenated with the prefix) in $_SESSION +; containing the upload progress information +; Default Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Development Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Production Value: "PHP_SESSION_UPLOAD_PROGRESS" +; http://php.net/session.upload-progress.name +;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" + +; How frequently the upload progress should be updated. +; Given either in percentages (per-file), or in bytes +; Default Value: "1%" +; Development Value: "1%" +; Production Value: "1%" +; http://php.net/session.upload-progress.freq +;session.upload_progress.freq = "1%" + +; The minimum delay between updates, in seconds +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.upload-progress.min-freq +;session.upload_progress.min_freq = "1" + +; Only write session data when session data is changed. Enabled by default. +; http://php.net/session.lazy-write +;session.lazy_write = On + +[Assertion] +; Switch whether to compile assertions at all (to have no overhead at run-time) +; -1: Do not compile at all +; 0: Jump over assertion at run-time +; 1: Execute assertions +; Changing from or to a negative value is only possible in php.ini! (For turning assertions on and off at run-time, see assert.active, when zend.assertions = 1) +; Default Value: 1 +; Development Value: 1 +; Production Value: -1 +; http://php.net/zend.assertions +zend.assertions = 1 + +; Assert(expr); active by default. +; http://php.net/assert.active +;assert.active = On + +; Throw an AssertationException on failed assertions +; http://php.net/assert.exception +;assert.exception = On + +; Issue a PHP warning for each failed assertion. (Overridden by assert.exception if active) +; http://php.net/assert.warning +;assert.warning = On + +; Don't bail out by default. +; http://php.net/assert.bail +;assert.bail = Off + +; User-function to be called if an assertion fails. +; http://php.net/assert.callback +;assert.callback = 0 + +; Eval the expression with current error_reporting(). Set to true if you want +; error_reporting(0) around the eval(). +; http://php.net/assert.quiet-eval +;assert.quiet_eval = 0 + +[COM] +; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs +; http://php.net/com.typelib-file +;com.typelib_file = + +; allow Distributed-COM calls +; http://php.net/com.allow-dcom +;com.allow_dcom = true + +; autoregister constants of a components typlib on com_load() +; http://php.net/com.autoregister-typelib +;com.autoregister_typelib = true + +; register constants casesensitive +; http://php.net/com.autoregister-casesensitive +;com.autoregister_casesensitive = false + +; show warnings on duplicate constant registrations +; http://php.net/com.autoregister-verbose +;com.autoregister_verbose = true + +; The default character set code-page to use when passing strings to and from COM objects. +; Default: system ANSI code page +;com.code_page= + +[mbstring] +; language for internal character representation. +; This affects mb_send_mail() and mbstring.detect_order. +; http://php.net/mbstring.language +;mbstring.language = Japanese + +; Use of this INI entry is deprecated, use global internal_encoding instead. +; internal/script encoding. +; Some encoding cannot work as internal encoding. (e.g. SJIS, BIG5, ISO-2022-*) +; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. +; The precedence is: default_charset < internal_encoding < iconv.internal_encoding +;mbstring.internal_encoding = + +; Use of this INI entry is deprecated, use global input_encoding instead. +; http input encoding. +; mbstring.encoding_traslation = On is needed to use this setting. +; If empty, default_charset or input_encoding or mbstring.input is used. +; The precedence is: default_charset < intput_encoding < mbsting.http_input +; http://php.net/mbstring.http-input +;mbstring.http_input = + +; Use of this INI entry is deprecated, use global output_encoding instead. +; http output encoding. +; mb_output_handler must be registered as output buffer to function. +; If empty, default_charset or output_encoding or mbstring.http_output is used. +; The precedence is: default_charset < output_encoding < mbstring.http_output +; To use an output encoding conversion, mbstring's output handler must be set +; otherwise output encoding conversion cannot be performed. +; http://php.net/mbstring.http-output +;mbstring.http_output = + +; enable automatic encoding translation according to +; mbstring.internal_encoding setting. Input chars are +; converted to internal encoding by setting this to On. +; Note: Do _not_ use automatic encoding translation for +; portable libs/applications. +; http://php.net/mbstring.encoding-translation +;mbstring.encoding_translation = Off + +; automatic encoding detection order. +; "auto" detect order is changed according to mbstring.language +; http://php.net/mbstring.detect-order +;mbstring.detect_order = auto + +; substitute_character used when character cannot be converted +; one from another +; http://php.net/mbstring.substitute-character +;mbstring.substitute_character = none + +; overload(replace) single byte functions by mbstring functions. +; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), +; etc. Possible values are 0,1,2,4 or combination of them. +; For example, 7 for overload everything. +; 0: No overload +; 1: Overload mail() function +; 2: Overload str*() functions +; 4: Overload ereg*() functions +; http://php.net/mbstring.func-overload +;mbstring.func_overload = 0 + +; enable strict encoding detection. +; Default: Off +;mbstring.strict_detection = On + +; This directive specifies the regex pattern of content types for which mb_output_handler() +; is activated. +; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) +;mbstring.http_output_conv_mimetype= + +[gd] +; Tell the jpeg decode to ignore warnings and try to create +; a gd image. The warning will then be displayed as notices +; disabled by default +; http://php.net/gd.jpeg-ignore-warning +;gd.jpeg_ignore_warning = 0 + +[exif] +; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. +; With mbstring support this will automatically be converted into the encoding +; given by corresponding encode setting. When empty mbstring.internal_encoding +; is used. For the decode settings you can distinguish between motorola and +; intel byte order. A decode setting cannot be empty. +; http://php.net/exif.encode-unicode +;exif.encode_unicode = ISO-8859-15 + +; http://php.net/exif.decode-unicode-motorola +;exif.decode_unicode_motorola = UCS-2BE + +; http://php.net/exif.decode-unicode-intel +;exif.decode_unicode_intel = UCS-2LE + +; http://php.net/exif.encode-jis +;exif.encode_jis = + +; http://php.net/exif.decode-jis-motorola +;exif.decode_jis_motorola = JIS + +; http://php.net/exif.decode-jis-intel +;exif.decode_jis_intel = JIS + +[Tidy] +; The path to a default tidy configuration file to use when using tidy +; http://php.net/tidy.default-config +;tidy.default_config = /usr/local/lib/php/default.tcfg + +; Should tidy clean and repair output automatically? +; WARNING: Do not use this option if you are generating non-html content +; such as dynamic images +; http://php.net/tidy.clean-output +tidy.clean_output = Off + +[soap] +; Enables or disables WSDL caching feature. +; http://php.net/soap.wsdl-cache-enabled +soap.wsdl_cache_enabled=1 + +; Sets the directory name where SOAP extension will put cache files. +; http://php.net/soap.wsdl-cache-dir +soap.wsdl_cache_dir="/tmp" + +; (time to live) Sets the number of second while cached file will be used +; instead of original one. +; http://php.net/soap.wsdl-cache-ttl +soap.wsdl_cache_ttl=86400 + +; Sets the size of the cache limit. (Max. number of WSDL files to cache) +soap.wsdl_cache_limit = 5 + +[sysvshm] +; A default size of the shared memory segment +;sysvshm.init_mem = 10000 + +[ldap] +; Sets the maximum number of open links or -1 for unlimited. +ldap.max_links = -1 + +[mcrypt] +; For more information about mcrypt settings see http://php.net/mcrypt-module-open + +; Directory where to load mcrypt algorithms +; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) +;mcrypt.algorithms_dir= + +; Directory where to load mcrypt modes +; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) +;mcrypt.modes_dir= + +[dba] +;dba.default_handler= + +[opcache] +; Determines if Zend OPCache is enabled +;opcache.enable=0 + +; Determines if Zend OPCache is enabled for the CLI version of PHP +;opcache.enable_cli=0 + +; The OPcache shared memory storage size. +;opcache.memory_consumption=64 + +; The amount of memory for interned strings in Mbytes. +;opcache.interned_strings_buffer=4 + +; The maximum number of keys (scripts) in the OPcache hash table. +; Only numbers between 200 and 100000 are allowed. +;opcache.max_accelerated_files=2000 + +; The maximum percentage of "wasted" memory until a restart is scheduled. +;opcache.max_wasted_percentage=5 + +; When this directive is enabled, the OPcache appends the current working +; directory to the script key, thus eliminating possible collisions between +; files with the same name (basename). Disabling the directive improves +; performance, but may break existing applications. +;opcache.use_cwd=1 + +; When disabled, you must reset the OPcache manually or restart the +; webserver for changes to the filesystem to take effect. +;opcache.validate_timestamps=1 + +; How often (in seconds) to check file timestamps for changes to the shared +; memory storage allocation. ("1" means validate once per second, but only +; once per request. "0" means always validate) +;opcache.revalidate_freq=2 + +; Enables or disables file search in include_path optimization +;opcache.revalidate_path=0 + +; If disabled, all PHPDoc comments are dropped from the code to reduce the +; size of the optimized code. +;opcache.save_comments=1 + +; If enabled, a fast shutdown sequence is used for the accelerated code +;opcache.fast_shutdown=0 + +; Allow file existence override (file_exists, etc.) performance feature. +;opcache.enable_file_override=0 + +; A bitmask, where each bit enables or disables the appropriate OPcache +; passes +;opcache.optimization_level=0xffffffff + +;opcache.inherited_hack=1 +;opcache.dups_fix=0 + +; The location of the OPcache blacklist file (wildcards allowed). +; Each OPcache blacklist file is a text file that holds the names of files +; that should not be accelerated. The file format is to add each filename +; to a new line. The filename may be a full path or just a file prefix +; (i.e., /var/www/x blacklists all the files and directories in /var/www +; that start with 'x'). Line starting with a ; are ignored (comments). +;opcache.blacklist_filename= + +; Allows exclusion of large files from being cached. By default all files +; are cached. +;opcache.max_file_size=0 + +; Check the cache checksum each N requests. +; The default value of "0" means that the checks are disabled. +;opcache.consistency_checks=0 + +; How long to wait (in seconds) for a scheduled restart to begin if the cache +; is not being accessed. +;opcache.force_restart_timeout=180 + +; OPcache error_log file name. Empty string assumes "stderr". +;opcache.error_log= + +; All OPcache errors go to the Web server log. +; By default, only fatal errors (level 0) or errors (level 1) are logged. +; You can also enable warnings (level 2), info messages (level 3) or +; debug messages (level 4). +;opcache.log_verbosity_level=1 + +; Preferred Shared Memory back-end. Leave empty and let the system decide. +;opcache.preferred_memory_model= + +; Protect the shared memory from unexpected writing during script execution. +; Useful for internal debugging only. +;opcache.protect_memory=0 + +; Allows calling OPcache API functions only from PHP scripts which path is +; started from specified string. The default "" means no restriction +;opcache.restrict_api= + +; Mapping base of shared memory segments (for Windows only). All the PHP +; processes have to map shared memory into the same address space. This +; directive allows to manually fix the "Unable to reattach to base address" +; errors. +;opcache.mmap_base= + +; Enables and sets the second level cache directory. +; It should improve performance when SHM memory is full, at server restart or +; SHM reset. The default "" disables file based caching. +;opcache.file_cache= + +; Enables or disables opcode caching in shared memory. +;opcache.file_cache_only=0 + +; Enables or disables checksum validation when script loaded from file cache. +;opcache.file_cache_consistency_checks=1 + +; Enables or disables copying of PHP code (text segment) into HUGE PAGES. +; This should improve performance, but requires appropriate OS configuration. +;opcache.huge_code_pages=0 + +[curl] +; A default value for the CURLOPT_CAINFO option. This is required to be an +; absolute path. +;curl.cainfo = + +[openssl] +; The location of a Certificate Authority (CA) file on the local filesystem +; to use when verifying the identity of SSL/TLS peers. Most users should +; not specify a value for this directive as PHP will attempt to use the +; OS-managed cert stores in its absence. If specified, this value may still +; be overridden on a per-stream basis via the "cafile" SSL stream context +; option. +;openssl.cafile= + +; If openssl.cafile is not specified or if the CA file is not found, the +; directory pointed to by openssl.capath is searched for a suitable +; certificate. This value must be a correctly hashed certificate directory. +; Most users should not specify a value for this directive as PHP will +; attempt to use the OS-managed cert stores in its absence. If specified, +; this value may still be overridden on a per-stream basis via the "capath" +; SSL stream context option. +;openssl.capath= + +; Local Variables: +; tab-width: 4 +; End: diff --git a/bin/php/php.ini-production b/bin/php/php.ini-production new file mode 100644 index 0000000..f2723f6 --- /dev/null +++ b/bin/php/php.ini-production @@ -0,0 +1,1873 @@ +[PHP] + +;;;;;;;;;;;;;;;;;;; +; About php.ini ; +;;;;;;;;;;;;;;;;;;; +; PHP's initialization file, generally called php.ini, is responsible for +; configuring many of the aspects of PHP's behavior. + +; PHP attempts to find and load this configuration from a number of locations. +; The following is a summary of its search order: +; 1. SAPI module specific location. +; 2. The PHPRC environment variable. (As of PHP 5.2.0) +; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) +; 4. Current working directory (except CLI) +; 5. The web server's directory (for SAPI modules), or directory of PHP +; (otherwise in Windows) +; 6. The directory from the --with-config-file-path compile time option, or the +; Windows directory (C:\windows or C:\winnt) +; See the PHP docs for more specific information. +; http://php.net/configuration.file + +; The syntax of the file is extremely simple. Whitespace and lines +; beginning with a semicolon are silently ignored (as you probably guessed). +; Section headers (e.g. [Foo]) are also silently ignored, even though +; they might mean something in the future. + +; Directives following the section heading [PATH=/www/mysite] only +; apply to PHP files in the /www/mysite directory. Directives +; following the section heading [HOST=www.example.com] only apply to +; PHP files served from www.example.com. Directives set in these +; special sections cannot be overridden by user-defined INI files or +; at runtime. Currently, [PATH=] and [HOST=] sections only work under +; CGI/FastCGI. +; http://php.net/ini.sections + +; Directives are specified using the following syntax: +; directive = value +; Directive names are *case sensitive* - foo=bar is different from FOO=bar. +; Directives are variables used to configure PHP or PHP extensions. +; There is no name validation. If PHP can't find an expected +; directive because it is not set or is mistyped, a default value will be used. + +; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one +; of the INI constants (On, Off, True, False, Yes, No and None) or an expression +; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a +; previously set variable or directive (e.g. ${foo}) + +; Expressions in the INI file are limited to bitwise operators and parentheses: +; | bitwise OR +; ^ bitwise XOR +; & bitwise AND +; ~ bitwise NOT +; ! boolean NOT + +; Boolean flags can be turned on using the values 1, On, True or Yes. +; They can be turned off using the values 0, Off, False or No. + +; An empty string can be denoted by simply not writing anything after the equal +; sign, or by using the None keyword: + +; foo = ; sets foo to an empty string +; foo = None ; sets foo to an empty string +; foo = "None" ; sets foo to the string 'None' + +; If you use constants in your value, and these constants belong to a +; dynamically loaded extension (either a PHP extension or a Zend extension), +; you may only use these constants *after* the line that loads the extension. + +;;;;;;;;;;;;;;;;;;; +; About this file ; +;;;;;;;;;;;;;;;;;;; +; PHP comes packaged with two INI files. One that is recommended to be used +; in production environments and one that is recommended to be used in +; development environments. + +; php.ini-production contains settings which hold security, performance and +; best practices at its core. But please be aware, these settings may break +; compatibility with older or less security conscience applications. We +; recommending using the production ini in production and testing environments. + +; php.ini-development is very similar to its production variant, except it is +; much more verbose when it comes to errors. We recommend using the +; development version only in development environments, as errors shown to +; application users can inadvertently leak otherwise secure information. + +; This is php.ini-production INI file. + +;;;;;;;;;;;;;;;;;;; +; Quick Reference ; +;;;;;;;;;;;;;;;;;;; +; The following are all the settings which are different in either the production +; or development versions of the INIs with respect to PHP's default behavior. +; Please see the actual settings later in the document for more details as to why +; we recommend these changes in PHP's behavior. + +; display_errors +; Default Value: On +; Development Value: On +; Production Value: Off + +; display_startup_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; error_reporting +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT + +; html_errors +; Default Value: On +; Development Value: On +; Production value: On + +; log_errors +; Default Value: Off +; Development Value: On +; Production Value: On + +; max_input_time +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) + +; output_buffering +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 + +; register_argc_argv +; Default Value: On +; Development Value: Off +; Production Value: Off + +; request_order +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" + +; session.gc_divisor +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 + +; session.hash_bits_per_character +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 + +; short_open_tag +; Default Value: On +; Development Value: Off +; Production Value: Off + +; track_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; url_rewriter.tags +; Default Value: "a=href,area=href,frame=src,form=,fieldset=" +; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" + +; variables_order +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS" + +;;;;;;;;;;;;;;;;;;;; +; php.ini Options ; +;;;;;;;;;;;;;;;;;;;; +; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" +;user_ini.filename = ".user.ini" + +; To disable this feature set this option to empty value +;user_ini.filename = + +; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) +;user_ini.cache_ttl = 300 + +;;;;;;;;;;;;;;;;;;;; +; Language Options ; +;;;;;;;;;;;;;;;;;;;; + +; Enable the PHP scripting language engine under Apache. +; http://php.net/engine +engine = On + +; This directive determines whether or not PHP will recognize code between +; tags as PHP source which should be processed as such. It is +; generally recommended that should be used and that this feature +; should be disabled, as enabling it may result in issues when generating XML +; documents, however this remains supported for backward compatibility reasons. +; Note that this directive does not control the would work. +; http://php.net/syntax-highlighting +;highlight.string = #DD0000 +;highlight.comment = #FF9900 +;highlight.keyword = #007700 +;highlight.default = #0000BB +;highlight.html = #000000 + +; If enabled, the request will be allowed to complete even if the user aborts +; the request. Consider enabling it if executing long requests, which may end up +; being interrupted by the user or a browser timing out. PHP's default behavior +; is to disable this feature. +; http://php.net/ignore-user-abort +;ignore_user_abort = On + +; Determines the size of the realpath cache to be used by PHP. This value should +; be increased on systems where PHP opens many files to reflect the quantity of +; the file operations performed. +; http://php.net/realpath-cache-size +;realpath_cache_size = 16k + +; Duration of time, in seconds for which to cache realpath information for a given +; file or directory. For systems with rarely changing files, consider increasing this +; value. +; http://php.net/realpath-cache-ttl +;realpath_cache_ttl = 120 + +; Enables or disables the circular reference collector. +; http://php.net/zend.enable-gc +zend.enable_gc = On + +; If enabled, scripts may be written in encodings that are incompatible with +; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such +; encodings. To use this feature, mbstring extension must be enabled. +; Default: Off +;zend.multibyte = Off + +; Allows to set the default encoding for the scripts. This value will be used +; unless "declare(encoding=...)" directive appears at the top of the script. +; Only affects if zend.multibyte is set. +; Default: "" +;zend.script_encoding = + +;;;;;;;;;;;;;;;;; +; Miscellaneous ; +;;;;;;;;;;;;;;;;; + +; Decides whether PHP may expose the fact that it is installed on the server +; (e.g. by adding its signature to the Web server header). It is no security +; threat in any way, but it makes it possible to determine whether you use PHP +; on your server or not. +; http://php.net/expose-php +expose_php = On + +;;;;;;;;;;;;;;;;;;; +; Resource Limits ; +;;;;;;;;;;;;;;;;;;; + +; Maximum execution time of each script, in seconds +; http://php.net/max-execution-time +; Note: This directive is hardcoded to 0 for the CLI SAPI +max_execution_time = 30 + +; Maximum amount of time each script may spend parsing request data. It's a good +; idea to limit this time on productions servers in order to eliminate unexpectedly +; long running scripts. +; Note: This directive is hardcoded to -1 for the CLI SAPI +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) +; http://php.net/max-input-time +max_input_time = 60 + +; Maximum input variable nesting level +; http://php.net/max-input-nesting-level +;max_input_nesting_level = 64 + +; How many GET/POST/COOKIE input variables may be accepted +; max_input_vars = 1000 + +; Maximum amount of memory a script may consume (128MB) +; http://php.net/memory-limit +memory_limit = 128M + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Error handling and logging ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; This directive informs PHP of which errors, warnings and notices you would like +; it to take action for. The recommended way of setting values for this +; directive is through the use of the error level constants and bitwise +; operators. The error level constants are below here for convenience as well as +; some common settings and their meanings. +; By default, PHP is set to take action on all errors, notices and warnings EXCEPT +; those related to E_NOTICE and E_STRICT, which together cover best practices and +; recommended coding standards in PHP. For performance reasons, this is the +; recommend error reporting setting. Your production server shouldn't be wasting +; resources complaining about best practices and coding standards. That's what +; development servers and development settings are for. +; Note: The php.ini-development file has this setting as E_ALL. This +; means it pretty much reports everything which is exactly what you want during +; development and early testing. +; +; Error Level Constants: +; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0) +; E_ERROR - fatal run-time errors +; E_RECOVERABLE_ERROR - almost fatal run-time errors +; E_WARNING - run-time warnings (non-fatal errors) +; E_PARSE - compile-time parse errors +; E_NOTICE - run-time notices (these are warnings which often result +; from a bug in your code, but it's possible that it was +; intentional (e.g., using an uninitialized variable and +; relying on the fact it is automatically initialized to an +; empty string) +; E_STRICT - run-time notices, enable to have PHP suggest changes +; to your code which will ensure the best interoperability +; and forward compatibility of your code +; E_CORE_ERROR - fatal errors that occur during PHP's initial startup +; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's +; initial startup +; E_COMPILE_ERROR - fatal compile-time errors +; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) +; E_USER_ERROR - user-generated error message +; E_USER_WARNING - user-generated warning message +; E_USER_NOTICE - user-generated notice message +; E_DEPRECATED - warn about code that will not work in future versions +; of PHP +; E_USER_DEPRECATED - user-generated deprecation warnings +; +; Common Values: +; E_ALL (Show all errors, warnings and notices including coding standards.) +; E_ALL & ~E_NOTICE (Show all errors, except for notices) +; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.) +; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT +; http://php.net/error-reporting +error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT + +; This directive controls whether or not and where PHP will output errors, +; notices and warnings too. Error output is very useful during development, but +; it could be very dangerous in production environments. Depending on the code +; which is triggering the error, sensitive information could potentially leak +; out of your application such as database usernames and passwords or worse. +; For production environments, we recommend logging errors rather than +; sending them to STDOUT. +; Possible Values: +; Off = Do not display any errors +; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) +; On or stdout = Display errors to STDOUT +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/display-errors +display_errors = Off + +; The display of errors which occur during PHP's startup sequence are handled +; separately from display_errors. PHP's default behavior is to suppress those +; errors from clients. Turning the display of startup errors on can be useful in +; debugging configuration problems. We strongly recommend you +; set this to 'off' for production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/display-startup-errors +display_startup_errors = Off + +; Besides displaying errors, PHP can also log errors to locations such as a +; server-specific log, STDERR, or a location specified by the error_log +; directive found below. While errors should not be displayed on productions +; servers they should still be monitored and logging is a great way to do that. +; Default Value: Off +; Development Value: On +; Production Value: On +; http://php.net/log-errors +log_errors = On + +; Set maximum length of log_errors. In error_log information about the source is +; added. The default is 1024 and 0 allows to not apply any maximum length at all. +; http://php.net/log-errors-max-len +log_errors_max_len = 1024 + +; Do not log repeated messages. Repeated errors must occur in same file on same +; line unless ignore_repeated_source is set true. +; http://php.net/ignore-repeated-errors +ignore_repeated_errors = Off + +; Ignore source of message when ignoring repeated messages. When this setting +; is On you will not log errors with repeated messages from different files or +; source lines. +; http://php.net/ignore-repeated-source +ignore_repeated_source = Off + +; If this parameter is set to Off, then memory leaks will not be shown (on +; stdout or in the log). This has only effect in a debug compile, and if +; error reporting includes E_WARNING in the allowed list +; http://php.net/report-memleaks +report_memleaks = On + +; This setting is on by default. +;report_zend_debug = 0 + +; Store the last error/warning message in $php_errormsg (boolean). Setting this value +; to On can assist in debugging and is appropriate for development servers. It should +; however be disabled on production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/track-errors +track_errors = Off + +; Turn off normal error reporting and emit XML-RPC error XML +; http://php.net/xmlrpc-errors +;xmlrpc_errors = 0 + +; An XML-RPC faultCode +;xmlrpc_error_number = 0 + +; When PHP displays or logs an error, it has the capability of formatting the +; error message as HTML for easier reading. This directive controls whether +; the error message is formatted as HTML or not. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: On +; Development Value: On +; Production value: On +; http://php.net/html-errors +html_errors = On + +; If html_errors is set to On *and* docref_root is not empty, then PHP +; produces clickable error messages that direct to a page describing the error +; or function causing the error in detail. +; You can download a copy of the PHP manual from http://php.net/docs +; and change docref_root to the base URL of your local copy including the +; leading '/'. You must also specify the file extension being used including +; the dot. PHP's default behavior is to leave these settings empty, in which +; case no links to documentation are generated. +; Note: Never use this feature for production boxes. +; http://php.net/docref-root +; Examples +;docref_root = "/phpmanual/" + +; http://php.net/docref-ext +;docref_ext = .html + +; String to output before an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-prepend-string +; Example: +;error_prepend_string = "" + +; String to output after an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-append-string +; Example: +;error_append_string = "" + +; Log errors to specified file. PHP's default behavior is to leave this value +; empty. +; http://php.net/error-log +; Example: +;error_log = php_errors.log +; Log errors to syslog (Event Log on Windows). +;error_log = syslog + +;windows.show_crt_warning +; Default value: 0 +; Development value: 0 +; Production value: 0 + +;;;;;;;;;;;;;;;;; +; Data Handling ; +;;;;;;;;;;;;;;;;; + +; The separator used in PHP generated URLs to separate arguments. +; PHP's default setting is "&". +; http://php.net/arg-separator.output +; Example: +;arg_separator.output = "&" + +; List of separator(s) used by PHP to parse input URLs into variables. +; PHP's default setting is "&". +; NOTE: Every character in this directive is considered as separator! +; http://php.net/arg-separator.input +; Example: +;arg_separator.input = ";&" + +; This directive determines which super global arrays are registered when PHP +; starts up. G,P,C,E & S are abbreviations for the following respective super +; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty +; paid for the registration of these arrays and because ENV is not as commonly +; used as the others, ENV is not recommended on productions servers. You +; can still get access to the environment variables through getenv() should you +; need to. +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS"; +; http://php.net/variables-order +variables_order = "GPCS" + +; This directive determines which super global data (G,P & C) should be +; registered into the super global array REQUEST. If so, it also determines +; the order in which that data is registered. The values for this directive +; are specified in the same manner as the variables_order directive, +; EXCEPT one. Leaving this value empty will cause PHP to use the value set +; in the variables_order directive. It does not mean it will leave the super +; globals array REQUEST empty. +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" +; http://php.net/request-order +request_order = "GP" + +; This directive determines whether PHP registers $argv & $argc each time it +; runs. $argv contains an array of all the arguments passed to PHP when a script +; is invoked. $argc contains an integer representing the number of arguments +; that were passed when the script was invoked. These arrays are extremely +; useful when running scripts from the command line. When this directive is +; enabled, registering these variables consumes CPU cycles and memory each time +; a script is executed. For performance reasons, this feature should be disabled +; on production servers. +; Note: This directive is hardcoded to On for the CLI SAPI +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-argc-argv +register_argc_argv = Off + +; When enabled, the ENV, REQUEST and SERVER variables are created when they're +; first used (Just In Time) instead of when the script starts. If these +; variables are not used within a script, having this directive on will result +; in a performance gain. The PHP directive register_argc_argv must be disabled +; for this directive to have any affect. +; http://php.net/auto-globals-jit +auto_globals_jit = On + +; Whether PHP will read the POST data. +; This option is enabled by default. +; Most likely, you won't want to disable this option globally. It causes $_POST +; and $_FILES to always be empty; the only way you will be able to read the +; POST data will be through the php://input stream wrapper. This can be useful +; to proxy requests or to process the POST data in a memory efficient fashion. +; http://php.net/enable-post-data-reading +;enable_post_data_reading = Off + +; Maximum size of POST data that PHP will accept. +; Its value may be 0 to disable the limit. It is ignored if POST data reading +; is disabled through enable_post_data_reading. +; http://php.net/post-max-size +post_max_size = 8M + +; Automatically add files before PHP document. +; http://php.net/auto-prepend-file +auto_prepend_file = + +; Automatically add files after PHP document. +; http://php.net/auto-append-file +auto_append_file = + +; By default, PHP will output a media type using the Content-Type header. To +; disable this, simply set it to be empty. +; +; PHP's built-in default media type is set to text/html. +; http://php.net/default-mimetype +default_mimetype = "text/html" + +; PHP's default character set is set to UTF-8. +; http://php.net/default-charset +default_charset = "UTF-8" + +; PHP internal character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/internal-encoding +;internal_encoding = + +; PHP input character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/input-encoding +;input_encoding = + +; PHP output character encoding is set to empty. +; If empty, default_charset is used. +; mbstring or iconv output handler is used. +; See also output_buffer. +; http://php.net/output-encoding +;output_encoding = + +;;;;;;;;;;;;;;;;;;;;;;;;; +; Paths and Directories ; +;;;;;;;;;;;;;;;;;;;;;;;;; + +; UNIX: "/path1:/path2" +;include_path = ".:/php/includes" +; +; Windows: "\path1;\path2" +;include_path = ".;c:\php\includes" +; +; PHP's default setting for include_path is ".;/path/to/php/pear" +; http://php.net/include-path + +; The root of the PHP pages, used only if nonempty. +; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root +; if you are running php as a CGI under any web server (other than IIS) +; see documentation for security issues. The alternate is to use the +; cgi.force_redirect configuration below +; http://php.net/doc-root +doc_root = + +; The directory under which PHP opens the script using /~username used only +; if nonempty. +; http://php.net/user-dir +user_dir = + +; Directory in which the loadable extensions (modules) reside. +; http://php.net/extension-dir +; extension_dir = "./" +; On windows: +; extension_dir = "ext" + +; Directory where the temporary files should be placed. +; Defaults to the system default (see sys_get_temp_dir) +; sys_temp_dir = "/tmp" + +; Whether or not to enable the dl() function. The dl() function does NOT work +; properly in multithreaded servers, such as IIS or Zeus, and is automatically +; disabled on them. +; http://php.net/enable-dl +enable_dl = Off + +; cgi.force_redirect is necessary to provide security running PHP as a CGI under +; most web servers. Left undefined, PHP turns this on by default. You can +; turn it off here AT YOUR OWN RISK +; **You CAN safely turn this off for IIS, in fact, you MUST.** +; http://php.net/cgi.force-redirect +;cgi.force_redirect = 1 + +; if cgi.nph is enabled it will force cgi to always sent Status: 200 with +; every request. PHP's default behavior is to disable this feature. +;cgi.nph = 1 + +; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape +; (iPlanet) web servers, you MAY need to set an environment variable name that PHP +; will look for to know it is OK to continue execution. Setting this variable MAY +; cause security issues, KNOW WHAT YOU ARE DOING FIRST. +; http://php.net/cgi.redirect-status-env +;cgi.redirect_status_env = + +; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +; http://php.net/cgi.fix-pathinfo +;cgi.fix_pathinfo=1 + +; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate +; security tokens of the calling client. This allows IIS to define the +; security context that the request runs under. mod_fastcgi under Apache +; does not currently support this feature (03/17/2002) +; Set to 1 if running under IIS. Default is zero. +; http://php.net/fastcgi.impersonate +;fastcgi.impersonate = 1 + +; Disable logging through FastCGI connection. PHP's default behavior is to enable +; this feature. +;fastcgi.logging = 0 + +; cgi.rfc2616_headers configuration option tells PHP what type of headers to +; use when sending HTTP response code. If set to 0, PHP sends Status: header that +; is supported by Apache. When this option is set to 1, PHP will send +; RFC2616 compliant header. +; Default is zero. +; http://php.net/cgi.rfc2616-headers +;cgi.rfc2616_headers = 0 + +;;;;;;;;;;;;;;;; +; File Uploads ; +;;;;;;;;;;;;;;;; + +; Whether to allow HTTP file uploads. +; http://php.net/file-uploads +file_uploads = On + +; Temporary directory for HTTP uploaded files (will use system default if not +; specified). +; http://php.net/upload-tmp-dir +;upload_tmp_dir = + +; Maximum allowed size for uploaded files. +; http://php.net/upload-max-filesize +upload_max_filesize = 2M + +; Maximum number of files that can be uploaded via a single request +max_file_uploads = 20 + +;;;;;;;;;;;;;;;;;; +; Fopen wrappers ; +;;;;;;;;;;;;;;;;;; + +; Whether to allow the treatment of URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-fopen +allow_url_fopen = On + +; Whether to allow include/require to open URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-include +allow_url_include = Off + +; Define the anonymous ftp password (your email address). PHP's default setting +; for this is empty. +; http://php.net/from +;from="john@doe.com" + +; Define the User-Agent string. PHP's default setting for this is empty. +; http://php.net/user-agent +;user_agent="PHP" + +; Default timeout for socket based streams (seconds) +; http://php.net/default-socket-timeout +default_socket_timeout = 60 + +; If your scripts have to deal with files from Macintosh systems, +; or you are running on a Mac and need to deal with files from +; unix or win32 systems, setting this flag will cause PHP to +; automatically detect the EOL character in those files so that +; fgets() and file() will work regardless of the source of the file. +; http://php.net/auto-detect-line-endings +;auto_detect_line_endings = Off + +;;;;;;;;;;;;;;;;;;;;;; +; Dynamic Extensions ; +;;;;;;;;;;;;;;;;;;;;;; + +; If you wish to have an extension loaded automatically, use the following +; syntax: +; +; extension=modulename.extension +; +; For example, on Windows: +; +; extension=msql.dll +; +; ... or under UNIX: +; +; extension=msql.so +; +; ... or with a path: +; +; extension=/path/to/extension/msql.so +; +; If you only provide the name of the extension, PHP will look for it in its +; default extension directory. +; +; Windows Extensions +; Note that ODBC support is built in, so no dll is needed for it. +; Note that many DLL files are located in the extensions/ (PHP 4) ext/ (PHP 5+) +; extension folders as well as the separate PECL DLL download (PHP 5+). +; Be sure to appropriately set the extension_dir directive. +; +;extension=php_bz2.dll +;extension=php_curl.dll +;extension=php_fileinfo.dll +;extension=php_ftp.dll +;extension=php_gd2.dll +;extension=php_gettext.dll +;extension=php_gmp.dll +;extension=php_intl.dll +;extension=php_imap.dll +;extension=php_interbase.dll +;extension=php_ldap.dll +;extension=php_mbstring.dll +;extension=php_exif.dll ; Must be after mbstring as it depends on it +;extension=php_mysqli.dll +;extension=php_oci8_12c.dll ; Use with Oracle Database 12c Instant Client +;extension=php_openssl.dll +;extension=php_pdo_firebird.dll +;extension=php_pdo_mysql.dll +;extension=php_pdo_oci.dll +;extension=php_pdo_odbc.dll +;extension=php_pdo_pgsql.dll +;extension=php_pdo_sqlite.dll +;extension=php_pgsql.dll +;extension=php_shmop.dll + +; The MIBS data available in the PHP distribution must be installed. +; See http://www.php.net/manual/en/snmp.installation.php +;extension=php_snmp.dll + +;extension=php_soap.dll +;extension=php_sockets.dll +;extension=php_sqlite3.dll +;extension=php_tidy.dll +;extension=php_xmlrpc.dll +;extension=php_xsl.dll + +;;;;;;;;;;;;;;;;;;; +; Module Settings ; +;;;;;;;;;;;;;;;;;;; + +[CLI Server] +; Whether the CLI web server uses ANSI color coding in its terminal output. +cli_server.color = On + +[Date] +; Defines the default timezone used by the date functions +; http://php.net/date.timezone +;date.timezone = + +; http://php.net/date.default-latitude +;date.default_latitude = 31.7667 + +; http://php.net/date.default-longitude +;date.default_longitude = 35.2333 + +; http://php.net/date.sunrise-zenith +;date.sunrise_zenith = 90.583333 + +; http://php.net/date.sunset-zenith +;date.sunset_zenith = 90.583333 + +[filter] +; http://php.net/filter.default +;filter.default = unsafe_raw + +; http://php.net/filter.default-flags +;filter.default_flags = + +[iconv] +; Use of this INI entry is deprecated, use global input_encoding instead. +; If empty, default_charset or input_encoding or iconv.input_encoding is used. +; The precedence is: default_charset < intput_encoding < iconv.input_encoding +;iconv.input_encoding = + +; Use of this INI entry is deprecated, use global internal_encoding instead. +; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. +; The precedence is: default_charset < internal_encoding < iconv.internal_encoding +;iconv.internal_encoding = + +; Use of this INI entry is deprecated, use global output_encoding instead. +; If empty, default_charset or output_encoding or iconv.output_encoding is used. +; The precedence is: default_charset < output_encoding < iconv.output_encoding +; To use an output encoding conversion, iconv's output handler must be set +; otherwise output encoding conversion cannot be performed. +;iconv.output_encoding = + +[intl] +;intl.default_locale = +; This directive allows you to produce PHP errors when some error +; happens within intl functions. The value is the level of the error produced. +; Default is 0, which does not produce any errors. +;intl.error_level = E_WARNING +;intl.use_exceptions = 0 + +[sqlite3] +;sqlite3.extension_dir = + +[Pcre] +;PCRE library backtracking limit. +; http://php.net/pcre.backtrack-limit +;pcre.backtrack_limit=100000 + +;PCRE library recursion limit. +;Please note that if you set this value to a high number you may consume all +;the available process stack and eventually crash PHP (due to reaching the +;stack size limit imposed by the Operating System). +; http://php.net/pcre.recursion-limit +;pcre.recursion_limit=100000 + +;Enables or disables JIT compilation of patterns. This requires the PCRE +;library to be compiled with JIT support. +;pcre.jit=1 + +[Pdo] +; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" +; http://php.net/pdo-odbc.connection-pooling +;pdo_odbc.connection_pooling=strict + +;pdo_odbc.db2_instance_name + +[Pdo_mysql] +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/pdo_mysql.cache_size +pdo_mysql.cache_size = 2000 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/pdo_mysql.default-socket +pdo_mysql.default_socket= + +[Phar] +; http://php.net/phar.readonly +;phar.readonly = On + +; http://php.net/phar.require-hash +;phar.require_hash = On + +;phar.cache_list = + +[mail function] +; For Win32 only. +; http://php.net/smtp +SMTP = localhost +; http://php.net/smtp-port +smtp_port = 25 + +; For Win32 only. +; http://php.net/sendmail-from +;sendmail_from = me@example.com + +; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). +; http://php.net/sendmail-path +;sendmail_path = + +; Force the addition of the specified parameters to be passed as extra parameters +; to the sendmail binary. These parameters will always replace the value of +; the 5th parameter to mail(). +;mail.force_extra_parameters = + +; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename +mail.add_x_header = On + +; The path to a log file that will log all mail() calls. Log entries include +; the full path of the script, line number, To address and headers. +;mail.log = +; Log mail to syslog (Event Log on Windows). +;mail.log = syslog + +[SQL] +; http://php.net/sql.safe-mode +sql.safe_mode = Off + +[ODBC] +; http://php.net/odbc.default-db +;odbc.default_db = Not yet implemented + +; http://php.net/odbc.default-user +;odbc.default_user = Not yet implemented + +; http://php.net/odbc.default-pw +;odbc.default_pw = Not yet implemented + +; Controls the ODBC cursor model. +; Default: SQL_CURSOR_STATIC (default). +;odbc.default_cursortype + +; Allow or prevent persistent links. +; http://php.net/odbc.allow-persistent +odbc.allow_persistent = On + +; Check that a connection is still valid before reuse. +; http://php.net/odbc.check-persistent +odbc.check_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/odbc.max-persistent +odbc.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/odbc.max-links +odbc.max_links = -1 + +; Handling of LONG fields. Returns number of bytes to variables. 0 means +; passthru. +; http://php.net/odbc.defaultlrl +odbc.defaultlrl = 4096 + +; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. +; See the documentation on odbc_binmode and odbc_longreadlen for an explanation +; of odbc.defaultlrl and odbc.defaultbinmode +; http://php.net/odbc.defaultbinmode +odbc.defaultbinmode = 1 + +;birdstep.max_links = -1 + +[Interbase] +; Allow or prevent persistent links. +ibase.allow_persistent = 1 + +; Maximum number of persistent links. -1 means no limit. +ibase.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +ibase.max_links = -1 + +; Default database name for ibase_connect(). +;ibase.default_db = + +; Default username for ibase_connect(). +;ibase.default_user = + +; Default password for ibase_connect(). +;ibase.default_password = + +; Default charset for ibase_connect(). +;ibase.default_charset = + +; Default timestamp format. +ibase.timestampformat = "%Y-%m-%d %H:%M:%S" + +; Default date format. +ibase.dateformat = "%Y-%m-%d" + +; Default time format. +ibase.timeformat = "%H:%M:%S" + +[MySQLi] + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysqli.max-persistent +mysqli.max_persistent = -1 + +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysqli.allow_local_infile +;mysqli.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysqli.allow-persistent +mysqli.allow_persistent = On + +; Maximum number of links. -1 means no limit. +; http://php.net/mysqli.max-links +mysqli.max_links = -1 + +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/mysqli.cache_size +mysqli.cache_size = 2000 + +; Default port number for mysqli_connect(). If unset, mysqli_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysqli.default-port +mysqli.default_port = 3306 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysqli.default-socket +mysqli.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-host +mysqli.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-user +mysqli.default_user = + +; Default password for mysqli_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysqli.default-pw +mysqli.default_pw = + +; Allow or prevent reconnect +mysqli.reconnect = Off + +[mysqlnd] +; Enable / Disable collection of general statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_statistics +mysqlnd.collect_statistics = On + +; Enable / Disable collection of memory usage statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_memory_statistics +mysqlnd.collect_memory_statistics = Off + +; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. +; http://php.net/mysqlnd.net_cmd_buffer_size +;mysqlnd.net_cmd_buffer_size = 2048 + +; Size of a pre-allocated buffer used for reading data sent by the server in +; bytes. +; http://php.net/mysqlnd.net_read_buffer_size +;mysqlnd.net_read_buffer_size = 32768 + +[OCI8] + +; Connection: Enables privileged connections using external +; credentials (OCI_SYSOPER, OCI_SYSDBA) +; http://php.net/oci8.privileged-connect +;oci8.privileged_connect = Off + +; Connection: The maximum number of persistent OCI8 connections per +; process. Using -1 means no limit. +; http://php.net/oci8.max-persistent +;oci8.max_persistent = -1 + +; Connection: The maximum number of seconds a process is allowed to +; maintain an idle persistent connection. Using -1 means idle +; persistent connections will be maintained forever. +; http://php.net/oci8.persistent-timeout +;oci8.persistent_timeout = -1 + +; Connection: The number of seconds that must pass before issuing a +; ping during oci_pconnect() to check the connection validity. When +; set to 0, each oci_pconnect() will cause a ping. Using -1 disables +; pings completely. +; http://php.net/oci8.ping-interval +;oci8.ping_interval = 60 + +; Connection: Set this to a user chosen connection class to be used +; for all pooled server requests with Oracle 11g Database Resident +; Connection Pooling (DRCP). To use DRCP, this value should be set to +; the same string for all web servers running the same application, +; the database pool must be configured, and the connection string must +; specify to use a pooled server. +;oci8.connection_class = + +; High Availability: Using On lets PHP receive Fast Application +; Notification (FAN) events generated when a database node fails. The +; database must also be configured to post FAN events. +;oci8.events = Off + +; Tuning: This option enables statement caching, and specifies how +; many statements to cache. Using 0 disables statement caching. +; http://php.net/oci8.statement-cache-size +;oci8.statement_cache_size = 20 + +; Tuning: Enables statement prefetching and sets the default number of +; rows that will be fetched automatically after statement execution. +; http://php.net/oci8.default-prefetch +;oci8.default_prefetch = 100 + +; Compatibility. Using On means oci_close() will not close +; oci_connect() and oci_new_connect() connections. +; http://php.net/oci8.old-oci-close-semantics +;oci8.old_oci_close_semantics = Off + +[PostgreSQL] +; Allow or prevent persistent links. +; http://php.net/pgsql.allow-persistent +pgsql.allow_persistent = On + +; Detect broken persistent links always with pg_pconnect(). +; Auto reset feature requires a little overheads. +; http://php.net/pgsql.auto-reset-persistent +pgsql.auto_reset_persistent = Off + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/pgsql.max-persistent +pgsql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +; http://php.net/pgsql.max-links +pgsql.max_links = -1 + +; Ignore PostgreSQL backends Notice message or not. +; Notice message logging require a little overheads. +; http://php.net/pgsql.ignore-notice +pgsql.ignore_notice = 0 + +; Log PostgreSQL backends Notice message or not. +; Unless pgsql.ignore_notice=0, module cannot log notice message. +; http://php.net/pgsql.log-notice +pgsql.log_notice = 0 + +[bcmath] +; Number of decimal digits for all bcmath functions. +; http://php.net/bcmath.scale +bcmath.scale = 0 + +[browscap] +; http://php.net/browscap +;browscap = extra/browscap.ini + +[Session] +; Handler used to store/retrieve data. +; http://php.net/session.save-handler +session.save_handler = files + +; Argument passed to save_handler. In the case of files, this is the path +; where data files are stored. Note: Windows users have to change this +; variable in order to use PHP's session functions. +; +; The path can be defined as: +; +; session.save_path = "N;/path" +; +; where N is an integer. Instead of storing all the session files in +; /path, what this will do is use subdirectories N-levels deep, and +; store the session data in those directories. This is useful if +; your OS has problems with many files in one directory, and is +; a more efficient layout for servers that handle many sessions. +; +; NOTE 1: PHP will not create this directory structure automatically. +; You can use the script in the ext/session dir for that purpose. +; NOTE 2: See the section on garbage collection below if you choose to +; use subdirectories for session storage +; +; The file storage module creates files using mode 600 by default. +; You can change that by using +; +; session.save_path = "N;MODE;/path" +; +; where MODE is the octal representation of the mode. Note that this +; does not overwrite the process's umask. +; http://php.net/session.save-path +;session.save_path = "/tmp" + +; Whether to use strict session mode. +; Strict session mode does not accept uninitialized session ID and regenerate +; session ID if browser sends uninitialized session ID. Strict mode protects +; applications from session fixation via session adoption vulnerability. It is +; disabled by default for maximum compatibility, but enabling it is encouraged. +; https://wiki.php.net/rfc/strict_sessions +session.use_strict_mode = 0 + +; Whether to use cookies. +; http://php.net/session.use-cookies +session.use_cookies = 1 + +; http://php.net/session.cookie-secure +;session.cookie_secure = + +; This option forces PHP to fetch and use a cookie for storing and maintaining +; the session id. We encourage this operation as it's very helpful in combating +; session hijacking when not specifying and managing your own session id. It is +; not the be-all and end-all of session hijacking defense, but it's a good start. +; http://php.net/session.use-only-cookies +session.use_only_cookies = 1 + +; Name of the session (used as cookie name). +; http://php.net/session.name +session.name = PHPSESSID + +; Initialize session on request startup. +; http://php.net/session.auto-start +session.auto_start = 0 + +; Lifetime in seconds of cookie or, if 0, until browser is restarted. +; http://php.net/session.cookie-lifetime +session.cookie_lifetime = 0 + +; The path for which the cookie is valid. +; http://php.net/session.cookie-path +session.cookie_path = / + +; The domain for which the cookie is valid. +; http://php.net/session.cookie-domain +session.cookie_domain = + +; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. +; http://php.net/session.cookie-httponly +session.cookie_httponly = + +; Handler used to serialize data. php is the standard serializer of PHP. +; http://php.net/session.serialize-handler +session.serialize_handler = php + +; Defines the probability that the 'garbage collection' process is started +; on every session initialization. The probability is calculated by using +; gc_probability/gc_divisor. Where session.gc_probability is the numerator +; and gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.gc-probability +session.gc_probability = 1 + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using the following equation: +; gc_probability/gc_divisor. Where session.gc_probability is the numerator and +; session.gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. Increasing this value to 1000 will give you +; a 0.1% chance the gc will run on any give request. For high volume production servers, +; this is a more efficient approach. +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 +; http://php.net/session.gc-divisor +session.gc_divisor = 1000 + +; After this number of seconds, stored data will be seen as 'garbage' and +; cleaned up by the garbage collection process. +; http://php.net/session.gc-maxlifetime +session.gc_maxlifetime = 1440 + +; NOTE: If you are using the subdirectory option for storing session files +; (see session.save_path above), then garbage collection does *not* +; happen automatically. You will need to do your own garbage +; collection through a shell script, cron entry, or some other method. +; For example, the following script would is the equivalent of +; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): +; find /path/to/sessions -cmin +24 -type f | xargs rm + +; Check HTTP Referer to invalidate externally stored URLs containing ids. +; HTTP_REFERER has to contain this substring for the session to be +; considered as valid. +; http://php.net/session.referer-check +session.referer_check = + +; How many bytes to read from the file. +; http://php.net/session.entropy-length +;session.entropy_length = 32 + +; Specified here to create the session id. +; http://php.net/session.entropy-file +; Defaults to /dev/urandom +; On systems that don't have /dev/urandom but do have /dev/arandom, this will default to /dev/arandom +; If neither are found at compile time, the default is no entropy file. +; On windows, setting the entropy_length setting will activate the +; Windows random source (using the CryptoAPI) +;session.entropy_file = /dev/urandom + +; Set to {nocache,private,public,} to determine HTTP caching aspects +; or leave this empty to avoid sending anti-caching headers. +; http://php.net/session.cache-limiter +session.cache_limiter = nocache + +; Document expires after n minutes. +; http://php.net/session.cache-expire +session.cache_expire = 180 + +; trans sid support is disabled by default. +; Use of trans sid may risk your users' security. +; Use this option with caution. +; - User may send URL contains active session ID +; to other person via. email/irc/etc. +; - URL that contains active session ID may be stored +; in publicly accessible computer. +; - User may access your site with the same session ID +; always using URL stored in browser's history or bookmarks. +; http://php.net/session.use-trans-sid +session.use_trans_sid = 0 + +; Select a hash function for use in generating session ids. +; Possible Values +; 0 (MD5 128 bits) +; 1 (SHA-1 160 bits) +; This option may also be set to the name of any hash function supported by +; the hash extension. A list of available hashes is returned by the hash_algos() +; function. +; http://php.net/session.hash-function +session.hash_function = 0 + +; Define how many bits are stored in each character when converting +; the binary hash data to something readable. +; Possible values: +; 4 (4 bits: 0-9, a-f) +; 5 (5 bits: 0-9, a-v) +; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 +; http://php.net/session.hash-bits-per-character +session.hash_bits_per_character = 5 + +; The URL rewriter will look for URLs in a defined set of HTML tags. +; form/fieldset are special; if you include them here, the rewriter will +; add a hidden field with the info which is otherwise appended +; to URLs. If you want XHTML conformity, remove the form entry. +; Note that all valid entries require a "=", even if no value follows. +; Default Value: "a=href,area=href,frame=src,form=,fieldset=" +; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; http://php.net/url-rewriter.tags +url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" + +; Enable upload progress tracking in $_SESSION +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.enabled +;session.upload_progress.enabled = On + +; Cleanup the progress information as soon as all POST data has been read +; (i.e. upload completed). +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.cleanup +;session.upload_progress.cleanup = On + +; A prefix used for the upload progress key in $_SESSION +; Default Value: "upload_progress_" +; Development Value: "upload_progress_" +; Production Value: "upload_progress_" +; http://php.net/session.upload-progress.prefix +;session.upload_progress.prefix = "upload_progress_" + +; The index name (concatenated with the prefix) in $_SESSION +; containing the upload progress information +; Default Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Development Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Production Value: "PHP_SESSION_UPLOAD_PROGRESS" +; http://php.net/session.upload-progress.name +;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" + +; How frequently the upload progress should be updated. +; Given either in percentages (per-file), or in bytes +; Default Value: "1%" +; Development Value: "1%" +; Production Value: "1%" +; http://php.net/session.upload-progress.freq +;session.upload_progress.freq = "1%" + +; The minimum delay between updates, in seconds +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.upload-progress.min-freq +;session.upload_progress.min_freq = "1" + +; Only write session data when session data is changed. Enabled by default. +; http://php.net/session.lazy-write +;session.lazy_write = On + +[Assertion] +; Switch whether to compile assertions at all (to have no overhead at run-time) +; -1: Do not compile at all +; 0: Jump over assertion at run-time +; 1: Execute assertions +; Changing from or to a negative value is only possible in php.ini! (For turning assertions on and off at run-time, see assert.active, when zend.assertions = 1) +; Default Value: 1 +; Development Value: 1 +; Production Value: -1 +; http://php.net/zend.assertions +zend.assertions = -1 + +; Assert(expr); active by default. +; http://php.net/assert.active +;assert.active = On + +; Throw an AssertationException on failed assertions +; http://php.net/assert.exception +;assert.exception = On + +; Issue a PHP warning for each failed assertion. (Overridden by assert.exception if active) +; http://php.net/assert.warning +;assert.warning = On + +; Don't bail out by default. +; http://php.net/assert.bail +;assert.bail = Off + +; User-function to be called if an assertion fails. +; http://php.net/assert.callback +;assert.callback = 0 + +; Eval the expression with current error_reporting(). Set to true if you want +; error_reporting(0) around the eval(). +; http://php.net/assert.quiet-eval +;assert.quiet_eval = 0 + +[COM] +; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs +; http://php.net/com.typelib-file +;com.typelib_file = + +; allow Distributed-COM calls +; http://php.net/com.allow-dcom +;com.allow_dcom = true + +; autoregister constants of a components typlib on com_load() +; http://php.net/com.autoregister-typelib +;com.autoregister_typelib = true + +; register constants casesensitive +; http://php.net/com.autoregister-casesensitive +;com.autoregister_casesensitive = false + +; show warnings on duplicate constant registrations +; http://php.net/com.autoregister-verbose +;com.autoregister_verbose = true + +; The default character set code-page to use when passing strings to and from COM objects. +; Default: system ANSI code page +;com.code_page= + +[mbstring] +; language for internal character representation. +; This affects mb_send_mail() and mbstring.detect_order. +; http://php.net/mbstring.language +;mbstring.language = Japanese + +; Use of this INI entry is deprecated, use global internal_encoding instead. +; internal/script encoding. +; Some encoding cannot work as internal encoding. (e.g. SJIS, BIG5, ISO-2022-*) +; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. +; The precedence is: default_charset < internal_encoding < iconv.internal_encoding +;mbstring.internal_encoding = + +; Use of this INI entry is deprecated, use global input_encoding instead. +; http input encoding. +; mbstring.encoding_traslation = On is needed to use this setting. +; If empty, default_charset or input_encoding or mbstring.input is used. +; The precedence is: default_charset < intput_encoding < mbsting.http_input +; http://php.net/mbstring.http-input +;mbstring.http_input = + +; Use of this INI entry is deprecated, use global output_encoding instead. +; http output encoding. +; mb_output_handler must be registered as output buffer to function. +; If empty, default_charset or output_encoding or mbstring.http_output is used. +; The precedence is: default_charset < output_encoding < mbstring.http_output +; To use an output encoding conversion, mbstring's output handler must be set +; otherwise output encoding conversion cannot be performed. +; http://php.net/mbstring.http-output +;mbstring.http_output = + +; enable automatic encoding translation according to +; mbstring.internal_encoding setting. Input chars are +; converted to internal encoding by setting this to On. +; Note: Do _not_ use automatic encoding translation for +; portable libs/applications. +; http://php.net/mbstring.encoding-translation +;mbstring.encoding_translation = Off + +; automatic encoding detection order. +; "auto" detect order is changed according to mbstring.language +; http://php.net/mbstring.detect-order +;mbstring.detect_order = auto + +; substitute_character used when character cannot be converted +; one from another +; http://php.net/mbstring.substitute-character +;mbstring.substitute_character = none + +; overload(replace) single byte functions by mbstring functions. +; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), +; etc. Possible values are 0,1,2,4 or combination of them. +; For example, 7 for overload everything. +; 0: No overload +; 1: Overload mail() function +; 2: Overload str*() functions +; 4: Overload ereg*() functions +; http://php.net/mbstring.func-overload +;mbstring.func_overload = 0 + +; enable strict encoding detection. +; Default: Off +;mbstring.strict_detection = On + +; This directive specifies the regex pattern of content types for which mb_output_handler() +; is activated. +; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) +;mbstring.http_output_conv_mimetype= + +[gd] +; Tell the jpeg decode to ignore warnings and try to create +; a gd image. The warning will then be displayed as notices +; disabled by default +; http://php.net/gd.jpeg-ignore-warning +;gd.jpeg_ignore_warning = 0 + +[exif] +; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. +; With mbstring support this will automatically be converted into the encoding +; given by corresponding encode setting. When empty mbstring.internal_encoding +; is used. For the decode settings you can distinguish between motorola and +; intel byte order. A decode setting cannot be empty. +; http://php.net/exif.encode-unicode +;exif.encode_unicode = ISO-8859-15 + +; http://php.net/exif.decode-unicode-motorola +;exif.decode_unicode_motorola = UCS-2BE + +; http://php.net/exif.decode-unicode-intel +;exif.decode_unicode_intel = UCS-2LE + +; http://php.net/exif.encode-jis +;exif.encode_jis = + +; http://php.net/exif.decode-jis-motorola +;exif.decode_jis_motorola = JIS + +; http://php.net/exif.decode-jis-intel +;exif.decode_jis_intel = JIS + +[Tidy] +; The path to a default tidy configuration file to use when using tidy +; http://php.net/tidy.default-config +;tidy.default_config = /usr/local/lib/php/default.tcfg + +; Should tidy clean and repair output automatically? +; WARNING: Do not use this option if you are generating non-html content +; such as dynamic images +; http://php.net/tidy.clean-output +tidy.clean_output = Off + +[soap] +; Enables or disables WSDL caching feature. +; http://php.net/soap.wsdl-cache-enabled +soap.wsdl_cache_enabled=1 + +; Sets the directory name where SOAP extension will put cache files. +; http://php.net/soap.wsdl-cache-dir +soap.wsdl_cache_dir="/tmp" + +; (time to live) Sets the number of second while cached file will be used +; instead of original one. +; http://php.net/soap.wsdl-cache-ttl +soap.wsdl_cache_ttl=86400 + +; Sets the size of the cache limit. (Max. number of WSDL files to cache) +soap.wsdl_cache_limit = 5 + +[sysvshm] +; A default size of the shared memory segment +;sysvshm.init_mem = 10000 + +[ldap] +; Sets the maximum number of open links or -1 for unlimited. +ldap.max_links = -1 + +[mcrypt] +; For more information about mcrypt settings see http://php.net/mcrypt-module-open + +; Directory where to load mcrypt algorithms +; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) +;mcrypt.algorithms_dir= + +; Directory where to load mcrypt modes +; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) +;mcrypt.modes_dir= + +[dba] +;dba.default_handler= + +[opcache] +; Determines if Zend OPCache is enabled +;opcache.enable=0 + +; Determines if Zend OPCache is enabled for the CLI version of PHP +;opcache.enable_cli=0 + +; The OPcache shared memory storage size. +;opcache.memory_consumption=64 + +; The amount of memory for interned strings in Mbytes. +;opcache.interned_strings_buffer=4 + +; The maximum number of keys (scripts) in the OPcache hash table. +; Only numbers between 200 and 100000 are allowed. +;opcache.max_accelerated_files=2000 + +; The maximum percentage of "wasted" memory until a restart is scheduled. +;opcache.max_wasted_percentage=5 + +; When this directive is enabled, the OPcache appends the current working +; directory to the script key, thus eliminating possible collisions between +; files with the same name (basename). Disabling the directive improves +; performance, but may break existing applications. +;opcache.use_cwd=1 + +; When disabled, you must reset the OPcache manually or restart the +; webserver for changes to the filesystem to take effect. +;opcache.validate_timestamps=1 + +; How often (in seconds) to check file timestamps for changes to the shared +; memory storage allocation. ("1" means validate once per second, but only +; once per request. "0" means always validate) +;opcache.revalidate_freq=2 + +; Enables or disables file search in include_path optimization +;opcache.revalidate_path=0 + +; If disabled, all PHPDoc comments are dropped from the code to reduce the +; size of the optimized code. +;opcache.save_comments=1 + +; If enabled, a fast shutdown sequence is used for the accelerated code +;opcache.fast_shutdown=0 + +; Allow file existence override (file_exists, etc.) performance feature. +;opcache.enable_file_override=0 + +; A bitmask, where each bit enables or disables the appropriate OPcache +; passes +;opcache.optimization_level=0xffffffff + +;opcache.inherited_hack=1 +;opcache.dups_fix=0 + +; The location of the OPcache blacklist file (wildcards allowed). +; Each OPcache blacklist file is a text file that holds the names of files +; that should not be accelerated. The file format is to add each filename +; to a new line. The filename may be a full path or just a file prefix +; (i.e., /var/www/x blacklists all the files and directories in /var/www +; that start with 'x'). Line starting with a ; are ignored (comments). +;opcache.blacklist_filename= + +; Allows exclusion of large files from being cached. By default all files +; are cached. +;opcache.max_file_size=0 + +; Check the cache checksum each N requests. +; The default value of "0" means that the checks are disabled. +;opcache.consistency_checks=0 + +; How long to wait (in seconds) for a scheduled restart to begin if the cache +; is not being accessed. +;opcache.force_restart_timeout=180 + +; OPcache error_log file name. Empty string assumes "stderr". +;opcache.error_log= + +; All OPcache errors go to the Web server log. +; By default, only fatal errors (level 0) or errors (level 1) are logged. +; You can also enable warnings (level 2), info messages (level 3) or +; debug messages (level 4). +;opcache.log_verbosity_level=1 + +; Preferred Shared Memory back-end. Leave empty and let the system decide. +;opcache.preferred_memory_model= + +; Protect the shared memory from unexpected writing during script execution. +; Useful for internal debugging only. +;opcache.protect_memory=0 + +; Allows calling OPcache API functions only from PHP scripts which path is +; started from specified string. The default "" means no restriction +;opcache.restrict_api= + +; Mapping base of shared memory segments (for Windows only). All the PHP +; processes have to map shared memory into the same address space. This +; directive allows to manually fix the "Unable to reattach to base address" +; errors. +;opcache.mmap_base= + +; Enables and sets the second level cache directory. +; It should improve performance when SHM memory is full, at server restart or +; SHM reset. The default "" disables file based caching. +;opcache.file_cache= + +; Enables or disables opcode caching in shared memory. +;opcache.file_cache_only=0 + +; Enables or disables checksum validation when script loaded from file cache. +;opcache.file_cache_consistency_checks=1 + +; Enables or disables copying of PHP code (text segment) into HUGE PAGES. +; This should improve performance, but requires appropriate OS configuration. +;opcache.huge_code_pages=1 + +[curl] +; A default value for the CURLOPT_CAINFO option. This is required to be an +; absolute path. +;curl.cainfo = + +[openssl] +; The location of a Certificate Authority (CA) file on the local filesystem +; to use when verifying the identity of SSL/TLS peers. Most users should +; not specify a value for this directive as PHP will attempt to use the +; OS-managed cert stores in its absence. If specified, this value may still +; be overridden on a per-stream basis via the "cafile" SSL stream context +; option. +;openssl.cafile= + +; If openssl.cafile is not specified or if the CA file is not found, the +; directory pointed to by openssl.capath is searched for a suitable +; certificate. This value must be a correctly hashed certificate directory. +; Most users should not specify a value for this directive as PHP will +; attempt to use the OS-managed cert stores in its absence. If specified, +; this value may still be overridden on a per-stream basis via the "capath" +; SSL stream context option. +;openssl.capath= + +; Local Variables: +; tab-width: 4 +; End: diff --git a/bin/php/php7apache2_4.dll b/bin/php/php7apache2_4.dll new file mode 100644 index 0000000..d902870 Binary files /dev/null and b/bin/php/php7apache2_4.dll differ diff --git a/bin/php/php7embed.lib b/bin/php/php7embed.lib new file mode 100644 index 0000000..e273a84 Binary files /dev/null and b/bin/php/php7embed.lib differ diff --git a/bin/php/php7phpdbg.dll b/bin/php/php7phpdbg.dll new file mode 100644 index 0000000..c4937e8 Binary files /dev/null and b/bin/php/php7phpdbg.dll differ diff --git a/bin/php/php7ts.dll b/bin/php/php7ts.dll new file mode 100644 index 0000000..710c354 Binary files /dev/null and b/bin/php/php7ts.dll differ diff --git a/bin/php/phpdbg.exe b/bin/php/phpdbg.exe new file mode 100644 index 0000000..221c0e7 Binary files /dev/null and b/bin/php/phpdbg.exe differ diff --git a/bin/php/pthreadVC2.dll b/bin/php/pthreadVC2.dll new file mode 100644 index 0000000..900da8a Binary files /dev/null and b/bin/php/pthreadVC2.dll differ diff --git a/bin/php/readme-redist-bins.txt b/bin/php/readme-redist-bins.txt new file mode 100644 index 0000000..9779827 --- /dev/null +++ b/bin/php/readme-redist-bins.txt @@ -0,0 +1,417 @@ +1. libmagic (ext/fileinfo) see ext/fileinfo/libmagic/LICENSE +2. Oniguruma (ext/mbstring) see ext/mbstring/oniguruma/COPYING +3. libmbfl (ext/mbstring) see ext/mbstring/libmbfl/LICENSE +4. pcrelib (ext/pcre) see ext/pcre/pcrelib/LICENCE +5. ext/standard crypt +6. ext/standard crypt's blowfish implementation +7. Sqlite/Sqlite3 ext/sqlite3 ext/sqlite +8. ext/standard/rand +9. ext/standard/scanf +10. ext/standard/strnatcmp.c +11. ext/standard/uuencode +12. libxmlrpc ext/xmlrpc +13. libzip ext/zip +14. main/snprintf.c +15. main/strlcat +16. main/strlcpy +17. libgd see ext/gd/libgd/COPYING + +5. ext/standard crypt + +FreeSec: libcrypt for NetBSD + +Copyright (c) 1994 David Burren +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the author nor the names of other contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + +6. ext/standard crypt's blowfish implementation + +The crypt_blowfish homepage is: + +http://www.openwall.com/crypt/ + +This code comes from John the Ripper password cracker, with reentrant +and crypt(3) interfaces added, but optimizations specific to password +cracking removed. + +Written by Solar Designer in 1998-2011. +No copyright is claimed, and the software is hereby placed in the public +domain. In case this attempt to disclaim copyright and place the software +in the public domain is deemed null and void, then the software is +Copyright (c) 1998-2011 Solar Designer and it is hereby released to the +general public under the following terms: + +Redistribution and use in source and binary forms, with or without +modification, are permitted. + +There's ABSOLUTELY NO WARRANTY, express or implied. + +It is my intent that you should be able to use this on your system, +as part of a software package, or anywhere else to improve security, +ensure compatibility, or for any other purpose. I would appreciate +it if you give credit where it is due and keep your modifications in +the public domain as well, but I don't require that in order to let +you place this code and any modifications you make under a license +of your choice. + +This implementation is mostly compatible with OpenBSD's bcrypt.c (prefix +"$2a$") by Niels Provos , and uses some of his +ideas. The password hashing algorithm was designed by David Mazieres +. For more information on the level of compatibility, +please refer to the comments in BF_set_key() and to the crypt(3) man page +included in the crypt_blowfish tarball. + +There's a paper on the algorithm that explains its design decisions: + +http://www.usenix.org/events/usenix99/provos.html + +Some of the tricks in BF_ROUND might be inspired by Eric Young's +Blowfish library (I can't be sure if I would think of something if I +hadn't seen his code). + + +7. Sqlite/Sqlite3 ext/sqlite3 ext/sqlite + +The author disclaims copyright to this source code. In place of +a legal notice, here is a blessing: + May you do good and not evil. + May you find forgiveness for yourself and forgive others. + May you share freely, never taking more than you give. + + +8. ext/standard/rand +The following php_mt_...() functions are based on a C++ class MTRand by +Richard J. Wagner. For more information see the web page at +http://www-personal.engin.umich.edu/~wagnerr/MersenneTwister.html + +Mersenne Twister random number generator -- a C++ class MTRand +Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus +Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com + +The Mersenne Twister is an algorithm for generating random numbers. It +was designed with consideration of the flaws in various other generators. +The period, 2^19937-1, and the order of equidistribution, 623 dimensions, +are far greater. The generator is also fast; it avoids multiplication and +division, and it benefits from caches and pipelines. For more information +see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html + +Reference +M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally +Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on +Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30. + +Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, +Copyright (C) 2000 - 2003, Richard J. Wagner +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +9. ext/standard/scanf +scanf.c -- + +This file contains the base code which implements sscanf and by extension +fscanf. Original code is from TCL8.3.0 and bears the following copyright: + +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., Scriptics Corporation, +and other parties. The following terms apply to all files associated +with the software unless explicitly disclaimed in individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. + +10. ext/standard/strnatcmp.c + +strnatcmp.c -- Perform 'natural order' comparisons of strings in C. +Copyright (C) 2000 by Martin Pool + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +11. ext/standard/uuencode +Portions of this code are based on Berkeley's uuencode/uudecode +implementation. + +Copyright (c) 1983, 1993 +The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: +This product includes software developed by the University of +California, Berkeley and its contributors. +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + +12. libxmlrpc ext/xmlrpc + +Copyright 2000 Epinions, Inc. + +Subject to the following 3 conditions, Epinions, Inc. permits you, free +of charge, to (a) use, copy, distribute, modify, perform and display this +software and associated documentation files (the "Software"), and (b) +permit others to whom the Software is furnished to do so as well. + +1) The above copyright notice and this permission notice shall be included +without modification in all copies or substantial portions of the +Software. + +2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF +ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY +IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE OR NONINFRINGEMENT. + +3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, +SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT +OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING +NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH +DAMAGES. + +13. libzip ext/zip +zip.h -- exported declarations. +Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner + +This file is part of libzip, a library to manipulate ZIP archives. +The authors can be contacted at + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. +3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +14. main/snprintf.c +Copyright (c) 2002, 2006 Todd C. Miller + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Sponsored in part by the Defense Advanced Research Projects +Agency (DARPA) and Air Force Research Laboratory, Air Force +Materiel Command, USAF, under agreement number F39502-99-1-0512. + +main/spprintf +Copyright (c) 1995-1998 The Apache Group. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + "This product includes software developed by the Apache Group + for use in the Apache HTTP server project (http://www.apache.org/)." + +4. The names "Apache Server" and "Apache Group" must not be used to + endorse or promote products derived from this software without + prior written permission. + +5. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes software developed by the Apache Group + for use in the Apache HTTP server project (http://www.apache.org/)." + +THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY +EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR +ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. +==================================================================== + +This software consists of voluntary contributions made by many +individuals on behalf of the Apache Group and was originally based +on public domain software written at the National Center for +Supercomputing Applications, University of Illinois, Urbana-Champaign. +For more information on the Apache Group and the Apache HTTP server +project, please see . + +This code is based on, and used with the permission of, the +SIO stdio-replacement strx_* functions by Panos Tsirigotis + for xinetd. + +15. main/strlcat +16. main/strlcpy +Copyright (c) 1998 Todd C. Miller +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/bin/php/sasl2/saslANONYMOUS.dll b/bin/php/sasl2/saslANONYMOUS.dll new file mode 100644 index 0000000..c89d6cd Binary files /dev/null and b/bin/php/sasl2/saslANONYMOUS.dll differ diff --git a/bin/php/sasl2/saslCRAMMD5.dll b/bin/php/sasl2/saslCRAMMD5.dll new file mode 100644 index 0000000..3b3d97a Binary files /dev/null and b/bin/php/sasl2/saslCRAMMD5.dll differ diff --git a/bin/php/sasl2/saslDIGESTMD5.dll b/bin/php/sasl2/saslDIGESTMD5.dll new file mode 100644 index 0000000..f0a7859 Binary files /dev/null and b/bin/php/sasl2/saslDIGESTMD5.dll differ diff --git a/bin/php/sasl2/saslLOGIN.dll b/bin/php/sasl2/saslLOGIN.dll new file mode 100644 index 0000000..4264ef4 Binary files /dev/null and b/bin/php/sasl2/saslLOGIN.dll differ diff --git a/bin/php/sasl2/saslNTLM.dll b/bin/php/sasl2/saslNTLM.dll new file mode 100644 index 0000000..bf33d55 Binary files /dev/null and b/bin/php/sasl2/saslNTLM.dll differ diff --git a/bin/php/sasl2/saslOTP.dll b/bin/php/sasl2/saslOTP.dll new file mode 100644 index 0000000..3a7534e Binary files /dev/null and b/bin/php/sasl2/saslOTP.dll differ diff --git a/bin/php/sasl2/saslPLAIN.dll b/bin/php/sasl2/saslPLAIN.dll new file mode 100644 index 0000000..633b3b9 Binary files /dev/null and b/bin/php/sasl2/saslPLAIN.dll differ diff --git a/bin/php/sasl2/saslSCRAM.dll b/bin/php/sasl2/saslSCRAM.dll new file mode 100644 index 0000000..a3fd131 Binary files /dev/null and b/bin/php/sasl2/saslSCRAM.dll differ diff --git a/bin/php/sasl2/saslSQLITE.dll b/bin/php/sasl2/saslSQLITE.dll new file mode 100644 index 0000000..cf3ee60 Binary files /dev/null and b/bin/php/sasl2/saslSQLITE.dll differ diff --git a/bin/php/sasl2/saslSRP.dll b/bin/php/sasl2/saslSRP.dll new file mode 100644 index 0000000..fbd51b1 Binary files /dev/null and b/bin/php/sasl2/saslSRP.dll differ diff --git a/bin/php/snapshot.txt b/bin/php/snapshot.txt new file mode 100644 index 0000000..36e01a6 --- /dev/null +++ b/bin/php/snapshot.txt @@ -0,0 +1,485 @@ +This snapshot was automatically generated on +Wed, 20 Jul 2016 18:44:53 +0000 + +Version: 7.0.9 +Branch: HEAD +Build: C:\php-sdk\php70dev\vc14\x86\obj\Release_TS + +Built-in Extensions +=========================== +Core +bcmath +calendar +ctype +date +filter +hash +iconv +json +mcrypt +SPL +pcre +Reflection +session +standard +mysqlnd +tokenizer +zip +zlib +libxml +dom +PDO +Phar +SimpleXML +xml +wddx +xmlreader +xmlwriter + + +Dependency information: +Module: php7apache2_4.dll +=========================== + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php-cgi.exe +=========================== + vcruntime140.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + api-ms-win-crt-locale-l1-1-0.dll + +Module: php.exe +=========================== + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + api-ms-win-crt-locale-l1-1-0.dll + +Module: php-win.exe +=========================== + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + api-ms-win-crt-locale-l1-1-0.dll + +Module: phpdbg.exe +=========================== + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-locale-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + +Module: php7phpdbg.dll +=========================== + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-locale-l1-1-0.dll + +Module: php_phpdbg_webhelper.dll +=========================== + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_bz2.dll +=========================== + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_com_dotnet.dll +=========================== + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_curl.dll +=========================== + libeay32.dll + libssh2.dll + ssleay32.dll + normaliz.dll + vcruntime140.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_enchant.dll +=========================== + libenchant.dll + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_fileinfo.dll +=========================== + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-locale-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_ftp.dll +=========================== + ssleay32.dll + libeay32.dll + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + +Module: php_gd2.dll +=========================== + vcruntime140.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_gettext.dll +=========================== + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + +Module: php_gmp.dll +=========================== + vcruntime140.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_imap.dll +=========================== + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-conio-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_interbase.dll +=========================== + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_intl.dll +=========================== + icuuc57.dll + icuin57.dll + icuio57.dll + msvcp140.dll + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-locale-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + +Module: php_ldap.dll +=========================== + libsasl.dll + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + ssleay32.dll + libeay32.dll + +Module: php_mbstring.dll +=========================== + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_oci8_12c.dll +=========================== + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + +Module: php_odbc.dll +=========================== + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + +Module: php_opcache.dll +=========================== + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + +Module: php_openssl.dll +=========================== + ssleay32.dll + libeay32.dll + vcruntime140.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_pgsql.dll +=========================== + libpq.dll + vcruntime140.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_shmop.dll +=========================== + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_snmp.dll +=========================== + libeay32.dll + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + api-ms-win-crt-locale-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + +Module: php_sockets.dll +=========================== + iphlpapi.dll + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_sqlite3.dll +=========================== + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_sysvshm.dll +=========================== + vcruntime140.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + +Module: php_tidy.dll +=========================== + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-environment-l1-1-0.dll + +Module: php_exif.dll +=========================== + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_mysqli.dll +=========================== + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_pdo_firebird.dll +=========================== + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_pdo_mysql.dll +=========================== + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + +Module: php_pdo_oci.dll +=========================== + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_pdo_odbc.dll +=========================== + vcruntime140.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + +Module: php_pdo_pgsql.dll +=========================== + libpq.dll + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + +Module: php_pdo_sqlite.dll +=========================== + vcruntime140.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_soap.dll +=========================== + vcruntime140.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + +Module: php_xmlrpc.dll +=========================== + vcruntime140.dll + api-ms-win-crt-convert-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-string-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + +Module: php_xsl.dll +=========================== + vcruntime140.dll + api-ms-win-crt-stdio-l1-1-0.dll + api-ms-win-crt-heap-l1-1-0.dll + api-ms-win-crt-filesystem-l1-1-0.dll + api-ms-win-crt-math-l1-1-0.dll + api-ms-win-crt-utility-l1-1-0.dll + api-ms-win-crt-time-l1-1-0.dll + api-ms-win-crt-runtime-l1-1-0.dll + diff --git a/bin/php/ssleay32.dll b/bin/php/ssleay32.dll new file mode 100644 index 0000000..d924808 Binary files /dev/null and b/bin/php/ssleay32.dll differ diff --git a/bin/php/yaml.dll b/bin/php/yaml.dll new file mode 100644 index 0000000..dc67e64 Binary files /dev/null and b/bin/php/yaml.dll differ diff --git a/devmine.yml b/devmine.yml new file mode 100644 index 0000000..0bb11f8 --- /dev/null +++ b/devmine.yml @@ -0,0 +1,183 @@ +# Main configuration file for DevMine-MP +# These settings are the ones that cannot be included in server.properties +# Some of these settings are safe, others can break your server if modified incorrectly +# New settings/defaults won't appear automatically on this file when upgrading. + +settings: + #Three-letter language code for server-side localization + #Check your language code on https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes + language: "eng" + #Whether to send all strings translated to server locale or let the device handle them + force-language: false + #When server shut down, the players will get kicked and this is what will show on there screen. + shutdown-message: "Server closed" + #Allow listing plugins via Query + query-plugins: true + #Show a console message when a plugin uses deprecated API methods + deprecated-verbose: true + #Enable plugin and core profiling by default + enable-profiling: false + #Will only add results when tick measurement is below or equal to given value (default 20) + profile-report-trigger: 20 + #Number of AsyncTask workers. + #Used for plugin asynchronous tasks, world generation, compression and web communication. + #Set this approximately to your number of cores. + #If set to auto, it'll try to detect the number of cores (or use 2) + async-workers: 4 + #Enables use of non-production, development builds. WARNING: DO NOT enable this unless you are sure you know what you are doing. + enable-testing: false + +memory: + #Global soft memory limit in megabytes. Set to 0 to disable + #This will trigger low-memory-triggers and fire an event to free memory when the usage goes over this + global-limit: 0 + + #Main thread soft memory limit in megabytes. Set to 0 to disable + #This will trigger low-memory-triggers and fire an event to free memory when the usage goes over this + main-limit: 0 + + #Main thread hard memory limit in megabytes. Set to 0 to disable + #This will stop the server when the limit is surpassed + main-hard-limit: 1024 + + #Period in ticks to check memory (default 1 second) + check-rate: 20 + + #Continue firing low-memory-triggers and event while on low memory + continuous-trigger: true + + #Only if memory.continuous-trigger is enabled. Specifies the rate in memory.check-rate steps (default 30 seconds) + continuous-trigger-rate: 30 + + garbage-collection: + #Period in ticks to fire the garbage collector manually (default 30 minutes), set to 0 to disable + #This only affect the main thread. Other threads should fire their own collections + period: 36000 + + #Fire asynchronous tasks to collect garbage from workers + collect-async-worker: true + + #Trigger on low memory + low-memory-trigger: true + + max-chunks: + #Limit of chunks to load per player, overrides chunk-sending.max-chunks + trigger-limit: 28 + + #Do chunk garbage collection on trigger + trigger-chunk-collect: true + + #Trigger on low memory + low-memory-trigger: true + + world-caches: + disable-chunk-cache: true + low-memory-trigger: true + + +network: + #Threshold for batching packets, in bytes. Only these packets will be compressed + #Set to 0 to compress everything, -1 to disable. + batch-threshold: 256 + #Compression level used when sending batched packets. Higher = Uses More CPU, Less = More Bandwidth Usage + compression-level: 2 + #Use AsyncTasks for compression. Adds half/one tick delay, less CPU load on main thread + async-compression: true + #Experimental, only for Windows. Tries to use UPnP to automatically port forward + upnp-forwarding: false + +debug: + #If > 1, it will show debug messages in the console + level: 2 + #Enables /status, /gc + commands: true + +player: + #Choose whether to enable player data saving. + save-player-data: true + +level-settings: + #The default format that levels will use when created + default-format: anvil + #If true, converts from a format that is not the default to the default format on load + #NOTE: This is currently not implemented + convert-format: false + #Automatically change levels tick rate to maintain 20 ticks per second + auto-tick-rate: false + auto-tick-rate-limit: 20 + #Sets the base tick rate (1 = 20 ticks per second, 2 = 10 ticks per second, etc.) + base-tick-rate: 1 + #Tick all players each tick even when other settings disallow this. + always-tick-players: false + +chunk-sending: + #Amount of chunks sent to players per tick + per-tick: 1 + #Amount of chunks sent around each player + max-chunks: 32 + #Amount of chunks that need to be sent before spawning the player + spawn-threshold: 28 + #Save a serialized copy of the chunk in memory for faster sending + #Useful in mostly-static worlds where lots of players join at the same time + cache-chunks: true + +chunk-ticking: + #Max amount of chunks processed each tick + per-tick: 16 + #Radius of chunks around a player to tick + tick-radius: 3 + light-updates: false + clear-tick-list: true + +chunk-generation: + #Max. amount of chunks in the waiting queue to be generated + queue-size: 2 + #Max. amount of chunks in the waiting queue to be populated + population-queue-size: 2 + +ticks-per: + animal-spawns: 400 + monster-spawns: 1 + autosave: 6000 + cache-cleanup: 900 +spawn-limits: + monsters: 70 + animals: 15 + water-animals: 5 + ambient: 15 + +auto-report: + #Send crash reports for processing + enabled: false + send-code: true + send-settings: true + send-phpinfo: false + host: crash.pocketmine.net + +anonymous-statistics: + #Sends anonymous statistics for data aggregation, plugin usage tracking + enabled: true + host: stats.pocketmine.net + +commands: + #Here you can customize server commands + #Specify command names to override the default set here. + #If no custom value is defined for a command, the default will be used. + #NOTE: Some commands cannot be disabled here, such as the important ones like /stop, /reload, etc. + default: true + #Set override values per command here + #For example, uncommenting the below will disable /plugins and /version + #version: false + #plugins: false + +aliases: + #Examples: + #showtheversion: version + #savestop: [save-all, stop] + +worlds: + #These settings will override the generator set in server.properties and allows loading multiple levels + #Example: + #world: + # seed: 404 + # generator: FLAT:2;7,59x1,3x3,2;1;decoration(treecount=80 grasscount=45) diff --git a/extended.yml b/extended.yml new file mode 100644 index 0000000..9577d1c --- /dev/null +++ b/extended.yml @@ -0,0 +1,105 @@ +#The advanced config for DevMine + +#Version of this file +config: + version: 27 + +level: + #This settting decides if weather is enabled in game (rain may cause lag to older devices) + weather: true + #This setting controls a random timer for weather durations (requires weather: true) + #The ranges that are set must follow the min-max range (min less than max (min < max)) + weather-random-duration-min: 6000 + weather-random-duration-max: 12000 + #This setting controls the interval of lightning strikes in game,default 200 as 10s, 0 = disable + lightning-time: 200 + #This setting will decide if lightning strikes have fire after they strike + lightning-fire: false + #This setting will decide if fire should spread after it is set on burnable materials (leaves, trees, etc.) + fire-spread: false + #Choose if the nether is allowed/loaded into the game. The level of nether will generate automatically even if false + allow-nether: true + #The name of nether's level will be set here + level-name: "nether" + +player: + #This setting decides if hunger will be enabled in game + #If set to false, hunger wont drop + hunger: true + #This setting decides if experience will be enalbed + #If set to false, then exp bottles wont drop exp dots, and exp level wont go up + experience: true + #This setting decides if the inventory of a player will be kept after they die + keep-inventory: false + #This setting decides if the inventory of a player will be cleared upon them changing their gamemode + auto-clear-inventory : true + #This setting will decide if the experience of a player will be kept after they die + keep-experience: false + #Radius of chunks in worlds, possibly for rendering, if players crash by too much processing, set this below 10. disable=-1 + chunk-radius: -1 + +server: + #This setting decides if the server.log file will not be made/written. + #You can set to True since it can help with disk space on a hosted server through computer + #But it is suggested to turn it on if you have players online, so you can see what console sees basically + disable-log: false + #This setting decides if the async chunks request will be enabled upon server loading/rebooting + async-chunk-request: true + #This setting chooses how to remind players when someone joins the game + #0 = Message, 1 = Tip, 2 = Popup + player-msg-type: 0 + login-msg: "§3@player joined the game" + logout-msg: "§3@player left the game" + #This setting decides if limited creative is enabled in game + #If set to true true, then players cannot drop items from hotbar, cannot open chests, and so on + limited-creative: true + #This setting decides if block particles upon destroying a block will spawn (may cause lag to older devices) + destroy-block-particle: true + #This setting decides if splash potions will be allowed to be thrown + #If set to false, then they will not be visible when thrown (wont splash either) + allow-splash-potion: true + #THis setting decides if Advanced Command Selector is enabled (recommended it is set to default (false)) + advanced-command-selector: false + +enchantment: + #This setting decides if Anvils are allowed to be used in game + #If the below setting is false, then anvils will not show the anvil gui + enable-anvil: true + #This setting decides if Enchantment Tables are allowed to be used in game + #If the below setting is false, then enchanting tables will not show the enchant table gui + enable-enchanting-table: true + #This setting decides if bookshelves are counted as entities (may cause server lag) + #If this option is false, the server will use a random count (recommended and the values range from 0~15) + count-bookshelf: false + +dserver: + #This setting decides if the server counts all multi-servers combined (recommended set to false) + enable: false + #This setting decides if the server will automatically update the Query + query-auto-update: false + #This setting decides if the server Query ticks update + query-tick-update: true + #This setting displays the # of max players on MOTD. 0 = Default + motd-max-players: 0 + #This setting displays the # of max players on Query. 0 = Default + query-max-players: 0 + #This setting decides if the server shows the # of all players on MOTD + motd-all-players: false + #This setting shows the number of all players on Query + query-all-players: false + #This setting shows the number of online players on MOTD + motd-players: false + #This setting shows the number of online players on Query + query-players: false + #This setting decides the interval for query/motd updating. 20=1s + time: 40 + #This setting decides the # of times the server retries when the server fails to load. 0 = Disable, 3 = Default + retry-times: 3 + #This setting displays the server list,Separate by ';',e.g. 1.example.com:19132;2.example.com:19133 + server-list: "" + +inventory: + #Set this setting to true if you have problems with anvils. + #This will process inventory transactions in a vanilla fashion with no anti-cheats or verification. + #If enchants do not work on PE or Windows 10, please enable cheats. + allow-cheats: false diff --git a/server.log b/server.log new file mode 100644 index 0000000..e69de29 diff --git a/server.properties b/server.properties new file mode 100644 index 0000000..2f47fc8 --- /dev/null +++ b/server.properties @@ -0,0 +1,19 @@ +#Minecraft server properties +#(file modification datestamp) +allow-nether=true +level-name=world +enable-query=false +allow-flight=false +server-port=19133 +level-type=DEFAULT +enable-rcon=false +level-seed= +force-gamemode=false +white-list=false +pvp=true +difficulty=0 +gamemode=1 +max-players=20 +spawn-monsters=false +generate-structures=true +motd=A minecraft server diff --git a/src/devmine/CompatibleClassLoader.php b/src/devmine/CompatibleClassLoader.php new file mode 100644 index 0000000..749078e --- /dev/null +++ b/src/devmine/CompatibleClassLoader.php @@ -0,0 +1,9 @@ +getPluginDescription($file)) instanceof PluginDescription){ - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.plugin.load", [$description->getFullName()])); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.plugin.load", [$description->getFullName()])); $dataFolder = dirname($file) . DIRECTORY_SEPARATOR . $description->getName(); if(file_exists($dataFolder) and !is_dir($dataFolder)){ throw new \InvalidStateException("Projected dataFolder '" . $dataFolder . "' for " . $description->getName() . " exists and is not a directory"); @@ -101,7 +101,7 @@ private function initPlugin(PluginBase $plugin, PluginDescription $description, */ public function enablePlugin(Plugin $plugin){ if($plugin instanceof PluginBase and !$plugin->isEnabled()){ - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.plugin.enable", [$plugin->getDescription()->getFullName()])); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.plugin.enable", [$plugin->getDescription()->getFullName()])); $plugin->setEnabled(true); @@ -114,7 +114,7 @@ public function enablePlugin(Plugin $plugin){ */ public function disablePlugin(Plugin $plugin){ if($plugin instanceof PluginBase and $plugin->isEnabled()){ - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.plugin.disable", [$plugin->getDescription()->getFullName()])); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.plugin.disable", [$plugin->getDescription()->getFullName()])); $this->server->getPluginManager()->callEvent(new PluginDisableEvent($plugin)); diff --git a/src/devmine/pluginfeatures/Plugin.php b/src/devmine/consumer/plugin/Plugin.php similarity index 95% rename from src/devmine/pluginfeatures/Plugin.php rename to src/devmine/consumer/plugin/Plugin.php index 22bbe71..cf5b5c0 100644 --- a/src/devmine/pluginfeatures/Plugin.php +++ b/src/devmine/consumer/plugin/Plugin.php @@ -5,7 +5,7 @@ /** * Plugin related classes */ -namespace devmine\pluginfeatures; +namespace devmine\consumer\plugin; use devmine\server\commands\CommandExecutor; @@ -78,7 +78,7 @@ public function saveDefaultConfig(); public function reloadConfig(); /** - * @return \devmine\Server + * @return \devmine\server\server */ public function getServer(); diff --git a/src/devmine/pluginfeatures/PluginBase.php b/src/devmine/consumer/plugin/PluginBase.php similarity index 97% rename from src/devmine/pluginfeatures/PluginBase.php rename to src/devmine/consumer/plugin/PluginBase.php index 81f2d03..0ee6a41 100644 --- a/src/devmine/pluginfeatures/PluginBase.php +++ b/src/devmine/consumer/plugin/PluginBase.php @@ -2,12 +2,12 @@ -namespace devmine\pluginfeatures; +namespace devmine\consumer\plugin; use devmine\server\commands\Command; use devmine\server\commands\CommandSender; use devmine\server\commands\PluginIdentifiableCommand; -use devmine\Server; +use devmine\server\server; use devmine\utilities\main\Config; abstract class PluginBase implements Plugin{ @@ -15,7 +15,7 @@ abstract class PluginBase implements Plugin{ /** @var PluginLoader */ private $loader; - /** @var \devmine\Server */ + /** @var \devmine\server\server */ private $server; /** @var bool */ @@ -187,7 +187,6 @@ public function saveResource($filename, $replace = false){ $out = $this->dataFolder . $filename; if(!file_exists(dirname($out))){ mkdir(dirname($out), 0755, true); - mkdir($this->dataFolder, 0755, true); } if(file_exists($out) and $replace !== true){ diff --git a/src/devmine/pluginfeatures/PluginDescription.php b/src/devmine/consumer/plugin/PluginDescription.php similarity index 89% rename from src/devmine/pluginfeatures/PluginDescription.php rename to src/devmine/consumer/plugin/PluginDescription.php index bceca40..26a406a 100644 --- a/src/devmine/pluginfeatures/PluginDescription.php +++ b/src/devmine/consumer/plugin/PluginDescription.php @@ -2,9 +2,9 @@ -namespace devmine\pluginfeatures; +namespace devmine\consumer\plugin; -use devmine\server\permissions\Permission; +use devmine\server\perms\Permission; use devmine\utilities\main\PluginException; class PluginDescription{ @@ -22,8 +22,6 @@ class PluginDescription{ private $prefix = null; private $order = PluginLoadOrder::POSTWORLD; - private $geniapi; - /** * @var Permission[] */ @@ -50,14 +48,9 @@ private function loadMap(array $plugin){ $this->version = $plugin["version"]; $this->main = $plugin["main"]; $this->api = !is_array($plugin["api"]) ? [$plugin["api"]] : $plugin["api"]; - if(!isset($plugin["geniapi"])){ - $this->geniapi = ["1.0.0"]; - }else{ - $this->geniapi = !is_array($plugin["geniapi"]) ? [$plugin["geniapi"]] : $plugin["geniapi"]; - } - - if(stripos($this->main, "devmine\\") === 0){ - throw new PluginException("Invalid PluginDescription main, cannot start within the devmine namespace"); + + if(stripos($this->main, "DevMine\\") === 0){ + throw new PluginException("Invalid PluginDescription main, cannot start within the DevMine namespace"); } if(isset($plugin["commands"]) and is_array($plugin["commands"])){ @@ -120,12 +113,6 @@ public function getCompatibleApis(){ return $this->api; } - /** - * @return array - */ - public function getCompatibleGeniApis(){ - return $this->geniapi; - } /** * @return array diff --git a/src/devmine/pluginfeatures/PluginLoadOrder.php b/src/devmine/consumer/plugin/PluginLoadOrder.php similarity index 86% rename from src/devmine/pluginfeatures/PluginLoadOrder.php rename to src/devmine/consumer/plugin/PluginLoadOrder.php index f1ea74d..9c24895 100644 --- a/src/devmine/pluginfeatures/PluginLoadOrder.php +++ b/src/devmine/consumer/plugin/PluginLoadOrder.php @@ -2,7 +2,7 @@ -namespace devmine\pluginfeatures; +namespace devmine\consumer\plugin; abstract class PluginLoadOrder{ diff --git a/src/devmine/pluginfeatures/PluginLoader.php b/src/devmine/consumer/plugin/PluginLoader.php similarity index 89% rename from src/devmine/pluginfeatures/PluginLoader.php rename to src/devmine/consumer/plugin/PluginLoader.php index 308832f..f1144d0 100644 --- a/src/devmine/pluginfeatures/PluginLoader.php +++ b/src/devmine/consumer/plugin/PluginLoader.php @@ -2,11 +2,8 @@ -namespace devmine\pluginfeatures; +namespace devmine\consumer\plugin; -/** - * Handles different types of plugins - */ interface PluginLoader{ /** @@ -49,4 +46,4 @@ public function enablePlugin(Plugin $plugin); public function disablePlugin(Plugin $plugin); -} \ No newline at end of file +} diff --git a/src/devmine/pluginfeatures/PluginLogger.php b/src/devmine/consumer/plugin/PluginLogger.php similarity index 96% rename from src/devmine/pluginfeatures/PluginLogger.php rename to src/devmine/consumer/plugin/PluginLogger.php index 7e2f400..30112a5 100644 --- a/src/devmine/pluginfeatures/PluginLogger.php +++ b/src/devmine/consumer/plugin/PluginLogger.php @@ -2,10 +2,10 @@ -namespace devmine\pluginfeatures; +namespace devmine\consumer\plugin; use LogLevel; -use devmine\Server; +use devmine\server\server; class PluginLogger implements \AttachableLogger{ diff --git a/src/devmine/pluginfeatures/PluginManager.php b/src/devmine/consumer/plugin/PluginManager.php similarity index 87% rename from src/devmine/pluginfeatures/PluginManager.php rename to src/devmine/consumer/plugin/PluginManager.php index 38f60f8..e8e30f0 100644 --- a/src/devmine/pluginfeatures/PluginManager.php +++ b/src/devmine/consumer/plugin/PluginManager.php @@ -2,26 +2,23 @@ -namespace devmine\pluginfeatures; +namespace devmine\consumer\plugin; use devmine\server\commands\defaults\TimingsCommand; use devmine\server\commands\PluginCommand; use devmine\server\commands\SimpleCommandMap; -use devmine\server\events\Event; -use devmine\server\events\EventPriority; -use devmine\server\events\HandlerList; -use devmine\server\events\Listener; -use devmine\server\events\Timings; -use devmine\server\events\TimingsHandler; -use devmine\server\permissions\Permissible; -use devmine\server\permissions\Permission; -use devmine\Server; +use devmine\events\Event; +use devmine\events\EventPriority; +use devmine\events\HandlerList; +use devmine\events\Listener; +use devmine\events\Timings; +use devmine\events\TimingsHandler; +use devmine\server\perms\Permissible; +use devmine\server\perms\Permission; +use devmine\server\server; use devmine\utilities\main\MainLogger; use devmine\utilities\main\PluginException; -use devmine\server\events\entity\EntityDamageByEntityEvent; -use devmine\server\events\entity\EntityDeathEvent; - /** * Manages all the plugins, Permissions and Permissibles */ @@ -186,15 +183,15 @@ public function loadPlugins($directory, $newLoaders = null){ $description = $loader->getPluginDescription($file); if($description instanceof PluginDescription){ $name = $description->getName(); - if(stripos($name, "devmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){ - $this->server->getLogger()->error($this->server->getLanguage()->translateString("devmine.plugin.loadError", [$name, "%devmine.plugin.restrictedName"])); + if(stripos($name, "DevMine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){ + $this->server->getLogger()->error($this->server->getLanguage()->translateString("DevMine.plugin.loadError", [$name, "%DevMine.plugin.restrictedName"])); continue; }elseif(strpos($name, " ") !== false){ - $this->server->getLogger()->warning($this->server->getLanguage()->translateString("devmine.plugin.spacesDiscouraged", [$name])); + $this->server->getLogger()->warning($this->server->getLanguage()->translateString("DevMine.plugin.spacesDiscouraged", [$name])); } if(isset($plugins[$name]) or $this->getPlugin($name) instanceof Plugin){ - $this->server->getLogger()->error($this->server->getLanguage()->translateString("devmine.plugin.duplicateError", [$name])); + $this->server->getLogger()->error($this->server->getLanguage()->translateString("DevMine.plugin.duplicateError", [$name])); continue; } @@ -222,40 +219,10 @@ public function loadPlugins($directory, $newLoaders = null){ break; } - $compatiblegeniapi = false; - foreach($description->getCompatibleGeniApis() as $version){ - //Format: majorVersion.minorVersion.patch - $version = array_map("intval", explode(".", $version)); - $apiVersion = array_map("intval", explode(".", $this->server->getGeniApiVersion())); - //Completely different API version - if($version[0] > $apiVersion[0]){ - continue; - } - //If the plugin uses new API - if($version[0] < $apiVersion[0]){ - $compatiblegeniapi = true; - break; - } - //If the plugin requires new API features, being backwards compatible - if($version[1] > $apiVersion[1]){ - continue; - } - - if($version[1] == $apiVersion[1] and $version[2] > $apiVersion[2]){ - continue; - } - $compatiblegeniapi = true; - break; - } if($compatible === false){ - $this->server->getLogger()->error($this->server->getLanguage()->translateString("devmine.plugin.loadError", [$name, "%devmine.plugin.incompatibleAPI"])); - continue; - } - - if($compatiblegeniapi === false){ - $this->server->getLogger()->error("Could not load plugin '{$description->getName()}': Incompatible GeniAPI version"); + $this->server->getLogger()->error($this->server->getLanguage()->translateString("DevMine.plugin.loadError", [$name, "%DevMine.plugin.incompatibleAPI"])); continue; } @@ -273,7 +240,7 @@ public function loadPlugins($directory, $newLoaders = null){ } } }catch(\Throwable $e){ - $this->server->getLogger()->error($this->server->getLanguage()->translateString("devmine.plugin.fileError", [$file, $directory, $e->getMessage()])); + $this->server->getLogger()->error($this->server->getLanguage()->translateString("DevMine.plugin.fileError", [$file, $directory, $e->getMessage()])); $this->server->getLogger()->logException($e); } } @@ -288,7 +255,7 @@ public function loadPlugins($directory, $newLoaders = null){ if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){ unset($dependencies[$name][$key]); }elseif(!isset($plugins[$dependency])){ - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("devmine.plugin.loadError", [$name, "%devmine.plugin.unknownDependency"])); + $this->server->getLogger()->critical($this->server->getLanguage()->translateString("DevMine.plugin.loadError", [$name, "%DevMine.plugin.unknownDependency"])); break; } } @@ -316,7 +283,7 @@ public function loadPlugins($directory, $newLoaders = null){ if($plugin = $this->loadPlugin($file, $loaders) and $plugin instanceof Plugin){ $loadedPlugins[$name] = $plugin; }else{ - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("devmine.plugin.genericLoadError", [$name])); + $this->server->getLogger()->critical($this->server->getLanguage()->translateString("DevMine.plugin.genericLoadError", [$name])); } } } @@ -330,7 +297,7 @@ public function loadPlugins($directory, $newLoaders = null){ if($plugin = $this->loadPlugin($file, $loaders) and $plugin instanceof Plugin){ $loadedPlugins[$name] = $plugin; }else{ - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("devmine.plugin.genericLoadError", [$name])); + $this->server->getLogger()->critical($this->server->getLanguage()->translateString("DevMine.plugin.genericLoadError", [$name])); } } } @@ -338,7 +305,7 @@ public function loadPlugins($directory, $newLoaders = null){ //No plugins loaded :( if($missingDependency === true){ foreach($plugins as $name => $file){ - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("devmine.plugin.loadError", [$name, "%devmine.plugin.circularDependency"])); + $this->server->getLogger()->critical($this->server->getLanguage()->translateString("DevMine.plugin.loadError", [$name, "%DevMine.plugin.circularDependency"])); } $plugins = []; } @@ -600,7 +567,7 @@ protected function parseYamlCommands(Plugin $plugin){ foreach($plugin->getDescription()->getCommands() as $key => $data){ if(strpos($key, ":") !== false){ - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("devmine.plugin.commandError", [$key, $plugin->getDescription()->getFullName()])); + $this->server->getLogger()->critical($this->server->getLanguage()->translateString("DevMine.plugin.commandError", [$key, $plugin->getDescription()->getFullName()])); continue; } if(is_array($data)){ @@ -617,7 +584,7 @@ protected function parseYamlCommands(Plugin $plugin){ $aliasList = []; foreach($data["aliases"] as $alias){ if(strpos($alias, ":") !== false){ - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("devmine.plugin.aliasError", [$alias, $plugin->getDescription()->getFullName()])); + $this->server->getLogger()->critical($this->server->getLanguage()->translateString("DevMine.plugin.aliasError", [$alias, $plugin->getDescription()->getFullName()])); continue; } $aliasList[] = $alias; @@ -690,7 +657,7 @@ public function callEvent(Event $event){ $registration->callEvent($event); }catch(\Throwable $e){ $this->server->getLogger()->critical( - $this->server->getLanguage()->translateString("devmine.plugin.eventError", [ + $this->server->getLanguage()->translateString("DevMine.plugin.eventError", [ $event->getEventName(), $registration->getPlugin()->getDescription()->getFullName(), $e->getMessage(), @@ -699,11 +666,6 @@ public function callEvent(Event $event){ $this->server->getLogger()->logException($e); } } - - if($this->server->getAIHolder() != null) { - if($event instanceof EntityDeathEvent) $this->server->getAIHolder()->MobDeath($event); - if($event instanceof EntityDamageByEntityEvent) $this->server->getAIHolder()->EntityDamage($event); - } } /** @@ -744,7 +706,7 @@ public function registerEvents(Listener $listener, Plugin $plugin){ $class = $parameters[0]->getClass()->getName(); $reflection = new \ReflectionClass($class); if(strpos((string) $reflection->getDocComment(), "@deprecated") !== false and $this->server->getProperty("settings.deprecated-verbose", true)){ - $this->server->getLogger()->warning($this->server->getLanguage()->translateString("devmine.plugin.deprecatedEvent", [ + $this->server->getLogger()->warning($this->server->getLanguage()->translateString("DevMine.plugin.deprecatedEvent", [ $plugin->getName(), $class, get_class($listener) . "->" . $method->getName() . "()" diff --git a/src/devmine/pluginfeatures/RegisteredListener.php b/src/devmine/consumer/plugin/RegisteredListener.php similarity index 89% rename from src/devmine/pluginfeatures/RegisteredListener.php rename to src/devmine/consumer/plugin/RegisteredListener.php index 4b3d0b3..4ff3c04 100644 --- a/src/devmine/pluginfeatures/RegisteredListener.php +++ b/src/devmine/consumer/plugin/RegisteredListener.php @@ -2,12 +2,12 @@ -namespace devmine\pluginfeatures; +namespace devmine\consumer\plugin; -use devmine\server\events\Cancellable; -use devmine\server\events\Event; -use devmine\server\events\Listener; -use devmine\server\events\TimingsHandler; +use devmine\events\Cancellable; +use devmine\events\Event; +use devmine\events\Listener; +use devmine\events\TimingsHandler; class RegisteredListener{ diff --git a/src/devmine/pluginfeatures/ScriptPluginLoader.php b/src/devmine/consumer/plugin/ScriptPluginLoader.php similarity index 89% rename from src/devmine/pluginfeatures/ScriptPluginLoader.php rename to src/devmine/consumer/plugin/ScriptPluginLoader.php index 5636433..1dddedc 100644 --- a/src/devmine/pluginfeatures/ScriptPluginLoader.php +++ b/src/devmine/consumer/plugin/ScriptPluginLoader.php @@ -2,11 +2,11 @@ -namespace devmine\pluginfeatures; +namespace devmine\consumer\plugin; -use devmine\server\events\plugin\PluginDisableEvent; -use devmine\server\events\plugin\PluginEnableEvent; -use devmine\Server; +use devmine\events\plugin\PluginDisableEvent; +use devmine\events\plugin\PluginEnableEvent; +use devmine\server\server; use devmine\utilities\main\PluginException; /** @@ -36,7 +36,7 @@ public function __construct(Server $server){ */ public function loadPlugin($file){ if(($description = $this->getPluginDescription($file)) instanceof PluginDescription){ - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.plugin.load", [$description->getFullName()])); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.plugin.load", [$description->getFullName()])); $dataFolder = dirname($file) . DIRECTORY_SEPARATOR . $description->getName(); if(file_exists($dataFolder) and !is_dir($dataFolder)){ throw new \InvalidStateException("Projected dataFolder '" . $dataFolder . "' for " . $description->getName() . " exists and is not a directory"); @@ -88,7 +88,7 @@ public function getPluginDescription($file){ $data[$key] = $content; } - if($insideHeader and strpos($line, "**/") !== false){ + if($insideHeader and strpos($line, "*/") !== false){ break; } } @@ -124,7 +124,7 @@ private function initPlugin(PluginBase $plugin, PluginDescription $description, */ public function enablePlugin(Plugin $plugin){ if($plugin instanceof PluginBase and !$plugin->isEnabled()){ - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.plugin.enable", [$plugin->getDescription()->getFullName()])); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.plugin.enable", [$plugin->getDescription()->getFullName()])); $plugin->setEnabled(true); @@ -137,7 +137,7 @@ public function enablePlugin(Plugin $plugin){ */ public function disablePlugin(Plugin $plugin){ if($plugin instanceof PluginBase and $plugin->isEnabled()){ - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.plugin.disable", [$plugin->getDescription()->getFullName()])); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.plugin.disable", [$plugin->getDescription()->getFullName()])); $this->server->getPluginManager()->callEvent(new PluginDisableEvent($plugin)); diff --git a/src/devmine/consumer/resourcepacks/ResourcePackInfoEntry.php b/src/devmine/consumer/resourcepacks/ResourcePackInfoEntry.php new file mode 100644 index 0000000..fcf2f97 --- /dev/null +++ b/src/devmine/consumer/resourcepacks/ResourcePackInfoEntry.php @@ -0,0 +1,30 @@ +packId = $packId; + $this->version = $version; + $this->packSize = $packSize; + } + + public function getPackId() : string{ + return $this->packId; + } + + public function getVersion() : string{ + return $this->version; + } + + public function getPackSize(){ + return $this->packSize; + } + +} \ No newline at end of file diff --git a/src/devmine/creatures/entities/Ageable.php b/src/devmine/creatures/entities/Ageable.php index d57a7ef..6180816 100644 --- a/src/devmine/creatures/entities/Ageable.php +++ b/src/devmine/creatures/entities/Ageable.php @@ -6,9 +6,5 @@ interface Ageable{ - const DATA_AGEABLE_FLAGS = 14; - - const DATA_FLAG_BABY = 0; - public function isBaby(); } \ No newline at end of file diff --git a/src/devmine/creatures/entities/Animal.php b/src/devmine/creatures/entities/Animal.php index b2c1542..a9d5573 100644 --- a/src/devmine/creatures/entities/Animal.php +++ b/src/devmine/creatures/entities/Animal.php @@ -7,14 +7,7 @@ abstract class Animal extends Creature implements Ageable{ - public function initEntity(){ - parent::initEntity(); - if($this->getDataProperty(self::DATA_AGEABLE_FLAGS) === null){ - $this->setDataProperty(self::DATA_AGEABLE_FLAGS, self::DATA_TYPE_BYTE, 0); - } - } - public function isBaby(){ - return $this->getDataFlag(self::DATA_AGEABLE_FLAGS, self::DATA_FLAG_BABY); + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BABY); } } \ No newline at end of file diff --git a/src/devmine/creatures/entities/Arrow.php b/src/devmine/creatures/entities/Arrow.php index 7733e81..099cab4 100644 --- a/src/devmine/creatures/entities/Arrow.php +++ b/src/devmine/creatures/entities/Arrow.php @@ -5,15 +5,15 @@ namespace devmine\creatures\entities; use devmine\inventory\items\Potion; -use devmine\levels\format\FullChunk; -use devmine\levels\particle\CriticalParticle; -use devmine\levels\particle\MobSpellParticle; +use devmine\worlds\format\Chunk; +use devmine\worlds\particle\CriticalParticle; +use devmine\worlds\particle\MobSpellParticle; use devmine\creatures\player\tag\CompoundTag; use devmine\creatures\player\tag\ShortTag; use devmine\server\network\protocol\AddEntityPacket; -use devmine\Player; +use devmine\creatures\player; -class Arrow extends Projecsolidentity{ +class Arrow extends Projectile{ const NETWORK_ID = 80; public $width = 0.5; @@ -28,7 +28,7 @@ class Arrow extends Projecsolidentity{ protected $isCritical; protected $potionId; - public function __construct(FullChunk $chunk, CompoundTag $nbt, Entity $shootingEntity = null, $critical = false){ + public function __construct(Chunk $chunk, CompoundTag $nbt, Entity $shootingEntity = null, $critical = false){ $this->isCritical = (bool) $critical; if(!isset($nbt->Potion)){ $nbt->Potion = new ShortTag("Potion", 0); @@ -90,7 +90,7 @@ public function spawnTo(Player $player){ $pk->speedX = $this->motionX; $pk->speedY = $this->motionY; $pk->speedZ = $this->motionZ; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Attribute.php b/src/devmine/creatures/entities/Attribute.php index 0044543..2c2493f 100644 --- a/src/devmine/creatures/entities/Attribute.php +++ b/src/devmine/creatures/entities/Attribute.php @@ -4,7 +4,7 @@ namespace devmine\creatures\entities; -use devmine\Server; +use devmine\server\server; class Attribute{ @@ -35,17 +35,18 @@ class Attribute{ protected static $attributes = []; public static function init(){ - self::addAttribute(self::ABSORPTION, "generic.absorption", 0.00, 340282346638528859811704183484516925440.00, 0.00); - self::addAttribute(self::SATURATION, "player.saturation", 0.00, 20.00, 5.00); - self::addAttribute(self::EXHAUSTION, "player.exhaustion", 0.00, 5.00, 0.41); - self::addAttribute(self::KNOCKBACK_RESISTANCE, "generic.knockbackResistance", 0.00, 1.00, 0.00); - self::addAttribute(self::HEALTH, "generic.health", 0.00, 20.00, 20.00); - self::addAttribute(self::MOVEMENT_SPEED, "generic.movementSpeed", 0.00, 340282346638528859811704183484516925440.00, 0.10); - self::addAttribute(self::FOLLOW_RANGE, "generic.followRange", 0.00, 2048.00, 16.00, false); - self::addAttribute(self::HUNGER, "player.hunger", 0.00, 20.00, 20.00); - self::addAttribute(self::ATTACK_DAMAGE, "generic.attackDamage", 0.00, 340282346638528859811704183484516925440.00, 1.00, false); - self::addAttribute(self::EXPERIENCE_LEVEL, "player.level", 0.00, 24791.00, 0.00); - self::addAttribute(self::EXPERIENCE, "player.experience", 0.00, 1.00, 0.00); + self::addAttribute(self::ABSORPTION, "minecraft:absorption", 0.00, 340282346638528859811704183484516925440.00, 0.00); + self::addAttribute(self::SATURATION, "minecraft:player.saturation", 0.00, 20.00, 5.00); + self::addAttribute(self::EXHAUSTION, "minecraft:player.exhaustion", 0.00, 5.00, 0.41); + self::addAttribute(self::KNOCKBACK_RESISTANCE, "minecraft:knockback_resistance", 0.00, 1.00, 0.00); + self::addAttribute(self::HEALTH, "minecraft:health", 0.00, 20.00, 20.00); + self::addAttribute(self::MOVEMENT_SPEED, "minecraft:movement", 0.00, 340282346638528859811704183484516925440.00, 0.10); + self::addAttribute(self::FOLLOW_RANGE, "minecraft:follow_range", 0.00, 2048.00, 16.00, false); + self::addAttribute(self::HUNGER, "minecraft:player.hunger", 0.00, 20.00, 20.00); + self::addAttribute(self::ATTACK_DAMAGE, "minecraft:attack_damage", 0.00, 340282346638528859811704183484516925440.00, 1.00, false); + self::addAttribute(self::EXPERIENCE_LEVEL, "minecraft:player.level", 0.00, 24791.00, 0.00); + self::addAttribute(self::EXPERIENCE, "minecraft:player.experience", 0.00, 1.00, 0.00); + //TODO: minecraft:luck (for fishing?) } /** @@ -153,7 +154,7 @@ public function getValue(){ return $this->currentValue; } - public function setValue($value, $fit = true){ + public function setValue($value, bool $fit = true, bool $shouldSend = false){ if($value > $this->getMaxValue() or $value < $this->getMinValue()){ if(!$fit){ Server::getInstance()->getLogger()->error("[Attribute / {$this->getName()}] Value $value exceeds the range!"); @@ -165,6 +166,10 @@ public function setValue($value, $fit = true){ $this->desynchronized = true; $this->currentValue = $value; } + + if($shouldSend){ + $this->desynchronized = true; + } return $this; } diff --git a/src/devmine/creatures/entities/AttributeMap.php b/src/devmine/creatures/entities/AttributeMap.php index 0294f37..a3ae600 100644 --- a/src/devmine/creatures/entities/AttributeMap.php +++ b/src/devmine/creatures/entities/AttributeMap.php @@ -21,6 +21,10 @@ public function getAttribute(int $id){ return $this->attributes[$id] ?? null; } + public function getAll(): array{ + return $this->attributes; + } + /** * @return Attribute[] */ diff --git a/src/devmine/creatures/entities/Bat.php b/src/devmine/creatures/entities/Bat.php index afc8e91..0a8e9df 100644 --- a/src/devmine/creatures/entities/Bat.php +++ b/src/devmine/creatures/entities/Bat.php @@ -1,18 +1,31 @@ isResting)){ $nbt->isResting = new ByteTag("isResting", 0); } parent::__construct($chunk, $nbt); - $this->setDataProperty(self::DATA_IS_RESTING, self::DATA_TYPE_BYTE, $this->isResting()); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_RESTING, $this->isResting()); } public function isResting() : int{ @@ -72,7 +85,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Blaze.php b/src/devmine/creatures/entities/Blaze.php index 7d67995..28c69dc 100644 --- a/src/devmine/creatures/entities/Blaze.php +++ b/src/devmine/creatures/entities/Blaze.php @@ -1,12 +1,29 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); } diff --git a/src/devmine/creatures/entities/BlazeFireball.php b/src/devmine/creatures/entities/BlazeFireball.php new file mode 100644 index 0000000..a0e9baa --- /dev/null +++ b/src/devmine/creatures/entities/BlazeFireball.php @@ -0,0 +1,92 @@ +isCritical = $critical; + } + + public function isExplode() : bool{ + return $this->canExplode; + } + + public function setExplode(bool $bool){ + $this->canExplode = $bool; + } + + public function onUpdate($currentTick){ + if($this->closed){ + return false; + } + + $this->timings->startTiming(); + $hasUpdate = parent::onUpdate($currentTick); + if(!$this->hadCollision and $this->isCritical){ + $this->level->addParticle(new CriticalParticle($this->add( + $this->width / 2 + mt_rand(-100, 100) / 500, + $this->height / 2 + mt_rand(-100, 100) / 500, + $this->width / 2 + mt_rand(-100, 100) / 500))); + }elseif($this->onGround){ + $this->isCritical = false; + } + + if($this->age > 1200 or $this->isCollided){ + if($this->isCollided and $this->canExplode){ + $this->server->getPluginManager()->callEvent($ev = new ExplosionPrimeEvent($this, 2.8)); + if(!$ev->isCancelled()){ + $explosion = new Explosion($this, $ev->getForce(), $this->shootingEntity); + if($ev->isBlockBreaking()){ + $explosion->explodeA(); + } + $explosion->explodeB(); + } + } + $this->kill(); + $hasUpdate = true; + } + $this->timings->stopTiming(); + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = BlazeFireball::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + parent::spawnTo($player); + } + +} \ No newline at end of file diff --git a/src/devmine/creatures/entities/BlueWitherSkull.php b/src/devmine/creatures/entities/BlueWitherSkull.php new file mode 100644 index 0000000..0f6d46a --- /dev/null +++ b/src/devmine/creatures/entities/BlueWitherSkull.php @@ -0,0 +1,62 @@ +closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = BlueWitherSkull::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} diff --git a/src/devmine/creatures/entities/Boat.php b/src/devmine/creatures/entities/Boat.php index 7149754..d581e99 100644 --- a/src/devmine/creatures/entities/Boat.php +++ b/src/devmine/creatures/entities/Boat.php @@ -1,40 +1,51 @@ WoodID)){ $nbt->WoodID = new IntTag("WoodID", 0); } parent::__construct($chunk, $nbt); - $this->setDataProperty(self::DATA_WOOD_ID, self::DATA_TYPE_BYTE, $this->getWoodID()); + $this->setDataProperty(self::DATA_VARIANT, self::DATA_TYPE_INT, $this->getWoodID()); } public function getWoodID() : int{ @@ -53,7 +64,7 @@ public function spawnTo(Player $player){ $pk->speedZ = 0; $pk->yaw = 0; $pk->pitch = 0; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Camera.php b/src/devmine/creatures/entities/Camera.php new file mode 100644 index 0000000..3b34ad3 --- /dev/null +++ b/src/devmine/creatures/entities/Camera.php @@ -0,0 +1,43 @@ +eid = $this->getId(); + $pk->type = Camera::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + parent::spawnTo($player); + } + + public function getDrops(){ + return []; + } +} diff --git a/src/devmine/creatures/entities/CaveSpider.php b/src/devmine/creatures/entities/CaveSpider.php index 2089303..f7e80bf 100644 --- a/src/devmine/creatures/entities/CaveSpider.php +++ b/src/devmine/creatures/entities/CaveSpider.php @@ -1,15 +1,28 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Chicken.php b/src/devmine/creatures/entities/Chicken.php index 105bdbb..aa8cbfe 100644 --- a/src/devmine/creatures/entities/Chicken.php +++ b/src/devmine/creatures/entities/Chicken.php @@ -1,16 +1,29 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); } diff --git a/src/devmine/creatures/entities/Cow.php b/src/devmine/creatures/entities/Cow.php index 920551e..c5d04e2 100644 --- a/src/devmine/creatures/entities/Cow.php +++ b/src/devmine/creatures/entities/Cow.php @@ -1,13 +1,30 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Creature.php b/src/devmine/creatures/entities/Creature.php index 0a6eaaf..00a87c8 100644 --- a/src/devmine/creatures/entities/Creature.php +++ b/src/devmine/creatures/entities/Creature.php @@ -4,8 +4,8 @@ namespace devmine\creatures\entities; -use devmine\server\events\entity\EntityDamageEvent; -use devmine\levels\Level; +use devmine\events\entity\EntityDamageEvent; +use devmine\worlds\Level; use devmine\server\calculations\Vector3; abstract class Creature extends Living{ diff --git a/src/devmine/creatures/entities/Creeper.php b/src/devmine/creatures/entities/Creeper.php index 2544c69..928c84a 100644 --- a/src/devmine/creatures/entities/Creeper.php +++ b/src/devmine/creatures/entities/Creeper.php @@ -1,26 +1,38 @@ namedtag->powered)){ $this->setPowered(false); } - $this->setDataProperty(self::DATA_POWERED, self::DATA_TYPE_BYTE, $this->isPowered() ? 1 : 0); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_POWERED, $this->isPowered()); } public function setPowered(bool $powered, Lightning $lightning = null){ @@ -47,12 +59,12 @@ public function setPowered(bool $powered, Lightning $lightning = null){ if(!$ev->isCancelled()){ $this->namedtag->powered = new ByteTag("powered", $powered ? 1 : 0); - $this->setDataProperty(self::DATA_POWERED, self::DATA_TYPE_BYTE, $powered ? 1 : 0); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_POWERED, $powered); } } public function isPowered() : bool{ - return $this->namedtag["powered"] == 0 ? false : true; + return (bool) $this->namedtag["powered"]; } public function spawnTo(Player $player){ @@ -67,7 +79,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/DragonFireBall.php b/src/devmine/creatures/entities/DragonFireBall.php new file mode 100644 index 0000000..c888dd4 --- /dev/null +++ b/src/devmine/creatures/entities/DragonFireBall.php @@ -0,0 +1,62 @@ +closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = DragonFireBall::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/creatures/entities/Effect.php b/src/devmine/creatures/entities/Effect.php index 1e2e691..6649f53 100644 --- a/src/devmine/creatures/entities/Effect.php +++ b/src/devmine/creatures/entities/Effect.php @@ -4,12 +4,12 @@ namespace devmine\creatures\entities; -use devmine\server\events\entity\EntityDamageEvent; -use devmine\server\events\entity\EntityRegainHealthEvent; +use devmine\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityRegainHealthEvent; +use devmine\events\player\PlayerExhaustEvent; use devmine\server\network\Network; use devmine\server\network\protocol\MobEffectPacket; -use devmine\Player; - +use devmine\creatures\player; class Effect{ const SPEED = 1; @@ -187,11 +187,18 @@ public function canTick(){ } return true; case Effect::REGENERATION: - case Effect::HUNGER: if(($interval = (40 >> $this->amplifier)) > 0){ return ($this->duration % $interval) === 0; } return true; + case Effect::HUNGER: + if($this->amplifier < 0){ // prevents hacking with amplifier -1 + return false; + } + if(($interval = 20) > 0){ + return ($this->duration % $interval) === 0; + } + return true; case Effect::HEALING: case Effect::HARMING: return true; @@ -225,10 +232,8 @@ public function applyEffect(Entity $entity){ } break; case Effect::HUNGER: - if($entity instanceof Player){ - if($entity->getServer()->foodEnabled){ - $entity->setFood($entity->getFood() - 1); - } + if($entity instanceof Human){ + $entity->exhaust(0.5 * $this->amplifier, PlayerExhaustEvent::CAUSE_POTION); } break; case Effect::HEALING: @@ -288,27 +293,27 @@ public function add(Entity $entity, $modify = false, Effect $oldEffect = null){ if($this->id === Effect::SPEED){ $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); if($modify and $oldEffect !== null){ - $speed = $attr->getValue() / (1 + 0.2 * $oldEffect->getAmplifier()); + $speed = $attr->getValue() / (1 + 0.2 * ($oldEffect->getAmplifier() + 1)); }else{ $speed = $attr->getValue(); } - $speed *= (1 + 0.2 * $this->amplifier); + $speed *= (1 + 0.2 * ($this->amplifier + 1)); $attr->setValue($speed); }elseif($this->id === Effect::SLOWNESS){ $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); if($modify and $oldEffect !== null){ - $speed = $attr->getValue() / (1 - 0.15 * $oldEffect->getAmplifier()); + $speed = $attr->getValue() / (1 - 0.15 * ($oldEffect->getAmplifier() + 1)); }else{ $speed = $attr->getValue(); } - $speed *= (1 - 0.15 * $this->amplifier); + $speed *= (1 - (0.15 * $this->amplifier + 1)); $attr->setValue($speed); } } if($this->id === Effect::INVISIBILITY){ $entity->setDataFlag(Entity::DATA_FLAGS, Entity::DATA_FLAG_INVISIBLE, true); - $entity->setDataProperty(Entity::DATA_SHOW_NAMETAG, Entity::DATA_TYPE_BYTE, 0); + $entity->setNameTagVisible(false); } } @@ -323,16 +328,16 @@ public function remove(Entity $entity){ if($this->id === Effect::SPEED){ $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); - $attr->setValue($attr->getValue() / (1 + 0.2 * $this->amplifier)); + $attr->setValue($attr->getValue() / (1 + 0.2 * ($this->amplifier + 1))); }elseif($this->id === Effect::SLOWNESS){ $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); - $attr->setValue($attr->getValue() / (1 - 0.15 * $this->amplifier)); + $attr->setValue($attr->getValue() / (1 - 0.15 * ($this->amplifier + 1))); } } if($this->id === Effect::INVISIBILITY){ $entity->setDataFlag(Entity::DATA_FLAGS, Entity::DATA_FLAG_INVISIBLE, false); - $entity->setDataProperty(Entity::DATA_SHOW_NAMETAG, Entity::DATA_TYPE_BYTE, 1); + $entity->setNameTagVisible(true); } } } diff --git a/src/devmine/creatures/entities/Egg.php b/src/devmine/creatures/entities/Egg.php index 31bb3e4..660d6c2 100644 --- a/src/devmine/creatures/entities/Egg.php +++ b/src/devmine/creatures/entities/Egg.php @@ -1,12 +1,32 @@ speedX = $this->motionX; $pk->speedY = $this->motionY; $pk->speedZ = $this->motionZ; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/ElderGuardian.php b/src/devmine/creatures/entities/ElderGuardian.php new file mode 100644 index 0000000..f8c67f6 --- /dev/null +++ b/src/devmine/creatures/entities/ElderGuardian.php @@ -0,0 +1,158 @@ +setMaxHealth(80); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ELDER, 1); + } + + public function getName() : string{ + return "Elder Guardian"; + } + + public function attack($damage, EntityDamageEvent $source){ + parent::attack($damage, $source); + if($source->isCancelled()){ + return; + } + + if($source instanceof EntityDamageByEntityEvent){ + $this->swimSpeed = mt_rand(150, 350) / 2000; + $e = $source->getDamager(); + $this->swimDirection = (new Vector3($this->x - $e->x, $this->y - $e->y, $this->z - $e->z))->normalize(); + + $pk = new EntityEventPacket(); + $pk->eid = $this->getId(); + Server::broadcastPacket($this->hasSpawned, $pk); + } + } + + private function generateRandomDirection(){ + return new Vector3(mt_rand(-1000, 1000) / 1000, mt_rand(-500, 500) / 1000, mt_rand(-1000, 1000) / 1000); + } + + + public function onUpdate($currentTick){ + if($this->closed !== false){ + return false; + } + + if(++$this->switchDirectionTicker === 100){ + $this->switchDirectionTicker = 0; + if(mt_rand(0, 100) < 50){ + $this->swimDirection = null; + } + } + + $this->lastUpdate = $currentTick; + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->isAlive()){ + + if($this->y > 62 and $this->swimDirection !== null){ + $this->swimDirection->y = -0.5; + } + + $inWater = $this->isInsideOfWater(); + if(!$inWater){ + $this->motionY -= $this->gravity; + $this->swimDirection = null; + }elseif($this->swimDirection !== null){ + if($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2 <= $this->swimDirection->lengthSquared()){ + $this->motionX = $this->swimDirection->x * $this->swimSpeed; + $this->motionY = $this->swimDirection->y * $this->swimSpeed; + $this->motionZ = $this->swimDirection->z * $this->swimSpeed; + } + }else{ + $this->swimDirection = $this->generateRandomDirection(); + $this->swimSpeed = mt_rand(50, 100) / 2000; + } + + $expectedPos = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ); + + $this->move($this->motionX, $this->motionY, $this->motionZ); + + if($expectedPos->distanceSquared($this) > 0){ + $this->swimDirection = $this->generateRandomDirection(); + $this->swimSpeed = mt_rand(50, 100) / 2000; + } + + $friction = 1 - $this->drag; + + $this->motionX *= $friction; + $this->motionY *= 1 - $this->drag; + $this->motionZ *= $friction; + + $f = sqrt(($this->motionX ** 2) + ($this->motionZ ** 2)); + $this->yaw = (-atan2($this->motionX, $this->motionZ) * 180 / M_PI); + $this->pitch = (-atan2($f, $this->motionY) * 180 / M_PI); + + if($this->onGround){ + $this->motionY *= -0.5; + } + + } + + $this->timings->stopTiming(); + + return $hasUpdate or !$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + } + + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = ElderGuardian::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $drops = array(ItemItem::get(ItemItem::PRISMARINE_SHARD, 0, mt_rand(1, 2))); + $drops[] = ItemItem::get(ItemItem::RAW_FISH, 0, mt_rand(0, 1)); + return $drops; + } +} diff --git a/src/devmine/creatures/entities/EnderCrystal.php b/src/devmine/creatures/entities/EnderCrystal.php new file mode 100644 index 0000000..fe8eac7 --- /dev/null +++ b/src/devmine/creatures/entities/EnderCrystal.php @@ -0,0 +1,58 @@ +eid = $this->getId(); + $pk->type = EnderCrystal::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = 0; + $pk->speedY = 0; + $pk->speedZ = 0; + $pk->yaw = 0; + $pk->pitch = 0; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} diff --git a/src/devmine/creatures/entities/EnderDragon.php b/src/devmine/creatures/entities/EnderDragon.php new file mode 100644 index 0000000..10eb461 --- /dev/null +++ b/src/devmine/creatures/entities/EnderDragon.php @@ -0,0 +1,45 @@ +setMaxHealth(200); + parent::initEntity(); + } + //-------------------------------------// + + public function getName() : string{ + return "Ender Dragon"; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = self::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + +} \ No newline at end of file diff --git a/src/devmine/creatures/entities/EnderPearl.php b/src/devmine/creatures/entities/EnderPearl.php new file mode 100644 index 0000000..4477759 --- /dev/null +++ b/src/devmine/creatures/entities/EnderPearl.php @@ -0,0 +1,77 @@ +closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + /** @return Player */ + public function getSpawner(){ + return $this->player; + } + + public function setSpawner(Player $player){ + $this->player = $player; + } + + public function close(){ + if ($this->getSpawner() instanceof Player) { + $this->getSpawner()->teleport($this); + } + parent::close(); + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = self::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} diff --git a/src/devmine/creatures/entities/Enderman.php b/src/devmine/creatures/entities/Enderman.php index 0623e56..8f4a466 100644 --- a/src/devmine/creatures/entities/Enderman.php +++ b/src/devmine/creatures/entities/Enderman.php @@ -1,15 +1,28 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Entity.php b/src/devmine/creatures/entities/Entity.php index 24d2cdf..640d4a8 100644 --- a/src/devmine/creatures/entities/Entity.php +++ b/src/devmine/creatures/entities/Entity.php @@ -13,26 +13,27 @@ use devmine\inventory\blocks\PressurePlate; use devmine\inventory\blocks\Water; use devmine\inventory\blocks\SlimeBlock; -use devmine\server\events\entity\EntityDamageEvent; -use devmine\server\events\entity\EntityDespawnEvent; -use devmine\server\events\entity\EntityLevelChangeEvent; -use devmine\server\events\entity\EntityMotionEvent; -use devmine\server\events\entity\EntityRegainHealthEvent; -use devmine\server\events\entity\EntitySpawnEvent; -use devmine\server\events\entity\EntityTeleportEvent; -use devmine\server\events\Timings; -use devmine\levels\format\Chunk; -use devmine\levels\format\FullChunk; -use devmine\levels\Level; -use devmine\levels\Location; -use devmine\levels\particle\DestroyBlockParticle; -use devmine\levels\Position; +use devmine\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityDespawnEvent; +use devmine\events\entity\EntityEffectAddEvent; +use devmine\events\entity\EntityEffectRemoveEvent; +use devmine\events\entity\EntityLevelChangeEvent; +use devmine\events\entity\EntityMotionEvent; +use devmine\events\entity\EntityRegainHealthEvent; +use devmine\events\entity\EntitySpawnEvent; +use devmine\events\entity\EntityTeleportEvent; +use devmine\events\Timings; +use devmine\worlds\format\Chunk; +use devmine\worlds\Level; +use devmine\worlds\Location; +use devmine\worlds\particle\DestroyBlockParticle; +use devmine\worlds\Position; use devmine\server\calculations\AxisAlignedBB; use devmine\server\calculations\Math; use devmine\server\calculations\Vector2; use devmine\server\calculations\Vector3; -use devmine\server\epilogos\epilogosble; -use devmine\server\epilogos\epilogosValue; +use devmine\server\meta\Metadatable; +use devmine\server\meta\MetadataValue; use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\CompoundTag; use devmine\creatures\player\tag\DoubleTag; @@ -45,12 +46,12 @@ use devmine\server\network\protocol\RemoveEntityPacket; use devmine\server\network\protocol\SetEntityDataPacket; use devmine\server\network\protocol\SetEntityLinkPacket; -use devmine\Player; -use devmine\pluginfeatures\Plugin; -use devmine\Server; +use devmine\creatures\player; +use devmine\consumer\plugin\Plugin; +use devmine\server\server; use devmine\utilities\main\ChunkException; -abstract class Entity extends Location implements epilogosble{ +abstract class Entity extends Location implements Metadatable{ const NETWORK_ID = -1; @@ -63,30 +64,86 @@ abstract class Entity extends Location implements epilogosble{ const DATA_TYPE_STRING = 4; const DATA_TYPE_SLOT = 5; const DATA_TYPE_POS = 6; - //const DATA_TYPE_ROTATION = 8; - //const DATA_TYPE_LONG = 8; const DATA_TYPE_LONG = 7; - + const DATA_TYPE_VECTOR3F = 8; + const DATA_FLAGS = 0; - const DATA_AIR = 1; - const DATA_NAMETAG = 2; - const DATA_SHOW_NAMETAG = 3; - const DATA_SILENT = 4; - const DATA_POTION_COLOR = 7; - const DATA_POTION_AMBIENT = 8; - const DATA_NO_AI = 15; - - const DATA_LEAD_HOLDER = 23; + //1 (int) + const DATA_VARIANT = 2; //int + const DATA_COLOUR = 3; //byte + const DATA_NAMETAG = 4; //string + const DATA_OWNER_EID = 5; //long + + const DATA_AIR = 7; //short + const DATA_POTION_COLOR = 8; //int (ARGB!) + const DATA_POTION_AMBIENT = 9; //byte + + /* 27 (byte) player-specific flags + * 28 (int) player "index"? + * 29 (block coords) bed position */ + const DATA_SCALE = 39; //float + const DATA_INTERACTIVE_TAG = 40; //string (button text) + /* 41 (long) */ + const DATA_URL_TAG = 43; //string + const DATA_MAX_AIR = 44; //short + const DATA_MARK_VARIANT = 45; //int + /* 46 (byte) + * 47 (int) + * 48 (int) + * 49 (long) + * 50 (long) + * 51 (long) + * 52 (short) */ + const DATA_BOUNDING_BOX_WIDTH = 53; //float + const DATA_BOUNDING_BOX_HEIGHT = 54; //float + const DATA_FUSE_LENGTH = 55; //int + /* 56 (vector3f) + * 57 (byte) + * 58 (float) + * 59 (float) */ + + const DATA_LEAD_HOLDER_EID = 38; const DATA_LEAD_HOLDER = 38; const DATA_LEAD = 24; - const DATA_FLAG_ONFIRE = 0; const DATA_FLAG_SNEAKING = 1; const DATA_FLAG_RIDING = 2; const DATA_FLAG_SPRINTING = 3; const DATA_FLAG_ACTION = 4; const DATA_FLAG_INVISIBLE = 5; - + const DATA_FLAG_TEMPTED = 6; //??? + const DATA_FLAG_INLOVE = 7; + const DATA_FLAG_SADDLED = 8; + const DATA_FLAG_POWERED = 9; + const DATA_FLAG_IGNITED = 10; //for creepers? + const DATA_FLAG_BABY = 11; + const DATA_FLAG_CONVERTING = 12; //??? + const DATA_FLAG_CRITICAL = 13; + const DATA_FLAG_CAN_SHOW_NAMETAG = 14; + const DATA_FLAG_ALWAYS_SHOW_NAMETAG = 15; + const DATA_FLAG_IMMOBILE = 16, DATA_FLAG_NO_AI = 16; + const DATA_FLAG_SILENT = 17; + const DATA_FLAG_WALLCLIMBING = 18; + const DATA_FLAG_RESTING = 19; //for bats? + const DATA_FLAG_SITTING = 20; + const DATA_FLAG_ANGRY = 21; + const DATA_FLAG_INTERESTED = 22; //for mobs following players with food? + const DATA_FLAG_CHARGED = 23; + const DATA_FLAG_TAMED = 24; + const DATA_FLAG_LEASHED = 25; + const DATA_FLAG_SHEARED = 26; //for sheep + const DATA_FLAG_GLIDING = 27; const DATA_FLAG_FALL_FLYING = 27; + const DATA_FLAG_ELDER = 28; //elder guardian + const DATA_FLAG_MOVING = 29; + const DATA_FLAG_BREATHING = 30; //hides bubbles if true + const DATA_FLAG_CHESTED = 31; //for mules? + const DATA_FLAG_STACKABLE = 32; + const DATA_FLAG_IDLING = 36; //Thanks pmmp. + + const SOUTH = 0; + const WEST = 1; + const NORTH = 2; + const EAST = 3; public static $entityCount = 1; /** @var Entity[] */ @@ -105,12 +162,11 @@ abstract class Entity extends Location implements epilogosble{ protected $dataFlags = 0; protected $dataProperties = [ - self::DATA_FLAGS => [self::DATA_TYPE_BYTE, 0], - self::DATA_AIR => [self::DATA_TYPE_SHORT, 300], + self::DATA_FLAGS => [self::DATA_TYPE_LONG, 0], + self::DATA_AIR => [self::DATA_TYPE_SHORT, 400], + self::DATA_MAX_AIR => [self::DATA_TYPE_SHORT, 400], self::DATA_NAMETAG => [self::DATA_TYPE_STRING, ""], - self::DATA_SHOW_NAMETAG => [self::DATA_TYPE_BYTE, 1], - self::DATA_SILENT => [self::DATA_TYPE_BYTE, 0], - self::DATA_NO_AI => [self::DATA_TYPE_BYTE, 0], + //self::DATA_SILENT => [self::DATA_TYPE_BYTE, 0], self::DATA_LEAD_HOLDER => [self::DATA_TYPE_LONG, -1], self::DATA_LEAD => [self::DATA_TYPE_BYTE, 0], ]; @@ -196,7 +252,7 @@ abstract class Entity extends Location implements epilogosble{ public $closed = false; - /** @var \devmine\server\events\TimingsHandler */ + /** @var \devmine\events\TimingsHandler */ protected $timings; protected $isPlayer = false; @@ -213,8 +269,10 @@ abstract class Entity extends Location implements epilogosble{ public $dropExp = [0, 0]; - public function __construct(FullChunk $chunk, CompoundTag $nbt){ - assert($chunk !== null and $chunk->getProvider() !== null); + public function __construct(Chunk $chunk, CompoundTag $nbt){ + if($chunk === null or $chunk->getProvider() === null){ + throw new ChunkException("Invalid garbage Chunk given to Entity"); + } $this->timings = Timings::getEntityTimings($this); @@ -246,7 +304,9 @@ public function __construct(FullChunk $chunk, CompoundTag $nbt){ ); $this->setMotion($this->temporalVector->setComponents($this->namedtag["Motion"][0], $this->namedtag["Motion"][1], $this->namedtag["Motion"][2])); - assert(!is_nan($this->x) and !is_infinite($this->x) and !is_nan($this->y) and !is_infinite($this->y) and !is_nan($this->z) and !is_infinite($this->z)); + if(is_nan($this->x) or is_infinite($this->x) or is_nan($this->y) or is_infinite($this->y) or is_nan($this->z) or is_infinite($this->z)){ + throw new \InvalidStateException("Invalid entity coordinates"); + } if(!isset($this->namedtag->FallDistance)){ $this->namedtag->FallDistance = new FloatTag("FallDistance", 0); @@ -310,7 +370,15 @@ public function getNameTag(){ * @return bool */ public function isNameTagVisible(){ - return $this->getDataProperty(self::DATA_SHOW_NAMETAG) > 0; + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_CAN_SHOW_NAMETAG); + } + + + /** + * @return bool + */ + public function isNameTagAlwaysVisible(){ + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ALWAYS_SHOW_NAMETAG); } /** @@ -324,7 +392,13 @@ public function setNameTag($name){ * @param bool $value */ public function setNameTagVisible($value = true){ - $this->setDataProperty(self::DATA_SHOW_NAMETAG, self::DATA_TYPE_BYTE, $value ? 1 : 0); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_CAN_SHOW_NAMETAG, $value); + } + /** + * @param bool $value + */ + public function setNameTagAlwaysVisible($value = true){ + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ALWAYS_SHOW_NAMETAG, $value); } public function isSneaking(){ @@ -332,7 +406,7 @@ public function isSneaking(){ } public function setSneaking($value = true){ - $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_SNEAKING, (bool)$value); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_SNEAKING, (bool) $value); } public function isSprinting(){ @@ -347,6 +421,21 @@ public function setSprinting($value = true){ } } + public function isImmobile() : bool{ + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_IMMOBILE); + } + public function isGliding(){ + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_IDLING); + } + + public function setGliding($value = true){ + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_FALL_FLYING, (bool) $value); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_IDLING, (bool) $value); + } + public function setImmobile($value = true) : bool{ + return $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_IMMOBILE, $value); + } + /** * @return Effect[] */ @@ -361,6 +450,10 @@ public function removeAllEffects(){ } public function removeEffect($effectId){ + Server::getInstance()->getPluginManager()->callEvent($ev = new EntityEffectRemoveEvent($this, $effectId)); + if($ev->isCancelled()){ + return false; + } if(isset($this->effects[$effectId])){ $effect = $this->effects[$effectId]; unset($this->effects[$effectId]); @@ -370,6 +463,7 @@ public function removeEffect($effectId){ } $this->recalculateEffectColor(); + return true; } } @@ -382,6 +476,10 @@ public function hasEffect($effectId){ } public function addEffect(Effect $effect){ + Server::getInstance()->getPluginManager()->callEvent($ev = new EntityEffectAddEvent($this, $effect)); + if($ev->isCancelled()){ + return false; + } if($effect->getId() === Effect::HEALTH_BOOST){ $this->setHealth($this->getHealth() + 4 * ($effect->getAmplifier() + 1)); } @@ -394,7 +492,7 @@ public function addEffect(Effect $effect){ if(($effect->getAmplifier() <= ($oldEffect->getAmplifier())) and $effect->getDuration() < $oldEffect->getDuration()){ return; } - $effect->add($this, true); + $effect->add($this, true, $oldEffect); }else{ $effect->add($this, false); } @@ -402,6 +500,7 @@ public function addEffect(Effect $effect){ $this->effects[$effect->getId()] = $effect; $this->recalculateEffectColor(); + return true; } protected function recalculateEffectColor(){ @@ -435,14 +534,14 @@ protected function recalculateEffectColor(){ } /** - * @param int|string $type - * @param FullChunk $chunk - * @param CompoundTag $nbt - * @param $args + * @param int|string $type + * @param Chunk $chunk + * @param CompoundTag $nbt + * @param $args * - * @return Entity|Projecsolidentity + * @return Entity|Projectile */ - public static function createEntity($type, FullChunk $chunk, CompoundTag $nbt, ...$args){ + public static function createEntity($type, Chunk $chunk, CompoundTag $nbt, ...$args){ if(isset(self::$knownEntities[$type])){ $class = self::$knownEntities[$type]; return new $class($chunk, $nbt, ...$args); @@ -531,7 +630,9 @@ public function saveNBT(){ } protected function initEntity(){ - assert($this->namedtag instanceof CompoundTag); + if(!($this->namedtag instanceof CompoundTag)){ + throw new \InvalidArgumentException("Expecting CompoundTag, received " . get_class($this->namedtag)); + } if(isset($this->namedtag->CustomName)){ $this->setNameTag($this->namedtag["CustomName"]); @@ -592,26 +693,28 @@ public function sendPotionEffects(Player $player){ } } - /** - * @deprecated - */ - public function sendepilogos($player){ - $this->sendData($player); - } - /** * @param Player[]|Player $player * @param array $data Properly formatted entity data, defaults to everything */ public function sendData($player, array $data = null){ + if(!is_array($player)){ + $player = [$player]; + } + $pk = new SetEntityDataPacket(); $pk->eid = ($player === $this ? 0 : $this->getId()); - $pk->epilogos = $data === null ? $this->dataProperties : $data; + $pk->metadata = $data === null ? $this->dataProperties : $data; - if(!is_array($player)){ - $player->dataPacket($pk); - }else{ - Server::broadcastPacket($player, $pk); + foreach($player as $p){ + if($p === $this){ + continue; + } + $p->dataPacket(clone $pk); + } + if($this instanceof Player){ + $pk->eid = 0; + $this->dataPacket($pk); } } @@ -694,7 +797,7 @@ public function isAlive(){ * @param int $amount */ public function setHealth($amount){ - $amount = (int)$amount; + $amount = (int) $amount; if($amount === $this->health){ return; } @@ -704,7 +807,7 @@ public function setHealth($amount){ $this->kill(); } }elseif($amount <= $this->getMaxHealth() or $amount < $this->health){ - $this->health = (int)$amount; + $this->health = (int) $amount; }else{ $this->health = $this->getMaxHealth(); } @@ -739,7 +842,7 @@ public function getMaxHealth(){ * @param int $amount */ public function setMaxHealth($amount){ - $this->maxHealth = (int)$amount; + $this->maxHealth = (int) $amount; } public function canCollideWith(Entity $entity){ @@ -870,7 +973,7 @@ public function entityBaseTick($tickDiff = 1){ $hasUpdate = false; - $this->checkBlockCollision(); + //$this->checkBlockCollision(); if($this->y <= -16 and $this->isAlive()){ $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10); @@ -929,7 +1032,7 @@ protected function updateMovement(){ $this->lastYaw = $this->yaw; $this->lastPitch = $this->pitch; - $this->level->addEntityMovement($this->chunk->getX(), $this->chunk->getZ(), $this->id, $this->x, $this->y + $this->getEyeHeight(), $this->z, $this->yaw, $this->pitch, $this->yaw); + $this->addMovement($this->x, $this->y + $this->getEyeHeight(), $this->z, $this->yaw, $this->pitch, $this->yaw); } if($diffMotion > 0.0025 or ($diffMotion > 0.0001 and $this->getMotion()->lengthSquared() <= 0.0001)){ //0.05 ** 2 @@ -941,6 +1044,10 @@ protected function updateMovement(){ } } + public function addMovement($x, $y, $z, $yaw, $pitch, $headYaw = null){ + $this->level->addEntityMovement($this->chunk->getX(), $this->chunk->getZ(), $this->id, $x, $y, $z, $yaw, $pitch, $headYaw === null ? $yaw : $headYaw); + } + /** * @return Vector3 */ @@ -1067,7 +1174,7 @@ public function fall($fallDistance){ return; } $damage = floor($fallDistance - 3 - ($this->hasEffect(Effect::JUMP) ? $this->getEffect(Effect::JUMP)->getAmplifier() + 1 : 0)); - + //Get the block directly beneath the player's feet, check if it is a slime block if($this->getLevel()->getBlock($this->floor()->subtract(0, 1, 0)) instanceof SlimeBlock){ $damage = 0; @@ -1401,7 +1508,7 @@ public function getBlocksAround(){ return $this->blocksAround; } - protected function checkBlockCollision(){ + /*protected function checkBlockCollision(){ $vector = new Vector3(0, 0, 0); foreach($blocksaround = $this->getBlocksAround() as $block){ @@ -1415,7 +1522,7 @@ protected function checkBlockCollision(){ } if($this->getLevel()->getServer()->redstoneEnabled and !$this->isPlayer){ - /** @var \devmine\inventory\blocks\PressurePlate $block **/ + @var \devmine\inventory\blocks\PressurePlate $block foreach($this->activatedPressurePlates as $key => $block){ if(!isset($blocksaround[$key])) $block->checkActivation(); } @@ -1428,7 +1535,7 @@ protected function checkBlockCollision(){ $this->motionY += $vector->y * $d; $this->motionZ += $vector->z * $d; } - } + }*/ public function setPositionAndRotation(Vector3 $pos, $yaw, $pitch){ if($this->setPosition($pos) === true){ @@ -1540,7 +1647,7 @@ public function kill(){ $this->removeAllEffects(); $this->scheduleUpdate(); - if($this->getLevel()->getServer()->expEnabled) { + if($this->getLevel()->getServer()->expEnabled){ $exp = mt_rand($this->getDropExpMin(), $this->getDropExpMax()); if($exp > 0) $this->getLevel()->spawnXPOrb($this, $exp); } @@ -1632,16 +1739,16 @@ public function close(){ } } - if($this->getLevel()->getServer()->redstoneEnabled){ - /** @var \devmine\inventory\blocks\PressurePlate $block **/ + /*if($this->getLevel()->getServer()->redstoneEnabled){ + @var \devmine\inventory\blocks\PressurePlate $block foreach($this->activatedPressurePlates as $key => $block){ $block->checkActivation(); } - } + }*/ $this->activatedPressurePlates = []; - if($this->attributeMap != null) { + if($this->attributeMap != null){ $this->attributeMap = null; } } @@ -1773,9 +1880,9 @@ public function getDataPropertyType($id){ * @param bool $value * @param int $type */ - public function setDataFlag($propertyId, $id, $value = true, $type = self::DATA_TYPE_BYTE){ + public function setDataFlag($propertyId, $id, $value = true, $type = self::DATA_TYPE_LONG){ if($this->getDataFlag($propertyId, $id) !== $value){ - $flags = (int)$this->getDataProperty($propertyId); + $flags = (int) $this->getDataProperty($propertyId); $flags ^= 1 << $id; $this->setDataProperty($propertyId, $type, $flags); } @@ -1788,27 +1895,27 @@ public function setDataFlag($propertyId, $id, $value = true, $type = self::DATA_ * @return bool */ public function getDataFlag($propertyId, $id){ - return (((int)$this->getDataProperty($propertyId)) & (1 << $id)) > 0; + return (((int) $this->getDataProperty($propertyId)) & (1 << $id)) > 0; } public function __destruct(){ $this->close(); } - public function setepilogos($epilogosKey, epilogosValue $epilogosValue){ - $this->server->getEntityepilogos()->setepilogos($this, $epilogosKey, $epilogosValue); + public function setMetadata($metadataKey, MetadataValue $metadataValue){ + $this->server->getEntityMetadata()->setMetadata($this, $metadataKey, $metadataValue); } - public function getepilogos($epilogosKey){ - return $this->server->getEntityepilogos()->getepilogos($this, $epilogosKey); + public function getMetadata($metadataKey){ + return $this->server->getEntityMetadata()->getMetadata($this, $metadataKey); } - public function hasepilogos($epilogosKey){ - return $this->server->getEntityepilogos()->hasepilogos($this, $epilogosKey); + public function hasMetadata($metadataKey){ + return $this->server->getEntityMetadata()->hasMetadata($this, $metadataKey); } - public function removeepilogos($epilogosKey, Plugin $plugin){ - $this->server->getEntityepilogos()->removeepilogos($this, $epilogosKey, $plugin); + public function removeMetadata($metadataKey, Plugin $plugin){ + $this->server->getEntityMetadata()->removeMetadata($this, $metadataKey, $plugin); } public function __toString(){ diff --git a/src/devmine/creatures/entities/FallingSand.php b/src/devmine/creatures/entities/FallingSand.php index 21b1043..d733c4c 100644 --- a/src/devmine/creatures/entities/FallingSand.php +++ b/src/devmine/creatures/entities/FallingSand.php @@ -8,17 +8,17 @@ use devmine\inventory\blocks\Block; use devmine\inventory\blocks\Liquid; use devmine\inventory\blocks\SnowLayer; -use devmine\server\events\entity\EntityBlockChangeEvent; -use devmine\server\events\entity\EntityDamageByEntityEvent; -use devmine\server\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityBlockChangeEvent; +use devmine\events\entity\EntityDamageByEntityEvent; +use devmine\events\entity\EntityDamageEvent; use devmine\inventory\items\Item as ItemItem; -use devmine\levels\sound\AnvilFallSound; +use devmine\worlds\sound\AnvilFallSound; use devmine\server\calculations\Vector3; use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\IntTag; use devmine\server\network\protocol\AddEntityPacket; -use devmine\Player; +use devmine\creatures\player; class FallingSand extends Entity{ const NETWORK_ID = 66; @@ -38,11 +38,11 @@ class FallingSand extends Entity{ protected function initEntity(){ parent::initEntity(); - if(isset($this->namedtag->solidentityID)){ - $this->blockId = $this->namedtag["solidentityID"]; - }elseif(isset($this->namedtag->solidentity)){ - $this->blockId = $this->namedtag["solidentity"]; - $this->namedtag["solidentityID"] = new IntTag("solidentityID", $this->blockId); + if(isset($this->namedtag->TileID)){ + $this->blockId = $this->namedtag["TileID"]; + }elseif(isset($this->namedtag->Tile)){ + $this->blockId = $this->namedtag["Tile"]; + $this->namedtag["TileID"] = new IntTag("TileID", $this->blockId); } if(isset($this->namedtag->Data)){ @@ -161,7 +161,7 @@ public function getDamage(){ } public function saveNBT(){ - $this->namedtag->solidentityID = new IntTag("solidentityID", $this->blockId); + $this->namedtag->TileID = new IntTag("TileID", $this->blockId); $this->namedtag->Data = new ByteTag("Data", $this->damage); } @@ -177,7 +177,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/FishingHook.php b/src/devmine/creatures/entities/FishingHook.php index a5b87b0..6043adb 100644 --- a/src/devmine/creatures/entities/FishingHook.php +++ b/src/devmine/creatures/entities/FishingHook.php @@ -1,17 +1,36 @@ setDataProperty(FallingSand::DATA_BLOCK_INFO, self::DATA_TYPE_INT, $this->getData()); } - public function __construct(FullChunk $chunk, CompoundTag $nbt, Entity $shootingEntity = null){ + public function __construct(Chunk $chunk, CompoundTag $nbt, Entity $shootingEntity = null){ parent::__construct($chunk, $nbt, $shootingEntity); } @@ -146,7 +165,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/FlyingAnimal.php b/src/devmine/creatures/entities/FlyingAnimal.php index e52cdf6..2f4b1cd 100644 --- a/src/devmine/creatures/entities/FlyingAnimal.php +++ b/src/devmine/creatures/entities/FlyingAnimal.php @@ -1,15 +1,27 @@ closed !== false){ return false; } - if ($this->willMove(100) and $this->getLevel()->getServer()->aiEnabled) { + if ($this->willMove(100)) { if(++$this->switchDirectionTicker === $this->switchDirectionTicks){ $this->switchDirectionTicker = 0; if(mt_rand(0, 100) < 50){ @@ -105,13 +117,11 @@ private function generateRandomDirection(){ public function initEntity(){ parent::initEntity(); - if($this->getDataProperty(self::DATA_AGEABLE_FLAGS) === null){ - $this->setDataProperty(self::DATA_AGEABLE_FLAGS, self::DATA_TYPE_BYTE, 0); - } + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BABY, false); } public function isBaby(){ - return $this->getDataFlag(self::DATA_AGEABLE_FLAGS, self::DATA_FLAG_BABY); + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BABY); } public function attack($damage, EntityDamageEvent $source){ diff --git a/src/devmine/creatures/entities/Ghast.php b/src/devmine/creatures/entities/Ghast.php index d6e64b8..673de12 100644 --- a/src/devmine/creatures/entities/Ghast.php +++ b/src/devmine/creatures/entities/Ghast.php @@ -5,7 +5,7 @@ namespace devmine\creatures\entities; use devmine\server\network\protocol\AddEntityPacket; -use devmine\Player; +use devmine\creatures\player; class Ghast extends FlyingAnimal{ const NETWORK_ID = 41; @@ -35,7 +35,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/GhastFireball.php b/src/devmine/creatures/entities/GhastFireball.php new file mode 100644 index 0000000..bd1b5c9 --- /dev/null +++ b/src/devmine/creatures/entities/GhastFireball.php @@ -0,0 +1,92 @@ +isCritical = $critical; + } + + public function isExplode() : bool{ + return $this->canExplode; + } + + public function setExplode(bool $bool){ + $this->canExplode = $bool; + } + + public function onUpdate($currentTick){ + if($this->closed){ + return false; + } + + $this->timings->startTiming(); + $hasUpdate = parent::onUpdate($currentTick); + if(!$this->hadCollision and $this->isCritical){ + $this->level->addParticle(new CriticalParticle($this->add( + $this->width / 2 + mt_rand(-100, 100) / 500, + $this->height / 2 + mt_rand(-100, 100) / 500, + $this->width / 2 + mt_rand(-100, 100) / 500))); + }elseif($this->onGround){ + $this->isCritical = false; + } + + if($this->age > 1200 or $this->isCollided){ + if($this->isCollided and $this->canExplode){ + $this->server->getPluginManager()->callEvent($ev = new ExplosionPrimeEvent($this, 2.8)); + if(!$ev->isCancelled()){ + $explosion = new Explosion($this, $ev->getForce(), $this->shootingEntity); + if($ev->isBlockBreaking()){ + $explosion->explodeA(); + } + $explosion->explodeB(); + } + } + $this->kill(); + $hasUpdate = true; + } + $this->timings->stopTiming(); + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = GhastFireball::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + parent::spawnTo($player); + } + +} \ No newline at end of file diff --git a/src/devmine/creatures/entities/Guardian.php b/src/devmine/creatures/entities/Guardian.php new file mode 100644 index 0000000..e022736 --- /dev/null +++ b/src/devmine/creatures/entities/Guardian.php @@ -0,0 +1,157 @@ +setMaxHealth(30); + } + + public function getName() : string{ + return "Guardian"; + } + + public function attack($damage, EntityDamageEvent $source){ + parent::attack($damage, $source); + if($source->isCancelled()){ + return; + } + + if($source instanceof EntityDamageByEntityEvent){ + $this->swimSpeed = mt_rand(150, 350) / 2000; + $e = $source->getDamager(); + $this->swimDirection = (new Vector3($this->x - $e->x, $this->y - $e->y, $this->z - $e->z))->normalize(); + + $pk = new EntityEventPacket(); + $pk->eid = $this->getId(); + Server::broadcastPacket($this->hasSpawned, $pk); + } + } + + private function generateRandomDirection(){ + return new Vector3(mt_rand(-1000, 1000) / 1000, mt_rand(-500, 500) / 1000, mt_rand(-1000, 1000) / 1000); + } + + + public function onUpdate($currentTick){ + if($this->closed !== false){ + return false; + } + + if(++$this->switchDirectionTicker === 100){ + $this->switchDirectionTicker = 0; + if(mt_rand(0, 100) < 50){ + $this->swimDirection = null; + } + } + + $this->lastUpdate = $currentTick; + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->isAlive()){ + + if($this->y > 62 and $this->swimDirection !== null){ + $this->swimDirection->y = -0.5; + } + + $inWater = $this->isInsideOfWater(); + if(!$inWater){ + $this->motionY -= $this->gravity; + $this->swimDirection = null; + }elseif($this->swimDirection !== null){ + if($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2 <= $this->swimDirection->lengthSquared()){ + $this->motionX = $this->swimDirection->x * $this->swimSpeed; + $this->motionY = $this->swimDirection->y * $this->swimSpeed; + $this->motionZ = $this->swimDirection->z * $this->swimSpeed; + } + }else{ + $this->swimDirection = $this->generateRandomDirection(); + $this->swimSpeed = mt_rand(50, 100) / 2000; + } + + $expectedPos = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ); + + $this->move($this->motionX, $this->motionY, $this->motionZ); + + if($expectedPos->distanceSquared($this) > 0){ + $this->swimDirection = $this->generateRandomDirection(); + $this->swimSpeed = mt_rand(50, 100) / 2000; + } + + $friction = 1 - $this->drag; + + $this->motionX *= $friction; + $this->motionY *= 1 - $this->drag; + $this->motionZ *= $friction; + + $f = sqrt(($this->motionX ** 2) + ($this->motionZ ** 2)); + $this->yaw = (-atan2($this->motionX, $this->motionZ) * 180 / M_PI); + $this->pitch = (-atan2($f, $this->motionY) * 180 / M_PI); + + if($this->onGround){ + $this->motionY *= -0.5; + } + + } + + $this->timings->stopTiming(); + + return $hasUpdate or !$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + } + + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Guardian::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $drops = array(ItemItem::get(ItemItem::PRISMARINE_SHARD, 0, mt_rand(1, 2))); + $drops[] = ItemItem::get(ItemItem::RAW_FISH, 0, mt_rand(0, 1)); + return $drops; + } +} diff --git a/src/devmine/creatures/entities/Human.php b/src/devmine/creatures/entities/Human.php index ea7ad2c..21a0b0a 100644 --- a/src/devmine/creatures/entities/Human.php +++ b/src/devmine/creatures/entities/Human.php @@ -4,13 +4,18 @@ namespace devmine\creatures\entities; -use devmine\server\events\entity\EntityDamageEvent; -use devmine\server\events\entity\EntityRegainHealthEvent; -use devmine\server\events\player\PlayerExhaustEvent; +use devmine\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityRegainHealthEvent; +use devmine\events\player\PlayerExhaustEvent; +use devmine\events\player\PlayerExperienceChangeEvent; +use devmine\inventory\layout\FloatingInventory; use devmine\inventory\layout\InventoryHolder; +use devmine\inventory\layout\InventoryType; use devmine\inventory\layout\PlayerInventory; +use devmine\inventory\layout\SimpleTransactionQueue; use devmine\inventory\items\enchantment\Enchantment; use devmine\inventory\items\Item as ItemItem; +use devmine\server\calculations\Math; use devmine\creatures\player\NBT; use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\CompoundTag; @@ -21,20 +26,27 @@ use devmine\creatures\player\tag\StringTag; use devmine\server\network\protocol\AddPlayerPacket; use devmine\server\network\protocol\RemoveEntityPacket; -use devmine\Player; +use devmine\creatures\player; use devmine\utilities\main\UUID; -class Human extends Creature implements Projecsolidentitiesource, InventoryHolder{ - +class Human extends Creature implements ProjectileSource, InventoryHolder{ + const DATA_PLAYER_FLAG_SLEEP = 1; - const DATA_PLAYER_FLAG_DEAD = 2; + const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK + + const DATA_PLAYER_FLAGS = 27; - const DATA_PLAYER_FLAGS = 16; - const DATA_PLAYER_BED_POSITION = 17; + const DATA_PLAYER_BED_POSITION = 29; /** @var PlayerInventory */ protected $inventory; + /** @var FloatingInventory */ + protected $floatingInventory; + + /** @var SimpleTransactionQueue */ + protected $transactionQueue = null; + /** @var UUID */ protected $uuid; protected $rawUUID; @@ -51,6 +63,7 @@ class Human extends Creature implements Projecsolidentitiesource, InventoryHolde protected $totalXp = 0; protected $xpSeed; + protected $xpCooldown = 0; public function getSkinData(){ return $this->skin; @@ -198,49 +211,218 @@ public function getXpLevel() : int{ return (int) $this->attributeMap->getAttribute(Attribute::EXPERIENCE_LEVEL)->getValue(); } - public function setXpLevel(int $level){ - $this->attributeMap->getAttribute(Attribute::EXPERIENCE_LEVEL)->setValue($level); + public function setXpLevel(int $level) : bool{ + $this->server->getPluginManager()->callEvent($ev = new PlayerExperienceChangeEvent($this, $level, $this->getXpProgress())); + if(!$ev->isCancelled()){ + $this->attributeMap->getAttribute(Attribute::EXPERIENCE_LEVEL)->setValue($ev->getExpLevel()); + return true; + } + return false; + } + + public function addXpLevel(int $level) : bool{ + return $this->setXpLevel($this->getXpLevel() + $level); + } + + public function takeXpLevel(int $level) : bool{ + return $this->setXpLevel($this->getXpLevel() - $level); } public function getXpProgress() : float{ return $this->attributeMap->getAttribute(Attribute::EXPERIENCE)->getValue(); } - public function setXpProgress(float $progress){ + public function setXpProgress(float $progress) : bool{ $this->attributeMap->getAttribute(Attribute::EXPERIENCE)->setValue($progress); + return true; } - public function getTotalXp() : float{ + public function getTotalXp() : int{ return $this->totalXp; } + /** + * Changes the total exp of a player + * + * @param int $xp + * @param bool $syncLevel This will reset the level to be in sync with the total. Usually you don't want to do this, + * because it'll mess up use of xp in anvils and enchanting tables. + * + * @return bool + */ + public function setTotalXp(int $xp, bool $syncLevel = false) : bool{ + $xp &= 0x7fffffff; + if($xp === $this->totalXp){ + return false; + } + if(!$syncLevel){ + $level = $this->getXpLevel(); + $diff = $xp - $this->totalXp + $this->getFilledXp(); + if($diff > 0){ //adding xp + while($diff > ($v = self::getLevelXpRequirement($level))){ + $diff -= $v; + if(++$level >= 21863){ + $diff = $v; //fill exp bar + break; + } + } + }else{ //taking xp + while($diff < ($v = self::getLevelXpRequirement($level - 1))){ + $diff += $v; + if(--$level <= 0){ + $diff = 0; + break; + } + } + } + $progress = ($diff / $v); + }else{ + $values = self::getLevelFromXp($xp); + $level = $values[0]; + $progress = $values[1]; + } + + $this->server->getPluginManager()->callEvent($ev = new PlayerExperienceChangeEvent($this, $level, $progress)); + if(!$ev->isCancelled()){ + $this->totalXp = $xp; + $this->setXpLevel($ev->getExpLevel()); + $this->setXpProgress($ev->getProgress()); + return true; + } + return false; + } + + public function addXp(int $xp, bool $syncLevel = false) : bool{ + return $this->setTotalXp($this->totalXp + $xp, $syncLevel); + } + + public function takeXp(int $xp, bool $syncLevel = false) : bool{ + return $this->setTotalXp($this->totalXp - $xp, $syncLevel); + } + public function getRemainderXp() : int{ - return $this->getTotalXp() - self::getTotalXpForLevel($this->getXpLevel()); + return self::getLevelXpRequirement($this->getXpLevel()) - $this->getFilledXp(); + } + + public function getFilledXp() : int{ + return self::getLevelXpRequirement($this->getXpLevel()) * $this->getXpProgress(); } public function recalculateXpProgress() : float{ - $this->setXpProgress($this->getRemainderXp() / self::getTotalXpForLevel($this->getXpLevel())); + $this->setXpProgress($this->getRemainderXp() / self::getLevelXpRequirement($this->getXpLevel())); + } + + public function getXpSeed() : int{ + //TODO: use this for randomizing enchantments in enchanting tables + return $this->xpSeed; + } + + public function resetXpCooldown(){ + $this->xpCooldown = microtime(true); + } + + public function canPickupXp() : bool{ + return microtime(true) - $this->xpCooldown > 0.5; } - public static function getTotalXpForLevel(int $level) : int{ + /** + * Returns the total amount of exp required to reach the specified level. + * + * @param int $level + * + * @return int + */ + public static function getTotalXpRequirement(int $level) : int{ if($level <= 16){ - return $level ** 2 + $level * 6; - }elseif($level < 32){ - return $level ** 2 * 2.5 - 40.5 * $level + 360; + return ($level ** 2) + (6 * $level); + }elseif($level <= 31){ + return (2.5 * ($level ** 2)) - (40.5 * $level) + 360; + }elseif($level <= 21863){ + return (4.5 * ($level ** 2)) - (162.5 * $level) + 2220; } - return $level ** 2 * 4.5 - 162.5 * $level + 2220; + return PHP_INT_MAX; //prevent float returns for invalid levels on 32-bit systems + } + + /** + * Returns the amount of exp required to complete the specified level. + * + * @param int $level + * + * @return int + */ + public static function getLevelXpRequirement(int $level) : int{ + if($level <= 16){ + return (2 * $level) + 7; + }elseif($level <= 31){ + return (5 * $level) - 38; + }elseif($level <= 21863){ + return (9 * $level) - 158; + } + return PHP_INT_MAX; + } + + /** + * Converts a quantity of exp into a level and a progress percentage + * + * @param int $xp + * + * @return int[] + */ + public static function getLevelFromXp(int $xp) : array{ + $xp &= 0x7fffffff; + + /** These values are correct up to and including level 16 */ + $a = 1; + $b = 6; + $c = -$xp; + if($xp > self::getTotalXpRequirement(16)){ + /** Modify the coefficients to fit the relevant equation */ + if($xp <= self::getTotalXpRequirement(31)){ + /** Levels 16-31 */ + $a = 2.5; + $b = -40.5; + $c += 360; + }else{ + /** Level 32+ */ + $a = 4.5; + $b = -162.5; + $c += 2220; + } + } + + $answer = max(Math::solveQuadratic($a, $b, $c)); //Use largest result value + $level = floor($answer); + $progress = $answer - $level; + return [$level, $progress]; } public function getInventory(){ return $this->inventory; } + public function getFloatingInventory(){ + return $this->floatingInventory; + } + + public function getTransactionQueue(){ + //Is creating the transaction queue ondemand a good idea? I think only if it's destroyed afterwards. hmm... + if($this->transactionQueue === null){ + //Potential for crashes here if a plugin attempts to use this, say for an NPC plugin or something... + $this->transactionQueue = new SimpleTransactionQueue($this); + } + return $this->transactionQueue; + } + protected function initEntity(){ + $this->setDataFlag(self::DATA_PLAYER_FLAGS, self::DATA_PLAYER_FLAG_SLEEP, false, self::DATA_TYPE_BYTE); + $this->setDataProperty(self::DATA_PLAYER_BED_POSITION, self::DATA_TYPE_POS, [0, 0, 0], false); + + $inventoryContents = ($this->namedtag->Inventory ?? null); + $this->inventory = new PlayerInventory($this, $inventoryContents); - $this->setDataFlag(self::DATA_PLAYER_FLAGS, self::DATA_PLAYER_FLAG_SLEEP, false); - $this->setDataProperty(self::DATA_PLAYER_BED_POSITION, self::DATA_TYPE_POS, [0, 0, 0]); + //Virtual inventory for desktop GUI crafting and anti-cheat transaction processing + $this->floatingInventory = new FloatingInventory($this); - $this->inventory = new PlayerInventory($this); if($this instanceof Player){ $this->addWindow($this->inventory, 0); }else{ @@ -255,21 +437,10 @@ protected function initEntity(){ $this->uuid = UUID::fromData($this->getId(), $this->getSkinData(), $this->getNameTag()); } - if(isset($this->namedtag->Inventory) and $this->namedtag->Inventory instanceof ListTag){ - foreach($this->namedtag->Inventory as $item){ - if($item["Slot"] >= 0 and $item["Slot"] < $this->inventory->getHotbarSize()){ //Hotbar - $this->inventory->setHotbarSlotIndex($item["Slot"], isset($item["TrueSlot"]) ? $item["TrueSlot"] : -1); - }elseif($item["Slot"] >= 100 and $item["Slot"] < 104){ //Armor - $this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, NBT::getItemHelper($item)); - }else{ - $this->inventory->setItem($item["Slot"] - $this->inventory->getHotbarSize(), NBT::getItemHelper($item)); - } - } - } parent::initEntity(); - /*if(!isset($this->namedtag->foodLevel) or !($this->namedtag->foodLevel instanceof IntTag)){ + if(!isset($this->namedtag->foodLevel) or !($this->namedtag->foodLevel instanceof IntTag)){ $this->namedtag->foodLevel = new IntTag("foodLevel", $this->getFood()); }else{ $this->setFood($this->namedtag["foodLevel"]); @@ -291,29 +462,27 @@ protected function initEntity(){ $this->namedtag->foodTickTimer = new IntTag("foodTickTimer", $this->foodTickTimer); }else{ $this->foodTickTimer = $this->namedtag["foodTickTimer"]; - }*/ + } if(!isset($this->namedtag->XpLevel) or !($this->namedtag->XpLevel instanceof IntTag)){ - $this->namedtag->XpLevel = new IntTag("XpLevel", $this->getXpLevel()); - }else{ - $this->setXpLevel($this->namedtag["XpLevel"]); + $this->namedtag->XpLevel = new IntTag("XpLevel", 0); } + $this->setXpLevel($this->namedtag["XpLevel"]); if(!isset($this->namedtag->XpP) or !($this->namedtag->XpP instanceof FloatTag)){ - $this->namedtag->XpP = new FloatTag("XpP", $this->getXpProgress()); + $this->namedtag->XpP = new FloatTag("XpP", 0); } + $this->setXpProgress($this->namedtag["XpP"]); if(!isset($this->namedtag->XpTotal) or !($this->namedtag->XpTotal instanceof IntTag)){ - $this->namedtag->XpTotal = new IntTag("XpTotal", $this->totalXp); - }else{ - $this->totalXp = $this->namedtag["XpTotal"]; + $this->namedtag->XpTotal = new IntTag("XpTotal", 0); } + $this->totalXp = $this->namedtag["XpTotal"]; if(!isset($this->namedtag->XpSeed) or !($this->namedtag->XpSeed instanceof IntTag)){ - $this->namedtag->XpSeed = new IntTag("XpSeed", $this->xpSeed ?? ($this->xpSeed = mt_rand(PHP_INT_MIN, PHP_INT_MAX))); - }else{ - $this->xpSeed = $this->namedtag["XpSeed"]; + $this->namedtag->XpSeed = new IntTag("XpSeed", mt_rand(PHP_INT_MIN, PHP_INT_MAX)); } + $this->xpSeed = $this->namedtag["XpSeed"]; } public function getAbsorption() : int{ @@ -343,38 +512,40 @@ public function entityBaseTick($tickDiff = 1, $EnchantL = 0){ } $hasUpdate = parent::entityBaseTick($tickDiff, $EnchantL); - /*$food = $this->getFood(); - $health = $this->getHealth(); - if($food >= 18){ - $this->foodTickTimer++; - if($this->foodTickTimer >= 80 and $health < $this->getMaxHealth()){ - $this->heal(1, new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_SATURATION)); - $this->exhaust(3.0, PlayerExhaustEvent::CAUSE_HEALTH_REGEN); - $this->foodTickTimer = 0; + if($this->server->foodEnabled){ + $food = $this->getFood(); + $health = $this->getHealth(); + if($food >= 18){ + $this->foodTickTimer++; + if($this->foodTickTimer >= 80 and $health < $this->getMaxHealth()){ + $this->heal(1, new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_SATURATION)); + $this->exhaust(3.0, PlayerExhaustEvent::CAUSE_HEALTH_REGEN); + $this->foodTickTimer = 0; - } - }elseif($food === 0){ - $this->foodTickTimer++; - if($this->foodTickTimer >= 80){ - $diff = $this->server->getDifficulty(); - $can = false; - if($diff === 1){ - $can = $health > 10; - }elseif($diff === 2){ - $can = $health > 1; - }elseif($diff === 3){ - $can = true; } - if($can){ - $this->attack(1, new EntityDamageEvent($this, EntityDamageEvent::CAUSE_STARVATION, 1)); + }elseif($food === 0){ + $this->foodTickTimer++; + if($this->foodTickTimer >= 80){ + $diff = $this->server->getDifficulty(); + $can = false; + if($diff === 1){ + $can = $health > 10; + }elseif($diff === 2){ + $can = $health > 1; + }elseif($diff === 3){ + $can = true; + } + if($can){ + $this->attack(1, new EntityDamageEvent($this, EntityDamageEvent::CAUSE_STARVATION, 1)); + } } } - } - if($food <= 6){ - if($this->isSprinting()){ - $this->setSprinting(false); + if($food <= 6){ + if($this->isSprinting()){ + $this->setSprinting(false); + } } - }*/ + } return $hasUpdate; } @@ -399,41 +570,29 @@ public function saveNBT(){ $this->namedtag->Inventory = new ListTag("Inventory", []); $this->namedtag->Inventory->setTagType(NBT::TAG_Compound); if($this->inventory !== null){ - for($slot = 0; $slot < $this->inventory->getHotbarSize(); ++$slot){ - $hotbarSlot = $this->inventory->getHotbarSlotIndex($slot); - if($hotbarSlot !== -1){ - $item = $this->inventory->getItem($hotbarSlot); - if($item->getId() !== 0 and $item->getCount() > 0){ - $tag = NBT::putItemHelper($item, $slot); - $tag->TrueSlot = new ByteTag("TrueSlot", $hotbarSlot); - $this->namedtag->Inventory[$slot] = $tag; - - continue; - } - } - $this->namedtag->Inventory[$slot] = new CompoundTag("", [ - new ByteTag("Count", 0), - new ShortTag("Damage", 0), - new ByteTag("Slot", $slot), - new ByteTag("TrueSlot", -1), - new ShortTag("id", 0), - ]); + //Hotbar + for($slot = 0; $slot < $this->inventory->getHotbarSize(); ++$slot){ + $inventorySlotIndex = $this->inventory->getHotbarSlotIndex($slot); + $item = $this->inventory->getItem($inventorySlotIndex); + $tag = $item->nbtSerialize($slot); + $tag->TrueSlot = new ByteTag("TrueSlot", $inventorySlotIndex); + $this->namedtag->Inventory[$slot] = $tag; } //Normal inventory - $slotCount = $this->getLevel()->getServer()->inventoryNum + $this->inventory->getHotbarSize(); - //$slotCount = (($this instanceof Player and ($this->gamemode & 0x01) === 1) ? Player::CREATIVE_SLOTS : Player::SURVIVAL_SLOTS) + $this->inventory->getHotbarSize(); + $slotCount = $this->inventory->getSize() + $this->inventory->getHotbarSize(); for($slot = $this->inventory->getHotbarSize(); $slot < $slotCount; ++$slot){ $item = $this->inventory->getItem($slot - $this->inventory->getHotbarSize()); - $this->namedtag->Inventory[$slot] = NBT::putItemHelper($item, $slot); + //As NBT, real inventory slots are slots 9-44, NOT 0-35 + $this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot); } - //Armor + //Armour for($slot = 100; $slot < 104; ++$slot){ $item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100); if($item instanceof ItemItem and $item->getId() !== ItemItem::AIR){ - $this->namedtag->Inventory[$slot] = NBT::putItemHelper($item, $slot); + $this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot); } } } @@ -444,16 +603,28 @@ public function saveNBT(){ "Name" => new StringTag("Name", $this->getSkinId()) ]); } + + //Xp + $this->namedtag->XpLevel = new IntTag("XpLevel", $this->getXpLevel()); + $this->namedtag->XpTotal = new IntTag("XpTotal", $this->getTotalXp()); + $this->namedtag->XpP = new FloatTag("XpP", $this->getXpProgress()); + $this->namedtag->XpSeed = new IntTag("XpSeed", $this->getXpSeed()); + + //Food + $this->namedtag->foodLevel = new IntTag("foodLevel", $this->getFood()); + $this->namedtag->foodExhaustionLevel = new FloatTag("foodExhaustionLevel", $this->getExhaustion()); + $this->namedtag->foodSaturationLevel = new FloatTag("foodSaturationLevel", $this->getSaturation()); + $this->namedtag->foodTickTimer = new IntTag("foodTickTimer", $this->foodTickTimer); } public function spawnTo(Player $player){ - if($player !== $this and !isset($this->hasSpawned[$player->getLoaderId()])){ + if(strlen($this->skin) < 64 * 32 * 4){ + $e = new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set"); + $this->server->getLogger()->logException($e); + $this->close(); + }elseif($player !== $this and !isset($this->hasSpawned[$player->getLoaderId()])){ $this->hasSpawned[$player->getLoaderId()] = $player; - if(strlen($this->skin) < 64 * 32 * 4){ - throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set"); - } - if(!($this instanceof Player)){ $this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getName(), $this->skinId, $this->skin, [$player]); } @@ -471,7 +642,7 @@ public function spawnTo(Player $player){ $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; $pk->item = $this->getInventory()->getItemInHand(); - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); $this->sendLinkedData(); @@ -496,6 +667,13 @@ public function despawnFrom(Player $player){ public function close(){ if(!$this->closed){ + if($this->getFloatingInventory() instanceof FloatingInventory){ + foreach($this->getFloatingInventory()->getContents() as $craftingItem){ + $this->level->dropItem($this, $craftingItem); + } + }else{ + $this->server->getLogger()->debug("Attempted to drop a null crafting inventory\n"); + } if(!($this instanceof Player) or $this->loggedIn){ foreach($this->inventory->getViewers() as $viewer){ $viewer->removeWindow($this->inventory); diff --git a/src/devmine/creatures/entities/Husk.php b/src/devmine/creatures/entities/Husk.php index 83dd416..eb1ae9d 100644 --- a/src/devmine/creatures/entities/Husk.php +++ b/src/devmine/creatures/entities/Husk.php @@ -1,10 +1,27 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); Entity::spawnTo($player); diff --git a/src/devmine/creatures/entities/IronGolem.php b/src/devmine/creatures/entities/IronGolem.php index 0fc5aa9..5402ce1 100644 --- a/src/devmine/creatures/entities/IronGolem.php +++ b/src/devmine/creatures/entities/IronGolem.php @@ -1,11 +1,28 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Item.php b/src/devmine/creatures/entities/Item.php index fe50da1..4544b1a 100644 --- a/src/devmine/creatures/entities/Item.php +++ b/src/devmine/creatures/entities/Item.php @@ -4,10 +4,10 @@ namespace devmine\creatures\entities; -use devmine\server\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityDamageEvent; -use devmine\server\events\entity\ItemDespawnEvent; -use devmine\server\events\entity\ItemSpawnEvent; +use devmine\events\entity\ItemDespawnEvent; +use devmine\events\entity\ItemSpawnEvent; use devmine\inventory\items\Item as ItemItem; use devmine\creatures\player\NBT; @@ -17,7 +17,7 @@ use devmine\creatures\player\tag\StringTag; use devmine\server\network\Network; use devmine\server\network\protocol\AddItemEntityPacket; -use devmine\Player; +use devmine\creatures\player; class Item extends Entity{ const NETWORK_ID = 64; @@ -57,12 +57,10 @@ protected function initEntity(){ $this->close(); return; } - $this->item = NBT::getItemHelper($this->namedtag->Item); - if($this->item->getId() <= 0){ - $this->close(); - return; - } + assert($this->namedtag->Item instanceof CompoundTag); + + $this->item = ItemItem::nbtDeserialize($this->namedtag->Item); $this->server->getPluginManager()->callEvent(new ItemSpawnEvent($this)); } @@ -149,7 +147,7 @@ public function onUpdate($currentTick){ public function saveNBT(){ parent::saveNBT(); - $this->namedtag->Item = NBT::putItemHelper($this->item); + $this->namedtag->Item = $this->item->nbtSerialize(-1, "Item"); $this->namedtag->Health = new ShortTag("Health", $this->getHealth()); $this->namedtag->Age = new ShortTag("Age", $this->age); $this->namedtag->PickupDelay = new ShortTag("PickupDelay", $this->pickupDelay); diff --git a/src/devmine/creatures/entities/LavaSlime.php b/src/devmine/creatures/entities/LavaSlime.php index a00abce..900fe03 100644 --- a/src/devmine/creatures/entities/LavaSlime.php +++ b/src/devmine/creatures/entities/LavaSlime.php @@ -5,7 +5,7 @@ namespace devmine\creatures\entities; use devmine\server\network\protocol\AddEntityPacket; -use devmine\Player; +use devmine\creatures\player; class LavaSlime extends Living{ const NETWORK_ID = 42; @@ -30,7 +30,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/LeashKnot.php b/src/devmine/creatures/entities/LeashKnot.php new file mode 100644 index 0000000..2eff19a --- /dev/null +++ b/src/devmine/creatures/entities/LeashKnot.php @@ -0,0 +1,61 @@ +dropItem = $dropItem; + } + + protected function initEntity(){ + parent::initEntity(); + } + + + public function canCollideWith(Entity $entity){ + return false; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = LeashKnot::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/creatures/entities/Lightning.php b/src/devmine/creatures/entities/Lightning.php index c2b0d86..cee604a 100644 --- a/src/devmine/creatures/entities/Lightning.php +++ b/src/devmine/creatures/entities/Lightning.php @@ -1,20 +1,33 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); $pk = new ExplodePacket(); diff --git a/src/devmine/creatures/entities/Living.php b/src/devmine/creatures/entities/Living.php index 8be6cc1..8219db9 100644 --- a/src/devmine/creatures/entities/Living.php +++ b/src/devmine/creatures/entities/Living.php @@ -6,19 +6,19 @@ use devmine\inventory\blocks\Block; -use devmine\server\events\entity\EntityDamageByChildEntityEvent; -use devmine\server\events\entity\EntityDamageByEntityEvent; -use devmine\server\events\entity\EntityDamageEvent; -use devmine\server\events\entity\EntityDeathEvent; -use devmine\server\events\entity\EntityRegainHealthEvent; -use devmine\server\events\Timings; +use devmine\events\entity\EntityDamageByChildEntityEvent; +use devmine\events\entity\EntityDamageByEntityEvent; +use devmine\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityDeathEvent; +use devmine\events\entity\EntityRegainHealthEvent; +use devmine\events\Timings; use devmine\inventory\items\Item as ItemItem; use devmine\server\calculations\Vector3; use devmine\creatures\player\tag\ShortTag; use devmine\server\network\Network; use devmine\server\network\protocol\EntityEventPacket; - -use devmine\Server; +use devmine\creatures\player; +use devmine\server\server; use devmine\utilities\main\BlockIterator; abstract class Living extends Entity implements Damageable{ @@ -100,7 +100,7 @@ public function attack($damage, EntityDamageEvent $source){ $e = $source->getChild(); } - if($e->isOnFire() > 0){ + if($e->isOnFire() > 0 and !($e instanceof Player)){ $this->setOnFire(2 * $this->server->getDifficulty()); } @@ -157,6 +157,7 @@ public function kill(){ public function entityBaseTick($tickDiff = 1, $EnchantL = 0){ Timings::$timerLivingEntityBaseTick->startTiming(); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BREATHING, !$this->isInsideOfWater()); $hasUpdate = parent::entityBaseTick($tickDiff); @@ -169,7 +170,7 @@ public function entityBaseTick($tickDiff = 1, $EnchantL = 0){ if(!$this->hasEffect(Effect::WATER_BREATHING) and $this->isInsideOfWater()){ if($this instanceof WaterAnimal){ - $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 1200); + $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 400); }else{ $hasUpdate = true; $airTicks = $this->getDataProperty(self::DATA_AIR) - $tickDiff * (4 - $EnchantL); @@ -193,7 +194,7 @@ public function entityBaseTick($tickDiff = 1, $EnchantL = 0){ } $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, $airTicks); }else{ - $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 1200); + $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 400); } } } diff --git a/src/devmine/creatures/entities/Minecart.php b/src/devmine/creatures/entities/Minecart.php index 9e87f01..9a0f7af 100644 --- a/src/devmine/creatures/entities/Minecart.php +++ b/src/devmine/creatures/entities/Minecart.php @@ -1,6 +1,23 @@ setMaxHealth(1); $this->setHealth($this->getMaxHealth()); + $this->moveVector[Entity::NORTH] = new Vector3(-1, 0, 0); + $this->moveVector[Entity::SOUTH] = new Vector3(1, 0, 0); + $this->moveVector[Entity::EAST] = new Vector3(0, 0, -1); + $this->moveVector[Entity::WEST] = new Vector3(0, 0, 1); parent::initEntity(); } @@ -49,6 +80,11 @@ public function onUpdate($currentTick){ return false; } + $tickDiff = $currentTick - $this->lastUpdate; + if($tickDiff <= 1){ + return false; + } + $this->lastUpdate = $currentTick; $this->timings->startTiming(); @@ -57,74 +93,337 @@ public function onUpdate($currentTick){ //parent::onUpdate($currentTick); if($this->isAlive()){ - $movingType = $this->getLevel()->getServer()->minecartMovingType; - if($movingType == -1) return false; - elseif($movingType == 0){ - $p = $this->getLinkedEntity(); - if($p instanceof Player){ - $this->motionX = -sin($p->getYaw() / 180 * M_PI); - $this->motionZ = cos($p->getYaw() / 180 * M_PI); - } - $target = $this->getLevel()->getBlock($this->add($this->motionX, 0, $this->motionZ)->round()); - $target2 = $this->getLevel()->getBlock($this->add($this->motionX, 0, $this->motionZ)->floor()); - if($target->getId() != ItemItem::AIR or $target2->getId() != ItemItem::AIR) $this->motionY = $this->gravity * 3; - else $this->motionY -= $this->gravity; - - if($this->checkObstruction($this->x, $this->y, $this->z)){ - $hasUpdate = true; - } - - $this->move($this->motionX, $this->motionY, $this->motionZ); - $this->updateMovement(); - - $friction = 1 - $this->drag; - - if($this->onGround and (abs($this->motionX) > 0.00001 or abs($this->motionZ) > 0.00001)){ - $friction = $this->getLevel()->getBlock($this->temporalVector->setComponents((int) floor($this->x), (int) floor($this->y - 1), (int) floor($this->z) - 1))->getFrictionFactor() * $friction; - } - - $this->motionX *= $friction; - $this->motionY *= 1 - $this->drag; - $this->motionZ *= $friction; - - if($this->onGround){ - $this->motionY *= -0.5; - } - }elseif($movingType == 1){ - $p = $this->getLinkedEntity(); - if($p instanceof Player){ - $rail = $this->getNearestRail(); - if($rail !== null){ - $this->setPosition($rail); - $motX = -sin($p->getYaw() / 180 * M_PI); - $motZ = cos($p->getYaw() / 180 * M_PI); - if($motX < 0) $motX = -0.5; - elseif($motX > 0) $motX = 0.5; - if($motZ < 0) $motZ = -0.5; - elseif($motZ > 0) $motZ = 0.5; - $block = $this->getLevel()->getBlock($this->add($motX, 0, $motZ)->round()); - if($block instanceof Rail){ - if($block->check($rail)){ - if($block->y > $rail->y) $motY = 1.0; - else $motY = 0; - $f = sqrt(($motX ** 2) + ($motZ ** 2)); - $this->yaw = (-atan2($motX, $motZ) * 180 / M_PI); - $this->pitch = (-atan2($f, $motY) * 180 / M_PI); - $this->move($motX, $motY, $motZ); - } - } - $this->updateMovement(); - } + $p = $this->getLinkedEntity(); + if($p instanceof Player){ + if($this->state === Minecart::STATE_INITIAL){ + $this->checkIfOnRail(); + }elseif($this->state === Minecart::STATE_ON_RAIL){ + $hasUpdate = $this->forwardOnRail($p); + $this->updateMovement(); } - $hasUpdate = true; } } + $this->timings->stopTiming (); + + return $hasUpdate or ! $this->onGround or abs ( $this->motionX ) > 0.00001 or abs ( $this->motionY ) > 0.00001 or abs ( $this->motionZ ) > 0.00001; + } + + + /** + * Check if minecart is currently on a rail and if so center the cart. + */ + private function checkIfOnRail() { + for ($y = -1; $y !== 2 and $this->state === Minecart::STATE_INITIAL; $y++) { + $positionToCheck = $this->temporalVector->setComponents($this->x, $this->y + $y, $this->z); + $block = $this->level->getBlock($positionToCheck); + if($this->isRail($block)){ + $minecartPosition = $positionToCheck->floor()->add(0.5, 0, 0.5); + $this->setPosition($minecartPosition); // Move minecart to center of rail + $this->state = Minecart::STATE_ON_RAIL; + } + } + if($this->state !== Minecart::STATE_ON_RAIL){ + $this->state = Minecart::STATE_OFF_RAIL; + } + } + + private function isRail($rail) { + return ($rail !== null and in_array($rail->getId(), [Block::RAIL, Block::ACTIVATOR_RAIL, Block::DETECTOR_RAIL, Block::POWERED_RAIL])); + } + + private function getCurrentRail() { + $block = $this->getLevel()->getBlock($this); + if($this->isRail($block)){ + return $block; + } + // Rail could be one block below descending down + $down = $this->temporalVector->setComponents($this->x, $this->y - 1, $this->z); + $block = $this->getLevel()->getBlock($down); + if($this->isRail($block)){ + return $block; + } + return null; + } + + /** + * Attempt to move forward on rail given the direction the cart is already moving, or if not moving based + * on the direction the player is looking. + * @param Player $player Player riding the minecart. + * @return boolean True if minecart moved, false otherwise. + */ + private function forwardOnRail(Player $player) { + if($this->direction === -1){ + $candidateDirection = $player->getDirection(); + }else{ + $candidateDirection = $this->direction; + } + $rail = $this->getCurrentRail(); + if ($rail !== null) { + $railType = $rail->getDamage (); + $nextDirection = $this->getDirectionToMove($railType, $candidateDirection); + if ($nextDirection !== -1) { + $this->direction = $nextDirection; + $moved = $this->checkForVertical($railType, $nextDirection); + if(!$moved){ + return $this->moveIfRail(); + }else{ + return true; + } + }else{ + $this->direction = -1; // Was not able to determine direction to move, so wait for player to look in valid direction + } + }else{ + // Not able to find rail + $this->state = Minecart::STATE_INITIAL; + } + return false; + } + + /** + * Determine the direction the minecart should move based on the candidate direction (current direction + * minecart is moving, or the direction the player is looking) and the type of rail that the minecart is + * on. + * @param RailType $railType Type of rail the minecart is on. + * @param Direction $candidateDirection Direction minecart already moving, or direction player looking. + * @return Direction The direction the minecart should move. + */ + private function getDirectionToMove($railType, $candidateDirection) { + switch($railType){ + case Rail::STRAIGHT_NORTH_SOUTH: + case Rail::SLOPED_ASCENDING_NORTH: + case Rail::SLOPED_ASCENDING_SOUTH: + switch($candidateDirection){ + case Entity::NORTH: + case Entity::SOUTH: + return $candidateDirection; + } + break; + case Rail::STRAIGHT_EAST_WEST: + case Rail::SLOPED_ASCENDING_EAST: + case Rail::SLOPED_ASCENDING_WEST: + switch($candidateDirection){ + case Entity::WEST: + case Entity::EAST: + return $candidateDirection; + } + break; + case Rail::CURVED_SOUTH_EAST: + switch($candidateDirection){ + case Entity::SOUTH: + case Entity::EAST: + return $candidateDirection; + case Entity::NORTH: + return $this->checkForTurn($candidateDirection, Entity::EAST); + case Entity::WEST: + return $this->checkForTurn($candidateDirection, Entity::SOUTH); + } + break; + case Rail::CURVED_SOUTH_WEST: + switch($candidateDirection){ + case Entity::SOUTH: + case Entity::WEST: + return $candidateDirection; + case Entity::NORTH: + return $this->checkForTurn($candidateDirection, Entity::WEST); + case Entity::EAST: + return $this->checkForTurn($candidateDirection, Entity::SOUTH); + } + break; + case Rail::CURVED_NORTH_WEST: + switch ($candidateDirection) { + case Entity::NORTH: + case Entity::WEST: + return $candidateDirection; + case Entity::SOUTH: + return $this->checkForTurn($candidateDirection, Entity::WEST); + case Entity::EAST: + return $this->checkForTurn($candidateDirection, Entity::NORTH); + + } + break; + case Rail::CURVED_NORTH_EAST: + switch ($candidateDirection) { + case Entity::NORTH: + case Entity::EAST: + return $candidateDirection; + case Entity::SOUTH: + return $this->checkForTurn($candidateDirection, Entity::EAST); + case Entity::WEST: + return $this->checkForTurn($candidateDirection, Entity::NORTH); + } + break; + } + return -1; + } - $this->timings->stopTiming(); + /** + * Need to alter direction on curves halfway through the turn and reset the minecart to be in the middle of + * the rail again so as not to collide with nearby blocks. + * @param Direction $currentDirection Direction minecart currently moving + * @param Direction $newDirection Direction minecart should turn once has hit the halfway point. + * @return Direction Either the current direction or the new direction depending on haw far across the rail the + * minecart is. + */ + private function checkForTurn($currentDirection, $newDirection) { + switch($currentDirection) { + case Entity::NORTH: + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff <= .5) { + $dx = ($this->getFloorX() + .5) - $this->x; + $this->move($dx, 0, 0); + return $newDirection; + } + break; + case Entity::SOUTH: + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff >= .5) { + $dx = ($this->getFloorX() + .5) - $this->x; + $this->move($dx, 0, 0); + return $newDirection; + } + break; + case Entity::EAST: + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff <= .5) { + $dz = ($this->getFloorZ() + .5) - $this->z; + $this->move(0, 0, $dz); + return $newDirection; + } + break; + case Entity::WEST: + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff >= .5) { + $dz = $dz = ($this->getFloorZ() + .5) - $this->z; + $this->move(0, 0, $dz); + return $newDirection; + } + break; + } + return $currentDirection; + } - return $hasUpdate or !$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + private function checkForVertical($railType, $currentDirection) { + switch ($railType) { + case Rail::SLOPED_ASCENDING_NORTH: + switch($currentDirection){ + case Entity::NORTH: + // Headed north up + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff <= .5) { + $dx = ($this->getFloorX() - .1) - $this->x; + $this->move($dx, 1, 0); + return true; + } + break; + case ENTITY::SOUTH: + // Headed south down + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff >= .5) { + $dx = ($this->getFloorX() + 1 ) - $this->x; + $this->move($dx, -1, 0); + return true; + } + break; + } + break; + case Rail::SLOPED_ASCENDING_SOUTH: + switch($currentDirection){ + case Entity::SOUTH: + // Headed south up + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff >= .5) { + $dx = ($this->getFloorX() + 1 ) - $this->x; + $this->move($dx, 1, 0); + return true; + } + break; + case Entity::NORTH: + // Headed north down + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff <= .5) { + $dx = ($this->getFloorX() - .1) - $this->x; + $this->move($dx, -1, 0); + return true; + } + break; + } + break; + case Rail::SLOPED_ASCENDING_EAST: + switch($currentDirection){ + case Entity::EAST: + // Headed east up + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff <= .5) { + $dz = ($this->getFloorZ() - .1) - $this->z; + $this->move(0, 1, $dz); + return true; + } + break; + case Entity::WEST: + // Headed west down + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff >= .5) { + $dz = ($this->getFloorZ() + 1) - $this->z; + $this->move(0, -1, $dz); + return true; + } + break; + } + break; + case Rail::SLOPED_ASCENDING_WEST: + switch($currentDirection){ + case Entity::WEST: + // Headed west up + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff >= .5) { + $dz = ($this->getFloorZ() + 1) - $this->z; + $this->move(0, 1, $dz); + return true; + } + break; + case Entity::EAST: + // Headed east down + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff <= .5) { + $dz = ($this->getFloorZ() - .1) - $this->z; + $this->move(0, -1, $dz); + return true; + } + break; + } + break; + } + return false; + } + + /** + * Move the minecart as long as it will still be moving on to another piece of rail. + * @return boolean True if the minecart moved. + */ + private function moveIfRail(){ + $nextMoveVector = $this->moveVector[$this->direction]; + $nextMoveVector = $nextMoveVector->multiply($this->moveSpeed); + $newVector = $this->add($nextMoveVector->x, $nextMoveVector->y, $nextMoveVector->z); + $possibleRail = $this->getCurrentRail(); + if(in_array($possibleRail->getId(), [Block::RAIL, Block::ACTIVATOR_RAIL, Block::DETECTOR_RAIL, Block::POWERED_RAIL])) { + $this->moveUsingVector($newVector); + return true; + } } + /** + * Invoke the normal move code, but first need to convert the desired position vector into the + * delta values from the current position. + * @param Vector3 $desiredPosition + */ + private function moveUsingVector(Vector3 $desiredPosition){ + $dx = $desiredPosition->x - $this->x; + $dy = $desiredPosition->y - $this->y; + $dz = $desiredPosition->z - $this->z; + $this->move($dx, $dy, $dz); + } + + /** * @return Rail */ @@ -171,7 +470,7 @@ public function spawnTo(Player $player){ $pk->speedZ = 0; $pk->yaw = 0; $pk->pitch = 0; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/MinecartChest.php b/src/devmine/creatures/entities/MinecartChest.php index 3fd5700..9a45075 100644 --- a/src/devmine/creatures/entities/MinecartChest.php +++ b/src/devmine/creatures/entities/MinecartChest.php @@ -1,11 +1,28 @@ speedZ = 0; $pk->yaw = 0; $pk->pitch = 0; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); Entity::spawnTo($player); diff --git a/src/devmine/creatures/entities/MinecartHopper.php b/src/devmine/creatures/entities/MinecartHopper.php index 423836b..1d51587 100644 --- a/src/devmine/creatures/entities/MinecartHopper.php +++ b/src/devmine/creatures/entities/MinecartHopper.php @@ -1,11 +1,28 @@ speedZ = 0; $pk->yaw = 0; $pk->pitch = 0; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); Entity::spawnTo($player); diff --git a/src/devmine/creatures/entities/MinecartTNT.php b/src/devmine/creatures/entities/MinecartTNT.php index 418b662..3522357 100644 --- a/src/devmine/creatures/entities/MinecartTNT.php +++ b/src/devmine/creatures/entities/MinecartTNT.php @@ -1,11 +1,28 @@ speedZ = 0; $pk->yaw = 0; $pk->pitch = 0; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); Entity::spawnTo($player); diff --git a/src/devmine/creatures/entities/Mooshroom.php b/src/devmine/creatures/entities/Mooshroom.php index e36c34f..5a4d95c 100644 --- a/src/devmine/creatures/entities/Mooshroom.php +++ b/src/devmine/creatures/entities/Mooshroom.php @@ -1,13 +1,30 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Ocelot.php b/src/devmine/creatures/entities/Ocelot.php index 75ed590..cb59db3 100644 --- a/src/devmine/creatures/entities/Ocelot.php +++ b/src/devmine/creatures/entities/Ocelot.php @@ -1,18 +1,31 @@ CatType)){ $nbt->CatType = new ByteTag("CatType", mt_rand(0, 3)); } @@ -63,7 +76,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Painting.php b/src/devmine/creatures/entities/Painting.php index d8d8632..2ac549c 100644 --- a/src/devmine/creatures/entities/Painting.php +++ b/src/devmine/creatures/entities/Painting.php @@ -7,10 +7,12 @@ namespace devmine\creatures\entities; -use devmine\server\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityDamageEvent; use devmine\server\network\protocol\AddPaintingPacket; use devmine\inventory\items\Item as ItemItem; -use devmine\Player; +use devmine\creatures\player; +use devmine\worlds\particle\DestroyBlockParticle; +use devmine\inventory\blocks\Block; class Painting extends Hanging{ const NETWORK_ID = 83; @@ -28,8 +30,9 @@ public function initEntity(){ public function attack($damage, EntityDamageEvent $source){ parent::attack($damage, $source); - - $this->close(); + if($source->isCancelled()) return false; + $this->level->addParticle(new DestroyBlockParticle($this->add(0.5), Block::get(Block::LADDER))); + $this->kill(); } public function spawnTo(Player $player){ @@ -45,6 +48,10 @@ public function spawnTo(Player $player){ parent::spawnTo($player); } + protected function updateMovement(){ + //Nothing to update, paintings cannot move. + } + public function getDrops(){ return [ItemItem::get(ItemItem::PAINTING, 0, 1)]; } diff --git a/src/devmine/creatures/entities/Pig.php b/src/devmine/creatures/entities/Pig.php index 04f2d71..87ef364 100644 --- a/src/devmine/creatures/entities/Pig.php +++ b/src/devmine/creatures/entities/Pig.php @@ -1,13 +1,30 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/PigZombie.php b/src/devmine/creatures/entities/PigZombie.php index 5f7a3db..db3e38a 100644 --- a/src/devmine/creatures/entities/PigZombie.php +++ b/src/devmine/creatures/entities/PigZombie.php @@ -6,8 +6,8 @@ use devmine\server\network\protocol\AddEntityPacket; use devmine\server\network\protocol\MobEquipmentPacket; -use devmine\server\events\entity\EntityDamageByEntityEvent; -use devmine\Player; +use devmine\events\entity\EntityDamageByEntityEvent; +use devmine\creatures\player; use devmine\inventory\items\Item as ItemItem; use devmine\inventory\items\enchantment\Enchantment; @@ -39,7 +39,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/PolarBear.php b/src/devmine/creatures/entities/PolarBear.php new file mode 100644 index 0000000..be6e7f8 --- /dev/null +++ b/src/devmine/creatures/entities/PolarBear.php @@ -0,0 +1,62 @@ +setMaxHealth(30); + return "Polar Bear"; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = PolarBear::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $cause = $this->lastDamageCause; + $drops = []; + if($cause instanceof EntityDamageByEntityEvent and $cause->getDamager() instanceof Player){ + $drops = []; + if (mt_rand(1, 4) === 1) { + $drops[] = ItemItem::get(ItemItem::RAW_SALMON, 0, mt_rand(0, 2));//yes.. 0,2 + } else { + $drops[] = ItemItem::get(ItemItem::RAW_FISH, 0, mt_rand(0, 2));//yes.. 0,2 + } + } + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/creatures/entities/PrimedTNT.php b/src/devmine/creatures/entities/PrimedTNT.php index 0a4e370..6498919 100644 --- a/src/devmine/creatures/entities/PrimedTNT.php +++ b/src/devmine/creatures/entities/PrimedTNT.php @@ -5,16 +5,16 @@ namespace devmine\creatures\entities; -use devmine\server\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityDamageEvent; -use devmine\server\events\entity\ExplosionPrimeEvent; -use devmine\levels\Explosion; -use devmine\levels\format\FullChunk; +use devmine\events\entity\ExplosionPrimeEvent; +use devmine\worlds\Explosion; +use devmine\worlds\format\Chunk; use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\CompoundTag; use devmine\server\network\Network; use devmine\server\network\protocol\AddEntityPacket; -use devmine\Player; +use devmine\creatures\player; class PrimedTNT extends Entity implements Explosive{ const NETWORK_ID = 65; @@ -32,7 +32,7 @@ class PrimedTNT extends Entity implements Explosive{ private $dropItem = true; - public function __construct(FullChunk $chunk, CompoundTag $nbt, bool $dropItem = true){ + public function __construct(Chunk $chunk, CompoundTag $nbt, bool $dropItem = true){ parent::__construct($chunk, $nbt); $this->dropItem = $dropItem; } @@ -135,7 +135,7 @@ public function spawnTo(Player $player){ $pk->speedX = $this->motionX; $pk->speedY = $this->motionY; $pk->speedZ = $this->motionZ; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Projectile.php b/src/devmine/creatures/entities/Projectile.php index 47d0159..ad2841c 100644 --- a/src/devmine/creatures/entities/Projectile.php +++ b/src/devmine/creatures/entities/Projectile.php @@ -5,20 +5,20 @@ namespace devmine\creatures\entities; -use devmine\server\events\entity\EntityCombustByEntityEvent; -use devmine\server\events\entity\EntityDamageByChildEntityEvent; -use devmine\server\events\entity\EntityDamageByEntityEvent; -use devmine\server\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityCombustByEntityEvent; +use devmine\events\entity\EntityDamageByChildEntityEvent; +use devmine\events\entity\EntityDamageByEntityEvent; +use devmine\events\entity\EntityDamageEvent; -use devmine\server\events\entity\ProjecsolidentityHitEvent; +use devmine\events\entity\ProjectileHitEvent; use devmine\inventory\items\Potion; -use devmine\levels\format\FullChunk; -use devmine\levels\MovingObjectPosition; +use devmine\worlds\format\Chunk; +use devmine\worlds\MovingObjectPosition; use devmine\server\calculations\Vector3; use devmine\creatures\player\tag\CompoundTag; use devmine\creatures\player\tag\ShortTag; -abstract class Projecsolidentity extends Entity{ +abstract class Projectile extends Entity{ const DATA_SHOOTER_ID = 17; @@ -28,7 +28,7 @@ abstract class Projecsolidentity extends Entity{ public $hadCollision = false; - public function __construct(FullChunk $chunk, CompoundTag $nbt, Entity $shootingEntity = null){ + public function __construct(Chunk $chunk, CompoundTag $nbt, Entity $shootingEntity = null){ $this->shootingEntity = $shootingEntity; if($shootingEntity !== null){ $this->setDataProperty(self::DATA_SHOOTER_ID, self::DATA_TYPE_LONG, $shootingEntity->getId()); @@ -120,7 +120,7 @@ public function onUpdate($currentTick){ if($movingObjectPosition !== null){ if($movingObjectPosition->entityHit !== null){ - $this->server->getPluginManager()->callEvent(new ProjecsolidentityHitEvent($this)); + $this->server->getPluginManager()->callEvent(new ProjectileHitEvent($this)); $motion = sqrt($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2); $damage = ceil($motion * $this->damage); @@ -130,9 +130,9 @@ public function onUpdate($currentTick){ } if($this->shootingEntity === null){ - $ev = new EntityDamageByEntityEvent($this, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECsolidentity, $damage); + $ev = new EntityDamageByEntityEvent($this, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage); }else{ - $ev = new EntityDamageByChildEntityEvent($this->shootingEntity, $this, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECsolidentity, $damage); + $ev = new EntityDamageByChildEntityEvent($this->shootingEntity, $this, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage); } if($movingObjectPosition->entityHit->attack($ev->getFinalDamage(), $ev) === true){ @@ -159,7 +159,7 @@ public function onUpdate($currentTick){ } } - $this->move($this->motionX,$this->motionY, $this->motionZ); + $this->move($this->motionX, $this->motionY, $this->motionZ); if($this->isCollided and !$this->hadCollision){ $this->hadCollision = true; @@ -168,7 +168,7 @@ public function onUpdate($currentTick){ $this->motionY = 0; $this->motionZ = 0; - $this->server->getPluginManager()->callEvent(new ProjecsolidentityHitEvent($this)); + $this->server->getPluginManager()->callEvent(new ProjectileHitEvent($this)); }elseif(!$this->isCollided and $this->hadCollision){ $this->hadCollision = false; } diff --git a/src/devmine/creatures/entities/ProjectileSource.php b/src/devmine/creatures/entities/ProjectileSource.php index fdb9c9e..872699e 100644 --- a/src/devmine/creatures/entities/ProjectileSource.php +++ b/src/devmine/creatures/entities/ProjectileSource.php @@ -5,6 +5,6 @@ namespace devmine\creatures\entities; -interface Projecsolidentitiesource{ +interface ProjectileSource{ } \ No newline at end of file diff --git a/src/devmine/creatures/entities/Rabbit.php b/src/devmine/creatures/entities/Rabbit.php index be97871..d49a7d3 100644 --- a/src/devmine/creatures/entities/Rabbit.php +++ b/src/devmine/creatures/entities/Rabbit.php @@ -1,18 +1,35 @@ RabbitType)){ $nbt->RabbitType = new ByteTag("RabbitType", $this->getRandomRabbitType()); } @@ -77,7 +94,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Sheep.php b/src/devmine/creatures/entities/Sheep.php index b8199c9..ad3a0ea 100644 --- a/src/devmine/creatures/entities/Sheep.php +++ b/src/devmine/creatures/entities/Sheep.php @@ -1,9 +1,22 @@ Color)){ $nbt->Color = new ByteTag("Color", self::getRandomColor()); } @@ -55,7 +68,7 @@ public static function getRandomColor() : int{ $rand .= str_repeat(Wool::RED . " ", 5); $rand .= str_repeat(Wool::BLACK . " ", 10); $arr = explode(" ", $rand); - return $arr[mt_rand(0, count($arr) - 1)]; + return intval($arr[mt_rand(0, count($arr) - 1)]); } public function getColor() : int{ @@ -78,7 +91,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Shulker.php b/src/devmine/creatures/entities/Shulker.php new file mode 100644 index 0000000..9fa6944 --- /dev/null +++ b/src/devmine/creatures/entities/Shulker.php @@ -0,0 +1,66 @@ +eid = $this->getId(); + $pk->type = Shulker::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + parent::spawnTo($player); + } + + public function getDrops(){ + $drops = []; + if ($this->lastDamageCause instanceof EntityDamageByEntityEvent and $this->lastDamageCause->getEntity() instanceof Player) { + if (mt_rand(0, 1) === 1) $drops[] = ItemItem::get(ItemItem::SHULKER_SHELL, 0, 1); + } + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/creatures/entities/ShulkerBullet.php b/src/devmine/creatures/entities/ShulkerBullet.php new file mode 100644 index 0000000..1047893 --- /dev/null +++ b/src/devmine/creatures/entities/ShulkerBullet.php @@ -0,0 +1,61 @@ +closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = ShulkerBullet::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/creatures/entities/Silverfish.php b/src/devmine/creatures/entities/Silverfish.php index 0478b95..2cb8959 100644 --- a/src/devmine/creatures/entities/Silverfish.php +++ b/src/devmine/creatures/entities/Silverfish.php @@ -5,7 +5,7 @@ namespace devmine\creatures\entities; use devmine\server\network\protocol\AddEntityPacket; -use devmine\Player; +use devmine\creatures\player; class Silverfish extends Monster{ const NETWORK_ID = 39; @@ -28,7 +28,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Skeleton.php b/src/devmine/creatures/entities/Skeleton.php index 2bc0781..7ee539d 100644 --- a/src/devmine/creatures/entities/Skeleton.php +++ b/src/devmine/creatures/entities/Skeleton.php @@ -1,20 +1,33 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Slime.php b/src/devmine/creatures/entities/Slime.php index da3ab5e..b38598a 100644 --- a/src/devmine/creatures/entities/Slime.php +++ b/src/devmine/creatures/entities/Slime.php @@ -1,16 +1,29 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); } diff --git a/src/devmine/creatures/entities/SnowGolem.php b/src/devmine/creatures/entities/SnowGolem.php index 1ddfa22..1fab7da 100644 --- a/src/devmine/creatures/entities/SnowGolem.php +++ b/src/devmine/creatures/entities/SnowGolem.php @@ -1,15 +1,28 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Snowball.php b/src/devmine/creatures/entities/Snowball.php index c0ab4a0..4d35523 100644 --- a/src/devmine/creatures/entities/Snowball.php +++ b/src/devmine/creatures/entities/Snowball.php @@ -5,13 +5,12 @@ namespace devmine\creatures\entities; -use devmine\levels\format\FullChunk; +use devmine\worlds\format\Chunk; use devmine\creatures\player\tag\CompoundTag; -use devmine\server\network\Network; use devmine\server\network\protocol\AddEntityPacket; -use devmine\Player; +use devmine\creatures\player; -class Snowball extends Projecsolidentity{ +class Snowball extends Projectile{ const NETWORK_ID = 81; public $width = 0.25; @@ -21,7 +20,7 @@ class Snowball extends Projecsolidentity{ protected $gravity = 0.03; protected $drag = 0.01; - public function __construct(FullChunk $chunk, CompoundTag $nbt, Entity $shootingEntity = null){ + public function __construct(Chunk $chunk, CompoundTag $nbt, Entity $shootingEntity = null){ parent::__construct($chunk, $nbt, $shootingEntity); } @@ -54,7 +53,7 @@ public function spawnTo(Player $player){ $pk->speedX = $this->motionX; $pk->speedY = $this->motionY; $pk->speedZ = $this->motionZ; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Spider.php b/src/devmine/creatures/entities/Spider.php index e8c088a..54175ac 100644 --- a/src/devmine/creatures/entities/Spider.php +++ b/src/devmine/creatures/entities/Spider.php @@ -1,16 +1,29 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); diff --git a/src/devmine/creatures/entities/Squid.php b/src/devmine/creatures/entities/Squid.php index 6edb1e9..8a0aa48 100644 --- a/src/devmine/creatures/entities/Squid.php +++ b/src/devmine/creatures/entities/Squid.php @@ -5,15 +5,15 @@ namespace devmine\creatures\entities; use devmine\inventory\items\enchantment\Enchantment; -use devmine\server\events\entity\EntityDamageByEntityEvent; -use devmine\server\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityDamageByEntityEvent; +use devmine\events\entity\EntityDamageEvent; use devmine\inventory\items\Item as ItemItem; use devmine\server\calculations\Vector3; use devmine\server\network\Network; use devmine\server\network\protocol\AddEntityPacket; use devmine\server\network\protocol\EntityEventPacket; -use devmine\Player; -use devmine\Server; +use devmine\creatures\player; +use devmine\server\server; class Squid extends WaterAnimal implements Ageable{ const NETWORK_ID = 17; @@ -144,7 +144,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Stray.php b/src/devmine/creatures/entities/Stray.php index bb64efe..95ca569 100644 --- a/src/devmine/creatures/entities/Stray.php +++ b/src/devmine/creatures/entities/Stray.php @@ -1,12 +1,29 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); Entity::spawnTo($player); diff --git a/src/devmine/creatures/entities/ThrownExpBottle.php b/src/devmine/creatures/entities/ThrownExpBottle.php index 56474b7..df1ab04 100644 --- a/src/devmine/creatures/entities/ThrownExpBottle.php +++ b/src/devmine/creatures/entities/ThrownExpBottle.php @@ -1,17 +1,34 @@ speedX = $this->motionX; $pk->speedY = $this->motionY; $pk->speedZ = $this->motionZ; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/ThrownPotion.php b/src/devmine/creatures/entities/ThrownPotion.php index 64237c2..ad4643b 100644 --- a/src/devmine/creatures/entities/ThrownPotion.php +++ b/src/devmine/creatures/entities/ThrownPotion.php @@ -1,18 +1,35 @@ PotionId)){ $nbt->PotionId = new ShortTag("PotionId", Potion::AWKWARD); } @@ -34,24 +51,26 @@ public function __construct(FullChunk $chunk, CompoundTag $nbt, Entity $shooting unset($this->dataProperties[self::DATA_SHOOTER_ID]); $this->setDataProperty(self::DATA_POTION_ID, self::DATA_TYPE_SHORT, $this->getPotionId()); } - + public function getPotionId() : int{ return (int) $this->namedtag["PotionId"]; } - + public function kill(){ - $color = Potion::getColor($this->getPotionId()); - $this->getLevel()->addParticle(new SpellParticle($this, $color[0], $color[1], $color[2])); - $players = $this->getViewers(); - foreach($players as $p) { - if($p->distance($this) <= 6){ - foreach(Potion::getEffectsById($this->getPotionId()) as $effect){ - $p->addEffect($effect); + if($this->isAlive()) { + $color = Potion::getColor($this->getPotionId()); + $this->getLevel()->addParticle(new SpellParticle($this, $color[0], $color[1], $color[2])); + $players = $this->getViewers(); + foreach($players as $p) { + if($p->distance($this) <= 6) { + foreach(Potion::getEffectsById($this->getPotionId()) as $effect) { + $p->addEffect($effect); + } } } + + parent::kill(); } - - parent::kill(); } public function onUpdate($currentTick){ @@ -70,11 +89,6 @@ public function onUpdate($currentTick){ $this->close(); $hasUpdate = true; } - - if($this->onGround) { - $this->kill(); - $this->close(); - } $this->timings->stopTiming(); @@ -91,7 +105,7 @@ public function spawnTo(Player $player){ $pk->speedX = $this->motionX; $pk->speedY = $this->motionY; $pk->speedZ = $this->motionZ; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Villager.php b/src/devmine/creatures/entities/Villager.php index a6baa29..f506cd3 100644 --- a/src/devmine/creatures/entities/Villager.php +++ b/src/devmine/creatures/entities/Villager.php @@ -6,10 +6,10 @@ use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\IntTag; -use devmine\levels\format\FullChunk; +use devmine\worlds\format\Chunk; use devmine\creatures\player\tag\CompoundTag; use devmine\server\network\protocol\AddEntityPacket; -use devmine\Player; +use devmine\creatures\player; class Villager extends Creature implements NPC, Ageable{ const PROFESSION_FARMER = 0; @@ -31,7 +31,7 @@ public function getName() : string{ return "Villager"; } - public function __construct(FullChunk $chunk, CompoundTag $nbt){ + public function __construct(Chunk $chunk, CompoundTag $nbt){ if(!isset($nbt->Profession)){ $nbt->Profession = new ByteTag("Profession", mt_rand(0, 4)); } @@ -60,7 +60,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); @@ -81,6 +81,6 @@ public function getProfession() : int{ } public function isBaby(){ - return $this->getDataFlag(self::DATA_AGEABLE_FLAGS, self::DATA_FLAG_BABY); + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BABY); } } diff --git a/src/devmine/creatures/entities/WaterAnimal.php b/src/devmine/creatures/entities/WaterAnimal.php index fc43967..8b0e772 100644 --- a/src/devmine/creatures/entities/WaterAnimal.php +++ b/src/devmine/creatures/entities/WaterAnimal.php @@ -5,14 +5,8 @@ namespace devmine\creatures\entities; abstract class WaterAnimal extends Creature implements Ageable{ - public function initEntity(){ - parent::initEntity(); - if($this->getDataProperty(self::DATA_AGEABLE_FLAGS) === null){ - $this->setDataProperty(self::DATA_AGEABLE_FLAGS, self::DATA_TYPE_BYTE, 0); - } - } public function isBaby(){ - return $this->getDataFlag(self::DATA_AGEABLE_FLAGS, self::DATA_FLAG_BABY); + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BABY); } } diff --git a/src/devmine/creatures/entities/Witch.php b/src/devmine/creatures/entities/Witch.php index 0eca92c..5093699 100644 --- a/src/devmine/creatures/entities/Witch.php +++ b/src/devmine/creatures/entities/Witch.php @@ -1,8 +1,27 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); } diff --git a/src/devmine/creatures/entities/Wither.php b/src/devmine/creatures/entities/Wither.php new file mode 100644 index 0000000..1fc9288 --- /dev/null +++ b/src/devmine/creatures/entities/Wither.php @@ -0,0 +1,53 @@ +setMaxHealth(300); + parent::initEntity(); + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Wither::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + //TODO: Add his spawn scenario and his death scenario + + public function getDrops(){ + $drops = [ItemItem::get(ItemItem::NETHER_STAR, 0, 1)]; + return $drops; + } +} diff --git a/src/devmine/creatures/entities/WitherSkeleton.php b/src/devmine/creatures/entities/WitherSkeleton.php new file mode 100644 index 0000000..bfc2293 --- /dev/null +++ b/src/devmine/creatures/entities/WitherSkeleton.php @@ -0,0 +1,46 @@ +eid = $this->getId(); + $pk->type = WitherSkeleton::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + + $pk = new MobEquipmentPacket(); + $pk->eid = $this->getId(); + $pk->item = new ItemItem(ItemItem::STONE_SWORD); + $pk->slot = 0; + $pk->selectedSlot = 0; + + $player->dataPacket($pk); + } +} \ No newline at end of file diff --git a/src/devmine/creatures/entities/Wolf.php b/src/devmine/creatures/entities/Wolf.php index bc360f8..c4dbf8e 100644 --- a/src/devmine/creatures/entities/Wolf.php +++ b/src/devmine/creatures/entities/Wolf.php @@ -1,15 +1,28 @@ speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/XPOrb.php b/src/devmine/creatures/entities/XPOrb.php index f32db84..345b050 100644 --- a/src/devmine/creatures/entities/XPOrb.php +++ b/src/devmine/creatures/entities/XPOrb.php @@ -1,12 +1,30 @@ getLevel()->getEntities() as $e){ - if($e instanceof Player and !$e->isSpectator()){ - if($e->distance($this) <= $minDistance) { - $expectedPos = $e; - $minDistance = $e->distance($this); + $target = null; + foreach($this->getViewers() as $p){ + if(!$p->isSpectator() and $p->isAlive()){ + if(($dist = $p->distance($this)) < $minDistance and $dist < $this->range){ + $target = $p; + $minDistance = $dist; } } } - - if($minDistance < PHP_INT_MAX){ + + if($target !== null){ $moveSpeed = 0.7; - $motX = ($expectedPos->getX() - $this->x) / 8; - $motY = ($expectedPos->getY() + $expectedPos->getEyeHeight() - $this->y) / 8; - $motZ = ($expectedPos->getZ() - $this->z) / 8; + $motX = ($target->getX() - $this->x) / 8; + $motY = ($target->getY() + $target->getEyeHeight() - $this->y) / 8; + $motZ = ($target->getZ() - $this->z) / 8; $motSqrt = sqrt($motX * $motX + $motY * $motY + $motZ * $motZ); $motC = 1 - $motSqrt; @@ -81,17 +101,20 @@ public function onUpdate($currentTick){ } if($this->isInsideOfSolid()){ - $this->setPosition($expectedPos); + $this->setPosition($target); } if($minDistance <= 1.3){ - if($this->getLevel()->getServer()->expEnabled){ - if($this->getExperience() > 0){ + if($this->getLevel()->getServer()->expEnabled and $target->canPickupXp()){ + $this->getLevel()->getServer()->getPluginManager()->callEvent($ev = new PlayerPickupExpOrbEvent($target, $this->getExperience())); + if(!$ev->isCancelled()){ $this->kill(); $this->close(); - - $this->getLevel()->getServer()->getPluginManager()->callEvent($ev = new PlayerPickupExpOrbEvent($expectedPos, $this->getExperience())); - if(!$ev->isCancelled()) $expectedPos->addExperience($this->getExperience()); + if($this->getExperience() > 0){ + $this->level->addSound(new ExpPickupSound($target, mt_rand(0, 1000))); + $target->addXp($this->getExperience()); + $target->resetXpCooldown(); + } } } } @@ -119,7 +142,7 @@ public function getExperience(){ } public function spawnTo(Player $player){ - $this->setDataProperty(self::DATA_NO_AI, self::DATA_TYPE_BYTE, 1); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_NO_AI, true); $pk = new AddEntityPacket(); $pk->type = XPOrb::NETWORK_ID; $pk->eid = $this->getId(); @@ -129,7 +152,7 @@ public function spawnTo(Player $player){ $pk->speedX = $this->motionX; $pk->speedY = $this->motionY; $pk->speedZ = $this->motionZ; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/Zombie.php b/src/devmine/creatures/entities/Zombie.php index 47c3284..128ea98 100644 --- a/src/devmine/creatures/entities/Zombie.php +++ b/src/devmine/creatures/entities/Zombie.php @@ -5,14 +5,14 @@ namespace devmine\creatures\entities; -use devmine\server\events\entity\EntityDamageByEntityEvent; +use devmine\events\entity\EntityDamageByEntityEvent; use devmine\inventory\items\Item as ItemItem; use devmine\inventory\items\enchantment\Enchantment; use devmine\server\network\Network; use devmine\server\network\protocol\AddEntityPacket; -use devmine\Player; +use devmine\creatures\player; use devmine\server\calculations\Vector3; -use devmine\server\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityDamageEvent; class Zombie extends Monster{ const NETWORK_ID = 32; @@ -103,7 +103,7 @@ public function onUpdate($currentTick){ return false; } - if($this->getLevel()->getServer()->aiConfig["zombie"] != 2) return parent::onUpdate($currentTick); + return parent::onUpdate($currentTick); $this->lastUpdate = $currentTick; @@ -209,7 +209,7 @@ public function spawnTo(Player $player){ $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/ZombieVillager.php b/src/devmine/creatures/entities/ZombieVillager.php index b666d9c..7b3f7e6 100644 --- a/src/devmine/creatures/entities/ZombieVillager.php +++ b/src/devmine/creatures/entities/ZombieVillager.php @@ -1,14 +1,27 @@ speedX = $this->motionX; $pk->speedY = $this->motionY; $pk->speedZ = $this->motionZ; - $pk->epilogos = $this->dataProperties; + $pk->metadata = $this->dataProperties; $player->dataPacket($pk); parent::spawnTo($player); diff --git a/src/devmine/creatures/entities/ai/AIHolder.php b/src/devmine/creatures/entities/ai/AIHolder.php deleted file mode 100644 index e78b384..0000000 --- a/src/devmine/creatures/entities/ai/AIHolder.php +++ /dev/null @@ -1,1008 +0,0 @@ -server; - } - - public function __construct(Server $server){ - $this->server = $server; - - if($this->server->aiConfig["mobgenerate"]){ - $this->tasks['ZombieGenerate'] = $this->getServer()->getScheduler()->scheduleRepeatingTask(new CallbackTask([ - $this, - "MobGenerate" - ]), 20 * 45); - } - - - /*$this->getServer()->getScheduler()->scheduleRepeatingTask(new CallbackTask([ - $this, - "TimeFix" - ]), 20);*/ - - $this->getServer()->getScheduler()->scheduleRepeatingTask(new CallbackTask ([$this, "RotationTimer"]), 2); - - $this->ZombieAI = new ZombieAI($this); - $this->CowAI = new CowAI($this); - //$this->PigAI = new PigAI($this); - //$this->SheepAI = new SheepAI($this); - //TODO: improve AIs below - $this->ChickenAI = new ChickenAI($this); - $this->CreeperAI = new CreeperAI($this); - $this->SkeletonAI = new SkeletonAI($this); - - $this->IronGolemAI = new IronGolemAI($this); - //$this->PigZombieAI = new PigZombieAI($this); - } - - /* - ************ API 部分 ************************************ - */ - - /** - * @param $r - * 设置僵尸仇恨半径 - */ - public function setZombieHatred_r($r){ - $this->ZombieAI->hatred_r = $r; - } - - /** - * @param $r - * 设置夜晚刷僵尸范围(以每个玩家为中心) - */ - public function setZombieBirth_r($r){ - $this->birth_r = $r; - } - - /** - * @param $v - * 设置僵尸仇恨模式下的走路速度 - */ - public function setZombieHate_v($v){ - $this->ZombieAI->zo_hate_v = $v; - } - - /** - * @param $tick - * @return bool - * 重新启动刷怪计时器 - * (可用于更改刷怪时间间隔) - */ - public function RestartSpawnTimer($tick = 600){ - $task = $this->tasks['ZombieGenerate']; - if($task instanceof TaskHandler){ - //TODO 没试验过是否有效。。。 - $task->cancel(); - $task->run($tick); - return true; - }else{ - return false; - } - } - - /** - * @return bool - * 停止刷怪计时器 - */ - public function CancelSpawnTimer(){ - $task = $this->tasks['ZombieGenerate']; - if($task instanceof TaskHandler){ - $task->cancel(); - return true; - }else{ - return false; - } - } - - public function TimeFix(){ - foreach($this->getServer()->getLevels() as $level){ - if($level->getTime() > 24000){ - $level->setTime(0); - } - } - } - - /** - * @param Position $pos 出生位置坐标(世界) - * @param int $maxHealth 最高血量 - * @param int $health 血量 - * 出生一只僵尸在某坐标 - */ - public function spawnZombie(Position $pos, $maxHealth = 20, $health = 20){ - $this->getZombie($pos, $maxHealth, $health)->spawnToAll(); - //$this->getLogger()->info("生成了一只僵尸"); - } - - public function getZombie(Position $pos, $maxHealth = 20, $health = 20){ - $chunk = $pos->level->getChunk($pos->x >> 4, $pos->z >> 4, false); - $nbt = $this->getNBT(); - $zo = new Zombie($chunk, $nbt); - $zo->setPosition($pos); - $zo->setMaxHealth($maxHealth); - $zo->setHealth($health); - return $zo; - } - - /** - * @param Position $pos 出生位置坐标(世界) - * @param int $maxHealth 最高血量 - * @param int $health 血量 - * 出生一只苦力怕在某坐标 - */ - public function spawnCreeper(Position $pos, $maxHealth = 20, $health = 20){ - $chunk = $pos->level->getChunk($pos->x >> 4, $pos->z >> 4, false); - $nbt = $this->getNBT(); - $zo = new Creeper($chunk, $nbt); - $zo->setPosition($pos); - $zo->setMaxHealth($maxHealth); - $zo->setHealth($health); - $zo->spawnToAll(); - //$this->getLogger()->info("生成了一只苦力怕"); - } - - /** - * @param Position $pos 出生位置坐标(世界) - * @param int $maxHealth 最高血量 - * @param int $health 血量 - * 出生一只骷髅弓箭手在某坐标 - */ - public function spawnSkeleton(Position $pos, $maxHealth = 20, $health = 20){ - $chunk = $pos->level->getChunk($pos->x >> 4, $pos->z >> 4, false); - $nbt = $this->getNBT(); - $zo = new Skeleton($chunk, $nbt); - $zo->setPosition($pos); - $zo->setMaxHealth($maxHealth); - $zo->setHealth($health); - $zo->spawnToAll(); - //$this->getLogger()->info("生成了一只骷髅弓箭手"); - } - - /** - * @param Position $pos 出生位置坐标(世界) - * @param int $maxHealth 最高血量 - * @param int $health 血量 - * 出生一只牛在某坐标 - * - * @return Cow - */ - public function getCow(Position $pos, $maxHealth = 20, $health = 20){ - $chunk = $pos->level->getChunk($pos->x >> 4, $pos->z >> 4, false); - $nbt = $this->getNBT(); - $zo = new Cow($chunk, $nbt); - $zo->setPosition($pos); - $zo->setMaxHealth($maxHealth); - $zo->setHealth($health); - return $zo; - //$this->getLogger()->info("生成了一只牛"); - } - - public function spawnCow(Position $pos, $maxHealth = 20, $health = 20){ - $this->getCow($pos, $maxHealth, $health)->spawnToAll(); - } - - /** - * @param Position $pos 出生位置坐标(世界) - * @param int $maxHealth 最高血量 - * @param int $health 血量 - * 出生一只豬在某坐标 - */ - public function spawnPig(Position $pos, $maxHealth = 20, $health = 20){ - $chunk = $pos->level->getChunk($pos->x >> 4, $pos->z >> 4, false); - $nbt = $this->getNBT(); - $zo = new Pig($chunk, $nbt); - $zo->setPosition($pos); - $zo->setMaxHealth($maxHealth); - $zo->setHealth($health); - $zo->spawnToAll(); - //$this->getLogger()->info("生成了一只豬"); - } - - /** - * @param Position $pos 出生位置坐标(世界) - * @param int $maxHealth 最高血量 - * @param int $health 血量 - * 出生一只羊在某坐标 - */ - public function spawnSheep(Position $pos, $maxHealth = 20, $health = 20){ - $chunk = $pos->level->getChunk($pos->x >> 4, $pos->z >> 4, false); - $nbt = $this->getNBT(); - $zo = new Sheep($chunk, $nbt); - $zo->setPosition($pos); - $zo->setMaxHealth($maxHealth); - $zo->setHealth($health); - $zo->spawnToAll(); - //$this->getLogger()->info("生成了一只羊"); - } - - /** - * @param Position $pos 出生位置坐标(世界) - * @param int $maxHealth 最高血量 - * @param int $health 血量 - * 出生一只雞在某坐标 - */ - public function spawnChicken(Position $pos, $maxHealth = 20, $health = 20){ - $chunk = $pos->level->getChunk($pos->x >> 4, $pos->z >> 4, false); - $nbt = $this->getNBT(); - $zo = new Chicken($chunk, $nbt); - $zo->setPosition($pos); - $zo->setMaxHealth($maxHealth); - $zo->setHealth($health); - $zo->spawnToAll(); - //$this->getLogger()->info("生成了一只雞"); - } - - /** - * @param $zoHealth - * @return int - * 根据僵尸血量获取对应攻击值 - */ - public function getZombieDamage($zoHealth){ - $dif = $this->getServer()->getDifficulty(); - switch($dif){ - case 0: - return 0; - break; - case 1: - if($zoHealth <= 20 and $zoHealth >= 16){ - return 2; - }elseif($zoHealth <= 11 and $zoHealth >= 15){ - return 3; - }elseif($zoHealth <= 6 and $zoHealth >= 10){ - return 3; - }elseif($zoHealth <= 1 and $zoHealth >= 5){ - return 4; - }else return 5; - break; - case 2: - if($zoHealth <= 20 and $zoHealth >= 16){ - return 3; - }elseif($zoHealth <= 11 and $zoHealth >= 15){ - return 4; - }elseif($zoHealth <= 6 and $zoHealth >= 10){ - return 5; - }elseif($zoHealth <= 1 and $zoHealth >= 5){ - return 6; - }else return 7; - break; - case 3: - if($zoHealth <= 20 and $zoHealth >= 16){ - return 4; - }elseif($zoHealth <= 11 and $zoHealth >= 15){ - return 6; - }elseif($zoHealth <= 6 and $zoHealth >= 10){ - return 7; - }elseif($zoHealth <= 1 and $zoHealth >= 5){ - return 9; - }else return 10; - break; - } - return 0; - } - - public function getSkeletonDamage($zoHealth){ - $dif = $this->getServer()->getDifficulty(); - switch($dif){ - case 0: - return 0; - break; - case 1: - if($zoHealth <= 20 and $zoHealth >= 16){ - return 2; - }elseif($zoHealth <= 11 and $zoHealth >= 15){ - return 3; - }elseif($zoHealth <= 6 and $zoHealth >= 10){ - return 3; - }elseif($zoHealth <= 1 and $zoHealth >= 5){ - return 4; - }else return 5; - break; - case 2: - if($zoHealth <= 20 and $zoHealth >= 16){ - return 3; - }elseif($zoHealth <= 11 and $zoHealth >= 15){ - return 4; - }elseif($zoHealth <= 6 and $zoHealth >= 10){ - return 5; - }elseif($zoHealth <= 1 and $zoHealth >= 5){ - return 6; - }else return 7; - break; - case 3: - if($zoHealth <= 20 and $zoHealth >= 16){ - return 4; - }elseif($zoHealth <= 11 and $zoHealth >= 15){ - return 6; - }elseif($zoHealth <= 6 and $zoHealth >= 10){ - return 7; - }elseif($zoHealth <= 1 and $zoHealth >= 5){ - return 9; - }else return 10; - break; - } - return 0; - } - - /** - * @param Player $player - * @param $damage - * @return float - * 根据玩家的装备获取玩家应受到的伤害值 - */ - public function getPlayerDamage(Player $player, $damage){ - $armorValues = [ - Item::LEATHER_CAP => 1, - Item::LEATHER_TUNIC => 3, - Item::LEATHER_PANTS => 2, - Item::LEATHER_BOOTS => 1, - Item::CHAIN_HELMET => 1, - Item::CHAIN_CHESTPLATE => 5, - Item::CHAIN_LEGGINGS => 4, - Item::CHAIN_BOOTS => 1, - Item::GOLD_HELMET => 1, - Item::GOLD_CHESTPLATE => 5, - Item::GOLD_LEGGINGS => 3, - Item::GOLD_BOOTS => 1, - Item::IRON_HELMET => 2, - Item::IRON_CHESTPLATE => 6, - Item::IRON_LEGGINGS => 5, - Item::IRON_BOOTS => 2, - Item::DIAMOND_HELMET => 3, - Item::DIAMOND_CHESTPLATE => 8, - Item::DIAMOND_LEGGINGS => 6, - Item::DIAMOND_BOOTS => 3, - ]; - $points = 0; - foreach($player->getInventory()->getArmorContents() as $index => $i){ - if(isset($armorValues[$i->getId()])){ - $points += $armorValues[$i->getId()]; - } - } - $damage = floor($damage - $points * 0.04); - if($damage < 0){ - $damage = 0; - } - return $damage; - } - - /** - * @return CompoundTag - * 返回一个空的实体通用NBT - */ - public function getNBT() : CompoundTag{ - $nbt = new CompoundTag("", [ - "Pos" => new ListTag("Pos", [ - new DoubleTag("", 0), - new DoubleTag("", 0), - new DoubleTag("", 0) - ]), - "Motion" => new ListTag("Motion", [ - new DoubleTag("", 0), - new DoubleTag("", 0), - new DoubleTag("", 0) - ]), - "Rotation" => new ListTag("Rotation", [ - new FloatTag("", 0), - new FloatTag("", 0) - ]), - ]); - return $nbt; - } - - /** - * @param Position $pos - * @return int - * 获取某坐标(位置)的亮度 - */ - public function getLight(Position $pos){ - $chunk = $pos->getLevel()->getChunk($pos->x >> 4, $pos->z >> 4, false); - $l = 0; - if($chunk instanceof FullChunk){ - $l = $chunk->getBlockSkyLight($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f); - if($l < 15){ - //$l = \max($chunk->getBlockLight($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f)); - $l = $chunk->getBlockLight($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f); - } - } - return $l; - } - - /******** API结束 以下为计时器 *****************************/ - - /** - * @param Entity $entity - * @return bool - * 判断某生物周边32格内是否有玩家存在 - * 控制僵尸是否移动(自由行走模式) - */ - public function willMove(Entity $entity){ - foreach($entity->getViewers() as $viewer){ - if($entity->distance($viewer->getLocation()) <= 32) return true; - } - return false; - } - - public function RotationTimer(){ - foreach($this->getServer()->getLevels() as $level){ - foreach($level->getEntities() as $entity){ - if($entity instanceof Zombie or $entity instanceof Creeper or $entity instanceof Skeleton or $entity instanceof Cow or $entity instanceof Pig or $entity instanceof Sheep or $entity - instanceof Chicken or $entity instanceof Mooshroom or $entity instanceof Ocelot or $entity instanceof Wolf or $entity instanceof PigZombie - ){ - if(count($entity->getViewers()) != 0){ - if($entity instanceof Zombie or $entity instanceof PigZombie){ - $array = &$this->zombie; - }elseif($entity instanceof Creeper){ - $array = &$this->Creeper; - }elseif($entity instanceof Skeleton){ - $array = &$this->Skeleton; - }elseif($entity instanceof Cow or $entity instanceof Mooshroom or $entity instanceof Pig or $entity instanceof Sheep or $entity instanceof Ocelot or $entity instanceof Wolf){ - $array = &$this->Cow; - }elseif($entity instanceof Pig){ - $array = &$this->Pig; - }elseif($entity instanceof Sheep){ - $array = &$this->Sheep; - }elseif($entity instanceof Chicken){ - $array = &$this->Chicken; - }elseif($entity instanceof IronGolem){ - $array = &$this->irongolem; - }elseif($entity instanceof SnowGolem){ - $array = &$this->snowgolem; - } - if(isset($array[$entity->getId()])){ - $yaw0 = $entity->yaw; //实际yaw - $yaw = $array[$entity->getId()]['yaw']; //目标yaw - //$this->getLogger()->info($yaw0.' '.$yaw); - if(abs($yaw0 - $yaw) <= 180){ //-180到+180正方向 - if($yaw0 <= $yaw){ //实际在目标左边 - if($yaw - $yaw0 <= 15){ - $yaw0 = $yaw; - }else{ - $yaw0 += 15; - } - }else{ ////实际在目标右边 - if($yaw0 - $yaw <= 15){ - $yaw0 = $yaw; - }else{ - $yaw0 -= 15; - } - } - }else{ ////+180到-180方向 - if($yaw0 >= $yaw){ //实际在目标左边 - if((180 - $yaw0) + ($yaw + 180) <= 15){ - $yaw0 = $yaw; - }else{ - $yaw0 += 15; - if($yaw0 >= 180) $yaw0 = $yaw0 - 360; - } - }else{ ////实际在目标右边 - if((180 - $yaw) - ($yaw0 + 180) <= 15){ - $yaw0 = $yaw; - }else{ - $yaw0 -= 15; - if($yaw0 <= 180) $yaw0 = $yaw0 + 360; - } - } - } - $pitch0 = $entity->pitch; //实际pitch - $pitch = $array[$entity->getId()]['pitch']; //目标pitch - - if(abs($pitch0 - $pitch) <= 15){ - $pitch0 = $pitch; - }elseif($pitch > $pitch0){ - $pitch0 += 10; - }elseif($pitch < $pitch0){ - $pitch0 -= 10; - } - - $entity->setRotation($yaw0, $pitch0); - //$this->RotateHead($entity,$yaw); - } - } - } - } - } - } - - /** - * @param $mx - * @param $mz - * @return float|int - * 获取yaw角度 - */ - public function getyaw($mx, $mz){ //根据motion计算转向角度 - //转向计算 - if($mz == 0){ //斜率不存在 - if($mx < 0){ - $yaw = -90; - }else{ - $yaw = 90; - } - }else{ //存在斜率 - if($mx >= 0 and $mz > 0){ //第一象限 - $atan = atan($mx / $mz); - $yaw = rad2deg($atan); - }elseif($mx >= 0 and $mz < 0){ //第二象限 - $atan = atan($mx / abs($mz)); - $yaw = 180 - rad2deg($atan); - }elseif($mx < 0 and $mz < 0){ //第三象限 - $atan = atan($mx / $mz); - $yaw = -(180 - rad2deg($atan)); - }elseif($mx < 0 and $mz > 0){ //第四象限 - $atan = atan(abs($mx) / $mz); - $yaw = -(rad2deg($atan)); - }else{ - $yaw = 0; - } - } - - $yaw = -$yaw; - return $yaw; - } - - /** - * @param Vector3 $from - * @param Vector3 $to - * @return float|int - * 获取pitch角度 - */ - public function getpitch(Vector3 $from, Vector3 $to){ - $distance = $from->distance($to); - $height = $to->y - $from->y; - if($height > 0){ - return -rad2deg(asin($height / $distance)); - }elseif($height < 0){ - return rad2deg(asin(-$height / $distance)); - }else{ - return 0; - } - } - - /** - * @param Level $level - * @param Vector3 $v3 - * @param bool $hate - * @param bool $reason - * @return bool|float|string - * 判断某坐标是否可以行走 - * 并给出原因 - */ - public function ifjump(Level $level, Vector3 $v3, $hate = false, $reason = false){ //boybook Y轴算法核心函数 - $x = floor($v3->getX()); - $y = floor($v3->getY()); - $z = floor($v3->getZ()); - - //echo ($y." "); - if($this->whatBlock($level, new Vector3($x, $y, $z)) == "air"){ - //echo "前方空气 "; - if($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "block" or new Vector3($x, $y - 1, $z) == "climb"){ //方块 - //echo "考虑向前 "; - if($this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "half" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "high"){ //上方一格被堵住了 - //echo "上方卡住 \n"; - if($reason) return 'up!'; - return false; //上方卡住 - }else{ - //echo "GO向前走 \n"; - if($reason) return 'GO'; - return $y; //向前走 - } - }/*elseif ($this->whatBlock($level,new Vector3($x,$y-1,$z)) == "water") { //水 - //echo "下水游泳 \n"; - if ($reason) return 'swim'; - return $y-1; //降低一格向前走(下水游泳) - }*/ - elseif($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "half"){ //半砖 - //echo "下到半砖 \n"; - if($reason) return 'half'; - return $y - 0.5; //向下跳0.5格 - }elseif($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "lava"){ //岩浆 - //echo "前方岩浆 \n"; - if($reason) return 'lava'; - return false; //前方岩浆 - }elseif($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "air"){ //空气 - //echo "考虑向下跳 "; - if($this->whatBlock($level, new Vector3($x, $y - 2, $z)) == "block"){ - //echo "GO向下跳 \n"; - if($reason) return 'down'; - return $y - 1; //向下跳 - }else{ //前方悬崖 - //echo "前方悬崖 \n"; - if($reason) return 'fall'; - /* if ($hate === false) { - return false; - } - else { - return $y-1; //向下跳 - }*/ - } - } - }/* - elseif ($this->whatBlock($level,new Vector3($x,$y,$z)) == "water") { //水 - //echo "正在水中"; - if ($this->whatBlock($level,new Vector3($x,$y+1,$z)) == "water") { //上面还是水 - //echo "向上游 \n"; - if ($reason) return 'inwater'; - return $y+1; //向上游,防溺水 - } - elseif ($this->whatBlock($level,new Vector3($x,$y+1,$z)) == "block" or $this->whatBlock($level,new Vector3($x,$y+1,$z)) == "half") { //上方一格被堵住了 - if ($this->whatBlock($level,new Vector3($x,$y-1,$z)) == "block" or $this->whatBlock($level,new Vector3($x,$y-1,$z)) == "half") { //下方一格被也堵住了 - //echo "上下都被卡住 \n"; - if ($reason) return 'up!_down!'; - return false; //上下都被卡住 - } - else { - //echo "向下游 \n"; - if ($reason) return 'up!'; - return $y-1; //向下游,防卡住 - } - } - else { - //echo "游泳ing... \n"; - return $y; //向前游 - } - }*/ - elseif($this->whatBlock($level, new Vector3($x, $y, $z)) == "half"){ //半砖 - //echo "前方半砖 \n"; - if($this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "half" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "high"){ //上方一格被堵住了 - //return false; //上方卡住 - }else{ - if($reason) return 'halfGO'; - return $y + 0.5; - } - - }elseif($this->whatBlock($level, new Vector3($x, $y, $z)) == "lava"){ //岩浆 - //echo "前方岩浆 \n"; - if($reason) return 'lava'; - return false; - }elseif($this->whatBlock($level, new Vector3($x, $y, $z)) == "high"){ //1.5格高方块 - //echo "前方栅栏 \n"; - if($reason) return 'high'; - return false; - }elseif($this->whatBlock($level, new Vector3($x, $y, $z)) == "climb"){ //梯子 - //echo "前方梯子 \n"; - //return $y; - if($reason) return 'climb'; - if($hate){ - return $y + 0.7; - }else{ - return $y + 0.5; - } - }else{ //考虑向上 - //echo "考虑向上 "; - if($this->whatBlock($level, new Vector3($x, $y + 1, $z)) != "air"){ //前方是面墙 - //echo "前方是墙 \n"; - if($reason) return 'wall'; - return false; - }else{ - if($this->whatBlock($level, new Vector3($x, $y + 2, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y + 2, $z)) == "half" or $this->whatBlock($level, new Vector3($x, $y + 2, $z)) == "high"){ //上方两格被堵住了 - //echo "2格处被堵 \n"; - if($reason) return 'up2!'; - return false; - }else{ - //echo "GO向上跳 \n"; - if($reason) return 'upGO'; - return $y + 1; //向上跳 - } - } - } - return false; - } - - public function whatBlock(Level $level, $v3){ //boybook的y轴判断法 核心 什么方块? - $block = $level->getBlock($v3); - $id = $block->getID(); - $damage = $block->getDamage(); - switch($id){ - case 0: - case 6: - case 27: - case 30: - case 31: - case 37: - case 38: - case 39: - case 40: - case 50: - case 51: - case 63: - case 66: - case 68: - case 78: - case 111: - case 141: - case 142: - case 171: - case 175: - case 244: - case 323: - //无碰撞体积的板 - case 78: - case 70: - case 72: - case 147: - case 148: - - //透明方块 - return "air"; - break; - case 8: - case 9: - //水 - return "water"; - break; - case 10: - case 11: - //岩浆 - return "lava"; - break; - case 44: - case 158: - //半砖 - if($damage >= 8){ - return "block"; - }else{ - return "half"; - } - break; - case 64: - //门 - //var_dump($damage." "); - //TODO 不知如何判断门是否开启,因为以下条件永远满足 - if($block->isOpened()){ - return "air"; - }else{ - return "block"; - } - break; - case 85: - case 107: - case 139: - //1.5格高的无法跳跃物 - return "high"; - break; - case 65: - case 106: - //可攀爬物 - return "climb"; - break; - default: - //普通方块 - return "block"; - break; - } - } - - public function MobDeath(EntityDeathEvent $event){ - //var_dump("death"); - $entity = $event->getEntity(); - if($entity instanceof Zombie){ - $eid = $entity->getID(); - if(isset($this->zombie[$eid])){ - unset($this->zombie[$eid]); - } - } - if($entity instanceof Creeper){ - $eid = $entity->getID(); - if(isset($this->Creeper[$eid])){ - unset($this->Creeper[$eid]); - } - } - } - - /** - * 刷僵尸计时器 - */ - public function MobGenerate(){ - foreach($this->getServer()->getOnlinePlayers() as $p){ - //$this->server->getLogger()->info("准备生成僵尸"); - $level = $p->getLevel(); - $max = 15; - //if ($level->getTime() >= 13500) { //是夜晚 - //$this->server->getLogger()->info("时间OK"); - $v3 = new Vector3($p->getX() + mt_rand(-$this->birth_r, $this->birth_r), $p->getY(), $p->getZ() + mt_rand(-$this->birth_r, $this->birth_r)); - for($y0 = $p->getY() - 10; $y0 <= $p->getY() + 10; $y0++){ - $v3->y = $y0; - if($this->whatBlock($level, $v3) == "block"){ - //$this->server->getLogger()->info("方块OK"); - $v3_1 = $v3; - $v3_1->y = $y0 + 1; - $v3_2 = $v3; - $v3_2->y = $y0 + 2; - $random = mt_rand(0, 1); - - - if($level->getBlock($v3_1)->getID() == 0 and $level->getBlock($v3_2)->getID() == 0){ //找到地面 - /** @var Entity[] $zoC */ - $zoC = []; - /** @var Entity[] $cowc */ - $cowc = []; - foreach($level->getEntities() as $zo){ - if($zo instanceof Zombie) $zoC[] = $zo; - if($zo instanceof Cow) $cowc[] = $zo; - } - - - if(count($zoC) > $max){ - for($i = 0; $i < (count($zoC) - $max); $i++) $zoC[$i]->kill(); - }elseif($random == 0 && $level->getTime() >= 13500){ - $pos = new Position($v3->x, $v3->y, $v3->z, $level); - - $this->server->getPluginManager()->callEvent($ev = new EntityGenerateEvent($pos, Zombie::NETWORK_ID, EntityGenerateEvent::CAUSE_AI_HOLDER)); - if(!$ev->isCancelled()){ - $this->spawnZombie($ev->getPosition()); - } - //$this->server->getLogger()->info("生成1僵尸"); - } - - if(count($cowc) > $max){ - for($i = 0; $i < (count($cowc) - $max); $i++) $cowc[$i]->kill(); - }elseif($random == 1){ - $pos = new Position($v3->x, $v3->y, $v3->z, $level); - - $this->server->getPluginManager()->callEvent($ev = new EntityGenerateEvent($pos, Cow::NETWORK_ID, EntityGenerateEvent::CAUSE_AI_HOLDER)); - if(!$ev->isCancelled()){ - $this->spawnCow($ev->getPosition()); - } - //$this->server->getLogger()->info("生成1牛"); - } - break; - } - } - } - } - } - - public function EntityDamage(EntityDamageEvent $event){ //击退修复 - if($event instanceof EntityDamageByEntityEvent){ - $p = $event->getDamager(); - $entity = $event->getEntity(); - if($entity instanceof Zombie){ - $array = &$this->zombie; - }elseif($entity instanceof Creeper){ - $array = &$this->Creeper; - }elseif($entity instanceof Cow){ - $array = &$this->Cow; - }elseif($entity instanceof Pig){ - $array = &$this->Pig; - }elseif($entity instanceof Sheep){ - $array = &$this->Sheep; - }elseif($entity instanceof Chicken){ - $array = &$this->Chicken; - }elseif($entity instanceof Skeleton){ - $array = &$this->Skeleton; - }else{ - $array = []; - } - if(isset($array[$entity->getId()])){ - if($p instanceof Player and ($array[$entity->getId()]['canAttack'] == 0)){ - $weapon = $p->getInventory()->getItemInHand()->getID(); //得到玩家手中的武器 - $high = 0; - if($weapon == 258 or $weapon == 271 or $weapon == 275){ //击退x5 - $back = 1.5; - }elseif($weapon == 267 or $weapon == 272 or $weapon == 279 or $weapon == 283 or $weapon == 286){ //击退x1 - $back = 3; - }elseif($weapon == 276){ //击退x2 - $back = 4; - }elseif($weapon == 292){ //击退x10 - $back = 8; - $high = 3; - }else{ - $back = 1; - } - //var_dump("玩家".$p->getName()."攻击了ID为".$zo->getId()."的实体"); - $array[$entity->getId()]['x'] = $array[$entity->getId()]['x'] - $array[$entity->getId()]['xxx'] * $back; - $array[$entity->getId()]['y'] = $entity->getY() + $high; - $array[$entity->getId()]['z'] = $array[$entity->getId()]['z'] - $array[$entity->getId()]['zzz'] * $back; - $pos = new Vector3 ($array[$entity->getId()]['x'], $array[$entity->getId()]['y'], $array[$entity->getId()]['z']); //目标坐标 - //$entity->setPosition($pos); - $entity->knockBack($entity, 0, $array[$entity->getId()]['xxx'] * $back, $array[$entity->getId()]['zzz'] * $back); - if(isset($array[$entity->getId()])){ - $zom = &$array[$entity->getId()]; - $zom['IsChasing'] = $p->getName(); - //var_dump( $zom['IsChasing']); - } - } - } - } - } - - public function knockBackover(Entity $entity, Vector3 $v3){ - if($entity instanceof Entity){ - if(isset($this->zombie[$entity->getId()])){ - $entity->setPosition($v3); - $this->zombie[$entity->getId()]['knockBack'] = false; - } - if(isset($this->Cow[$entity->getId()])){ - $entity->setPosition($v3); - $this->Cow[$entity->getId()]['knockBack'] = false; - } - if(isset($this->Pig[$entity->getId()])){ - $entity->setPosition($v3); - $this->Pig[$entity->getId()]['knockBack'] = false; - } - if(isset($this->Sheep[$entity->getId()])){ - $entity->setPosition($v3); - $this->Sheep[$entity->getId()]['knockBack'] = false; - } - if(isset($this->Chicken[$entity->getId()])){ - $entity->setPosition($v3); - $this->Chicken[$entity->getId()]['knockBack'] = false; - } - if(isset($this->Skeleton[$entity->getId()])){ - $entity->setPosition($v3); - $this->Skeleton[$entity->getId()]['knockBack'] = false; - } - if(isset($this->Creeper[$entity->getId()])){ - $entity->setPosition($v3); - $this->Creeper[$entity->getId()]['knockBack'] = false; - } - } - } - -} - diff --git a/src/devmine/creatures/entities/ai/ChickenAI.php b/src/devmine/creatures/entities/ai/ChickenAI.php deleted file mode 100644 index a256e75..0000000 --- a/src/devmine/creatures/entities/ai/ChickenAI.php +++ /dev/null @@ -1,242 +0,0 @@ -AIHolder = $AIHolder; - if($this->AIHolder->getServer()->aiConfig["chicken"]){ - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ChickenRandomWalkCalc" - ] ), 10); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ChickenRandomWalk" - ] ), 1); - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "array_clear" - ] ), 20 * 5); - } - } - - public function ChickenRandomWalkCalc() { - $this->dif = $this->AIHolder->getServer()->getDifficulty(); - //$this->getLogger()->info("雞数量:".count($this->plugin->Chicken)); - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo){ - if($zo instanceof Chicken){ - if ($this->AIHolder->willMove($zo)) { - if (!isset($this->AIHolder->Chicken[$zo->getId()])){ - $this->AIHolder->Chicken[$zo->getId()] = array( - 'ID' => $zo->getId(), - 'IsChasing' => false, - 'motionx' => 0, - 'motiony' => 0, - 'motionz' => 0, - 'hurt' => 10, - 'time'=>10, - 'x' => 0, - 'y' => 0, - 'z' => 0, - 'oldv3' => $zo->getLocation(), - 'yup' => 20, - 'up' => 0, - 'yaw' => $zo->yaw, - 'pitch' => 0, - 'level' => $zo->getLevel()->getName(), - 'xxx' => 0, - 'zzz' => 0, - 'gotimer' => 10, - 'swim' => 0, - 'jump' => 0.01, - 'canjump' => true, - 'drop' => false, - 'canAttack' => 0, - 'knockBack' => false, - ); - $zom = &$this->AIHolder->Chicken[$zo->getId()]; - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - $zom = &$this->AIHolder->Chicken[$zo->getId()]; - - if ($zom['IsChasing'] === false) { //自由行走模式 - if ($zom['gotimer'] == 0 or $zom['gotimer'] == 10) { - //限制转动幅度 - $newmx = mt_rand(-5,5)/10; - while (abs($newmx - $zom['motionx']) >= 0.7) { - $newmx = mt_rand(-5,5)/10; - } - $zom['motionx'] = $newmx; - - $newmz = mt_rand(-5,5)/10; - while (abs($newmz - $zom['motionz']) >= 0.7) { - $newmz = mt_rand(-5,5)/10; - } - $zom['motionz'] = $newmz; - } - elseif ($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24) { - $zom['motionx'] = 0; - $zom['motionz'] = 0; - //雞停止 - } - - $zom['gotimer'] += 0.5; - if ($zom['gotimer'] >= 22) $zom['gotimer'] = 0; //重置走路计时器 - - //$zom['motionx'] = mt_rand(-10,10)/10; - //$zom['motionz'] = mt_rand(-10,10)/10; - $zom['yup'] = 0; - $zom['up'] = 0; - - //boybook的y轴判断法 - //$width = $this->width; - $pos = new Vector3 ($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1,$zom['z'] + $zom['motionz']); //目标坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(),$pos); - if ($zy === false) { //前方不可前进 - $pos2 = new Vector3 ($zom['x'], $zom['y'] ,$zom['z']); //目标坐标 - if ($this->AIHolder->ifjump($zo->getLevel(),$pos2) === false) { //原坐标依然是悬空 - $pos2 = new Vector3 ($zom['x'], $zom['y']-1,$zom['z']); //下降 - $zom['up'] = 1; - $zom['yup'] = 0; - } - else { - $zom['motionx'] = - $zom['motionx']; - $zom['motionz'] = - $zom['motionz']; - //转向180度,向身后走 - $zom['up'] = 0; - } - } - else { - $pos2 = new Vector3 ($zom['x'] + $zom['motionx'], $zy - 1 ,$zom['z'] + $zom['motionz']); //目标坐标 - if ($pos2->y - $zom['y'] < 0) { - $zom['up'] = 1; - } - else { - $zom['up'] = 0; - } - } - - if ($zom['motionx'] == 0 and $zom['motionz'] == 0) { //雞停止 - } - else { - //转向计算 - $yaw = $this->AIHolder->getyaw($zom['motionx'], $zom['motionz']); - //$zo->setRotation($yaw,0); - $zom['yaw'] = $yaw; - $zom['pitch'] = 0; - } - - //更新坐标 - if (!$zom['knockBack']) { - $zom['x'] = $pos2->getX(); - $zom['z'] = $pos2->getZ(); - $zom['y'] = $pos2->getY(); - } - $zom['motiony'] = $pos2->getY() - $zo->getY(); - //echo($zo->getY()."\n"); - //var_dump($pos2); - //var_dump($zom['motiony']); - $zo->setPosition($pos2); - //echo "SetPosition \n"; - } - } - } - } - } - } - - public function ChickenRandomWalk() { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Chicken) { - if (isset($this->AIHolder->Chicken[$zo->getId()])) { - $zom = &$this->AIHolder->Chicken[$zo->getId()]; - if ($zom['canAttack'] != 0) { - $zom['canAttack'] -= 1; - } - $pos = $zo->getLocation(); - //echo ($zom['IsChasing']."\n"); - - //真正的自由落体 by boybook - if ($zom['drop'] !== false) { - $olddrop = $zom['drop']; - $zom['drop'] += 0.5; - $drop = $zom['drop']; - //echo $drop."\n"; - $dropy = $zo->getY() - ($olddrop * 0.05 + 0.0125); - $posd0 = new Vector3 (floor($zo->getX()), floor($dropy), floor($zo->getZ())); - $posd = new Vector3 ($zo->getX(), $dropy, $zo->getZ()); - if ($this->AIHolder->whatBlock($zo->getLevel(), $posd0) == "air") { - $zo->setPosition($posd); //下降 - } else { - for ($i = 1; $i <= $drop; $i++) { - $posd0->y++; - if ($this->AIHolder->whatBlock($zo->getLevel(), $posd0) != "block") { - $posd->y = $posd0->y; - //$zo->setPosition($posd); //下降完成 - $h = $zom['drop'] * $zom['drop'] / 20; - $damage = $h - 3; - //echo($h . ": " . $damage . "\n"); - if ($damage > 0) { - $zo->attack($damage, EntityDamageEvent::CAUSE_FALL); - } - $zom['drop'] = false; - break; - } - } - } - } else { - $drop = 0; - } - //echo "."; - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10, 0, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - - } - } - } - } - } - - public function array_clear() { - if (count($this->AIHolder->Chicken) != 0) { - foreach ($this->AIHolder->Chicken as $eid=> $info) { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - if (!($level->getEntity($eid) instanceof Entity)) { - unset($this->AIHolder->Chicken[$eid]); - //echo "清除 $eid \n"; - } - } - } - } - } - - -} diff --git a/src/devmine/creatures/entities/ai/CowAI.php b/src/devmine/creatures/entities/ai/CowAI.php deleted file mode 100644 index 6dc90b7..0000000 --- a/src/devmine/creatures/entities/ai/CowAI.php +++ /dev/null @@ -1,239 +0,0 @@ -AIHolder = $AIHolder; - if($this->AIHolder->getServer()->aiConfig["cow"]){ - $this->AIHolder->getServer()->getScheduler()->scheduleRepeatingTask(new CallbackTask ([ - $this, - "CowRandomWalkCalc" - ]), 5); - - $this->AIHolder->getServer()->getScheduler()->scheduleRepeatingTask(new CallbackTask ([ - $this, - "CowRandomWalk" - ]), 10); - /* $this->plugin->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "array_clear" - ] ), 20 * 5);*/ - - } - } - - public function CowRandomWalkCalc(){ - $this->dif = $this->AIHolder->getServer()->getDifficulty(); - //$this->getLogger()->info("牛数量:".count($this->plugin->Cow)); - foreach($this->AIHolder->getServer()->getLevels() as $level){ - foreach($level->getEntities() as $zo){ - if(($zo::NETWORK_ID == Cow::NETWORK_ID) or ($zo::NETWORK_ID == Mooshroom::NETWORK_ID) or ($zo::NETWORK_ID == Pig::NETWORK_ID) or ($zo::NETWORK_ID == Sheep::NETWORK_ID) or - ($zo::NETWORK_ID == Ocelot::NETWORK_ID) or ($zo::NETWORK_ID == Wolf::NETWORK_ID)){ - if($this->AIHolder->willMove($zo)){ - if(!isset($this->AIHolder->Cow[$zo->getId()])){ - $this->AIHolder->Cow[$zo->getId()] = array( - 'ID' => $zo->getId(), - 'IsChasing' => false, - 'motionx' => 0, - 'motiony' => 0, - 'motionz' => 0, - 'hurt' => 10, - 'time' => 10, - 'x' => 0, - 'y' => 0, - 'z' => 0, - 'oldv3' => $zo->getLocation(), - 'yup' => 20, - 'up' => 0, - 'yaw' => $zo->yaw, - 'pitch' => 0, - 'level' => $zo->getLevel()->getName(), - 'xxx' => 0, - 'zzz' => 0, - 'gotimer' => 10, - 'swim' => 0, - 'jump' => 0.01, - 'canjump' => true, - 'drop' => false, - 'canAttack' => 0, - 'knockBack' => false, - ); - $zom = &$this->AIHolder->Cow[$zo->getId()]; - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - $zom = &$this->AIHolder->Cow[$zo->getId()]; - - //if ($zom['IsChasing'] === false) { //自由行走模式 - - if($zom['gotimer'] == 0 or $zom['gotimer'] == 10){ - //限制转动幅度 - $newmx = mt_rand(-5, 5) / 10; - while(abs($newmx - $zom['motionx']) >= 0.7){ - $newmx = mt_rand(-5, 5) / 10; - } - $zom['motionx'] = $newmx; - - $newmz = mt_rand(-5, 5) / 10; - while(abs($newmz - $zom['motionz']) >= 0.7){ - $newmz = mt_rand(-5, 5) / 10; - } - $zom['motionz'] = $newmz; - }elseif($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24){ - $zom['motionx'] = 0; - $zom['motionz'] = 0; - //牛停止 - } - - $zom['gotimer'] += 0.5; - if($zom['gotimer'] >= 22) $zom['gotimer'] = 0; //重置走路计时器 - - //$zom['motionx'] = mt_rand(-10,10)/10; - //$zom['motionz'] = mt_rand(-10,10)/10; - $zom['yup'] = 0; - $zom['up'] = 0; - - //boybook的y轴判断法 - //$width = $this->width; - $pos = new Vector3 ($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1, $zom['z'] + $zom['motionz']); //目标坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(), $pos); - - if($zy === false){ //前方不可前进 - $pos2 = new Vector3 ($zom['x'], $zom['y'], $zom['z']); //目标坐标 - if($this->AIHolder->ifjump($zo->getLevel(), $pos2) === false){ //原坐标依然是悬空 - // $pos2 = new Vector3 ($zom['x'], $zom['y'],$zom['z']); //下降 - // $zom['up'] = 1; - $zom['yup'] = 0; - }else{ - // print($zy-$pos->y); - $zom['motionx'] = -$zom['motionx']; - $zom['motionz'] = -$zom['motionz']; - //$zom['motiony'] = 0.01; - //转向180度,向身后走 - $zom['up'] = 0; - } - }else{ - $pos2 = new Vector3 ($zom['x'] + $zom['motionx'], $zy - 1, $zom['z'] + $zom['motionz']); //目标坐标 - if($pos2->y - $zom['y'] < 0){ - $zom['up'] = 1; - }else{ - $zom['up'] = 0; - } - } - - if($zom['motionx'] == 0 and $zom['motionz'] == 0){ //牛停止 - }else{ - //转向计算 - $yaw = $this->AIHolder->getyaw($zom['motionx'], $zom['motionz']); - //$zo->setRotation($yaw,0); - $zom['yaw'] = $yaw; - $zom['pitch'] = 0; - } - - //更新坐标 - if(!$zom['knockBack']){ - $zom['x'] = $pos2->getX(); - $zom['z'] = $pos2->getZ(); - $zom['y'] = $pos2->getY(); - } - - $zom['motiony'] = $pos2->getY() - $zo->getY(); - //echo($zo->getY()."\n"); - //var_dump($pos2); - //var_dump($zom['motiony']); - $zo->setPosition($pos2); - //echo "SetPosition \n"; - } - //} - - } - } - } - } - - public function CowRandomWalk(){ - foreach($this->AIHolder->getServer()->getLevels() as $level){ - foreach($level->getEntities() as $zo){ - if(($zo::NETWORK_ID == Cow::NETWORK_ID) or ($zo::NETWORK_ID == Mooshroom::NETWORK_ID) or ($zo::NETWORK_ID == Pig::NETWORK_ID) or ($zo::NETWORK_ID == Sheep::NETWORK_ID) or - ($zo::NETWORK_ID == Ocelot::NETWORK_ID) or ($zo::NETWORK_ID == Wolf::NETWORK_ID)){ - if(isset($this->AIHolder->Cow[$zo->getId()])){ - $zom = &$this->AIHolder->Cow[$zo->getId()]; - if($zom['canAttack'] != 0){ - $zom['canAttack'] -= 1; - } - //echo ($zom['IsChasing']."\n"); - - //真正的自由落体 by boybook - $downly = $zo->onGround; - - /* if ($zo->onGround != false) { - $downly=true; - - //$zom['motionY']=-0.04; - //zom['drop'] += 0.01; - } else { - $drop = 0; - - }*/ - if(abs($zo->getY() - $zom['oldv3']->y) == 1 and $zom['canjump'] === true){ - //var_dump("跳"); - $zom['canjump'] = false; - $zom['jump'] = 0.3; - }else{ - if($zom['jump'] > 0.01){ - $zom['jump'] -= 0.1; - }else{ - $zom['jump'] = 0; - } - } - - //echo "."; - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['xxx'], $zom['jump'] - $downly ? 0.04 : 0, $zom['zzz']] - ]; - foreach($zo->getViewers() as $pl){ - $pl->dataPacket($pk3); - } - - } - } - } - } - } - - public function array_clear(){ - if(count($this->AIHolder->Cow) != 0){ - foreach($this->AIHolder->Cow as $eid => $info){ - foreach($this->AIHolder->getServer()->getLevels() as $level){ - if(!($level->getEntity($eid) instanceof Entity)){ - unset($this->AIHolder->Cow[$eid]); - //echo "清除 $eid \n"; - } - } - } - } - } - - -} diff --git a/src/devmine/creatures/entities/ai/CreeperAI.php b/src/devmine/creatures/entities/ai/CreeperAI.php deleted file mode 100644 index 0ce3301..0000000 --- a/src/devmine/creatures/entities/ai/CreeperAI.php +++ /dev/null @@ -1,539 +0,0 @@ -AIHolder = $AIHolder; - if($this->AIHolder->getServer()->aiConfig["creeper"]){ - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "CreeperRandomWalkCalc" - ] ), 10); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "CreeperRandomWalk" - ] ), 1); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "CreeperHateWalk" - ] ), 10); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "CreeperHateFinder" - ] ), 10); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "array_clear" - ] ), 20 * 5); - } - } - - public function array_clear() { - if (count($this->AIHolder->Creeper) != 0) { - foreach ($this->AIHolder->Creeper as $eid=> $info) { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - if (!($level->getEntity($eid) instanceof Entity)) { - unset($this->AIHolder->Creeper[$eid]); - //echo "清除 $eid \n"; - } - } - } - } - } - - /** - * 苦力怕初始化,常规化及自由行走模式循环计时器 - * 循环间隔:20 ticks - */ - public function CreeperRandomWalkCalc() { - $this->dif = $this->AIHolder->getServer()->getDifficulty(); - //$this->getLogger()->info("苦力怕数量:".count($this->plugin->Creeper)); - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo){ - if($zo instanceof Creeper){ - if ($this->AIHolder->willMove($zo)) { - if (!isset($this->AIHolder->Creeper[$zo->getId()])){ - $this->AIHolder->Creeper[$zo->getId()] = array( - 'ID' => $zo->getId(), - 'IsChasing' => false, - 'motionx' => 0, - 'motiony' => 0, - 'motionz' => 0, - 'hurt' => 10, - 'time'=>10, - 'x' => 0, - 'y' => 0, - 'z' => 0, - 'oldv3' => $zo->getLocation(), - 'yup' => 20, - 'up' => 0, - 'yaw' => $zo->yaw, - 'pitch' => 0, - 'level' => $zo->getLevel()->getName(), - 'xxx' => 0, - 'zzz' => 0, - 'gotimer' => 10, - 'swim' => 0, - 'jump' => 0.01, - 'canjump' => true, - 'drop' => false, - 'canAttack' => 0, - 'knockBack' => false, - 'boom' => false, - ); - $zom = &$this->AIHolder->Creeper[$zo->getId()]; - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - $zom = &$this->AIHolder->Creeper[$zo->getId()]; - - if ($zom['boom'] == false) { - if ($zom['IsChasing'] === false) { //自由行走模式 - - //限制转动幅度 - $newmx = mt_rand(-5,5)/10; - while (abs($newmx - $zom['motionx']) >= 0.6) { - $newmx = mt_rand(-5,5)/10; - } - $zom['motionx'] = $newmx; - - $newmz = mt_rand(-5,5)/10; - while (abs($newmz - $zom['motionz']) >= 0.6) { - $newmz = mt_rand(-5,5)/10; - } - $zom['motionz'] = $newmz; - - if ($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24) { - $zom['motionx'] = 0; - $zom['motionz'] = 0; - //苦力怕停止 - } - - $zom['gotimer'] += 0.5; - if ($zom['gotimer'] >= 22) $zom['gotimer'] = 0; //重置走路计时器 - - //$zom['motionx'] = mt_rand(-10,10)/10; - //$zom['motionz'] = mt_rand(-10,10)/10; - $zom['yup'] = 0; - $zom['up'] = 0; - - //boybook的y轴判断法 - //$width = $this->width; - $pos = new Vector3 ($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1,$zom['z'] + $zom['motionz']); //目标坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(),$pos); - if ($zy === false) { //前方不可前进 - $pos2 = new Vector3 ($zom['x'], $zom['y'] ,$zom['z']); //目标坐标 - if ($this->AIHolder->ifjump($zo->getLevel(),$pos2) === false) { //原坐标依然是悬空 - $pos2 = new Vector3 ($zom['x'], $zom['y']-1,$zom['z']); //下降 - $zom['up'] = 1; - $zom['yup'] = 0; - } - else { - $zom['motionx'] = - $zom['motionx']; - $zom['motionz'] = - $zom['motionz']; - //转向180度,向身后走 - $zom['up'] = 0; - } - } - else { - $pos2 = new Vector3 ($zom['x'] + $zom['motionx'], $zy - 1 ,$zom['z'] + $zom['motionz']); //目标坐标 - if ($pos2->y - $zom['y'] < 0) { - $zom['up'] = 1; - } - else { - $zom['up'] = 0; - } - } - - if ($zom['motionx'] == 0 and $zom['motionz'] == 0) { //苦力怕停止 - } - else { - //转向计算 - $yaw = $this->AIHolder->getyaw($zom['motionx'], $zom['motionz']); - //$zo->setRotation($yaw,0); - $zom['yaw'] = $yaw; - $zom['pitch'] = 0; - } - - //更新苦力怕坐标 - if (!$zom['knockBack']) { - $zom['x'] = $pos2->getX(); - $zom['z'] = $pos2->getZ(); - $zom['y'] = $pos2->getY(); - } - $zom['motiony'] = $pos2->getY() - $zo->getY(); - //echo($zo->getY()."\n"); - //var_dump($pos2); - //var_dump($zom['motiony']); - $zo->setPosition($pos2->add(0,1,0)); - //echo "SetPosition \n"; - } - } - } - } - } - } - } - - /** - * 苦力怕仇恨刷新计时器 - * 循环间隔:10 ticks - */ - public function CreeperHateFinder() { - foreach ($this->AIHolder->getServer()->getLevels () as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Creeper) { - if (isset($this->AIHolder->Creeper[$zo->getId()])) { - $zom = &$this->AIHolder->Creeper[$zo->getId()]; - $h_r = $this->hatred_r; //仇恨半径 - $pos = new Vector3($zo->getX(), $zo->getY(), $zo->getZ()); - $hatred = false; - foreach ($zo->getViewers() as $p) { //获取附近玩家 - if ($p->distance($pos) <= $h_r) { //玩家在仇恨半径内 - if ($hatred === false) { - $hatred = $p; - } elseif ($hatred instanceof Player) { - if ($p->distance($pos) <= $hatred->distance($pos)) { //比上一个更近 - $hatred = $p; - } - } - } - } - //echo ($zom['IsChasing']."\n"); - if ($hatred == false or $this->dif == 0) { - $zom['IsChasing'] = false; - } else { - $zom['IsChasing'] = $hatred->getName(); - } - } - } - } - } - } - - /** - * 苦力怕仇恨模式坐标更新计时器 - * 循环间隔:10 ticks - */ - public function CreeperHateWalk() { - foreach ($this->AIHolder->getServer()->getLevels () as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Creeper) { - if (isset($this->AIHolder->Creeper[$zo->getId()])) { - $zom = &$this->AIHolder->Creeper[$zo->getId()]; - //$zom['yup'] = $zom['yup'] - 1; - if (!$zom['knockBack']) { - $zom['oldv3'] = $zo->getLocation(); - $zom['canjump'] = true; - - //苦力怕碰撞检测 by boybook - foreach ($level->getEntities() as $zo0) { - if ($zo0 instanceof Creeper and !($zo0 == $zo)) { - if ($zo->distance($zo0) <= $this->width * 2) { - $dx = $zo->x - $zo0->x; - $dz = $zo->z - $zo0->z; - if ($dx == 0) { - $dx = mt_rand(-5,5) / 5; - if ($dx == 0) $dx = 1; - } - if ($dz == 0) { - $dz = mt_rand(-5,5) / 5; - if ($dz == 0) $dz = 1; - } - $zo->knockBack($zo0,0,$dx/5,$dz/5,0); - $newpos = new Vector3($zo->x + $dx * 5, $zo->y, $zo->z + $dz * 5); - $zom['x'] = $newpos->x; - $zom['y'] = $newpos->y; - $zom['z'] = $newpos->z; - $this->AIHolder->getServer()->getScheduler()->scheduleDelayedTask(new CallbackTask([$this->AIHolder,"knockBackover"],[$zo,$newpos]),5); - } - } - - } - - if ($zom['IsChasing'] !== false) { - //echo ("是属于仇恨模式\n"); - $p = $this->AIHolder->getServer()->getPlayer($zom['IsChasing']); - if (($p instanceof Player) === false) { - $zom['IsChasing'] = false; //取消仇恨模式 - } else { - //真正的行走方向计算 - $xx = $p->getX() - $zo->getX(); - $zz = $p->getZ() - $zo->getZ(); - $yaw = $this->AIHolder->getyaw($xx,$zz); - /* - * x = $xxx, z = $zzz - * x0 = $xx, z0 = $zz - * x^2 + z^2 = 0.7 - * x/z = x0/z0 => x = bi * z - * => - * bi^2 * z^2 + z^2 = 0.7 - * z^2 * (bi^2 + 1) = 0.7 - * */ - if ($zz != 0) { - $bi = $xx/$zz; - }else{ - $bi = 0; - } - - //根据wiki:苦力怕掉血后走路更快 - if ($zo->getHealth() == $zo->getMaxHealth()) { - $zzz = sqrt(($this->zo_hate_v / 2.5) / ($bi * $bi + 1)); - }else{ - $zzz = sqrt(($this->zo_hate_v / 2) / ($bi * $bi + 1)); - } - - if ($zz < 0) $zzz = -$zzz; - $xxx = $zzz * $bi; - - $zo_v2 = new Vector2($zo->getX(),$zo->getZ()); - $p_v2 = new Vector2($p->getX(),$p->getZ()); - if ($zo_v2->distance($p_v2) <= $this->zo_hate_v/2) { - $xxx = $xx; - $zzz = $zz; - } - - $zom['xxx'] = $xxx; - $zom['zzz'] = $zzz; - - //计算y轴 - //$width = $this->width; - $pos0 = new Vector3 ($zo->getX(), $zo->getY() + 1, $zo->getZ()); //原坐标 - $pos = new Vector3 ($zo->getX() + $xxx, $zo->getY() + 1, $zo->getZ() + $zzz); //目标坐标 - //用来写苦力怕宽度的 - //$v = $this->zo_hate_v/2; - //$pos_front = new Vector3 ($zo->getX() + ($xxx/$v*($v+$this->width)), $zo->getY() + 1, $zo->getZ() + ($zzz/$v*($v+$this->width))); //前方坐标 - //$pos_back = new Vector3 ($zo->getX() + (-$xxx/$v*(-$v-$this->width)), $zo->getY() + 1, $zo->getZ() + (-$zzz/$v*(-$v-$this->width))); //后方坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(), $pos, true); - - if ($zy === false or ($zy !== false and $this->AIHolder->ifjump($zo->getLevel(), $pos0, true, true) == 'fall')) { //前方不可前进 - //真正的自由落体 by boybook - if ($this->AIHolder->ifjump($zo->getLevel(), $pos0, false) === false) { //原坐标依然是悬空 - if ($zom['drop'] === false) { - $zom['drop'] = 0; //苦力怕下落的速度 - } - $pos2 = new Vector3 ($zo->getX(), $zo->getY() - ($zom['drop'] / 2 + 1.25), $zo->getZ()); //下降 - } else { - $zom['drop'] = false; - if ($this->AIHolder->whatBlock($level, $pos0) == "climb") { //梯子 - $zy = $pos0->y + 0.7; - $pos2 = new Vector3 ($zo->getX(), $zy - 1, $zo->getZ()); //目标坐标 - } - elseif ($xxx != 0 and $zzz != 0) { //走向最近距离 - if ($this->AIHolder->ifjump($zo->getLevel(), new Vector3($zo->getX() + $xxx, $zo->getY() + 1, $zo->getZ()), true) !== false) { - $pos2 = new Vector3($zo->getX() + $xxx, floor($zo->getY()), $zo->getZ()); //目标坐标 - } elseif ($this->AIHolder->ifjump($zo->getLevel(), new Vector3($zo->getX(), $zo->getY() + 1, $zo->getZ() + $zzz), true) !== false) { - $pos2 = new Vector3($zo->getX(), floor($zo->getY()), $zo->getZ() + $zzz); //目标坐标 - } else { - $pos2 = new Vector3 ($zo->getX() - $xxx / 5, floor($zo->getY()), $zo->getZ() - $zzz / 5); //目标坐标 - //转向180度,向身后走 - } - } else { - $pos2 = new Vector3 ($zo->getX() - $xxx / 5, floor($zo->getY()), $zo->getZ() - $zzz / 5); //目标坐标 - } - } - } else { - $pos2 = new Vector3 ($zo->getX() + $xxx, $zy - 1, $zo->getZ() + $zzz); //目标坐标 - } - $zo->setPosition($pos2->add(0,1,0)); - - $pos3 = $pos2; - $pos3->y = $pos3->y + 2.62; - $ppos = $p->getLocation(); - $ppos->y = $ppos->y + $p->getEyeHeight(); - $pitch = $this->AIHolder->getpitch($pos3,$ppos); - - $zom['yaw'] = $yaw; - $zom['pitch'] = $pitch; - if (!$zom['knockBack']) { - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - } - } - } - } - } - } - } - } - - /** - * 高密集型发包计时器 - * - 发送数据包 - * - 计算自由落体相关数据 - * 循环间隔:1 tick - */ - public function CreeperRandomWalk() { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Creeper) { - if (isset($this->AIHolder->Creeper[$zo->getId()])) { - $zom = &$this->AIHolder->Creeper[$zo->getId()]; - if ($zom['canAttack'] != 0) { - $zom['canAttack'] -= 1; - } - $pos = $zo->getLocation(); - //echo ($zom['IsChasing']."\n"); - - - - if ($zom['boom'] == false) { - - - //真正的自由落体 by boybook - if ($zom['drop'] !== false) { - $olddrop = $zom['drop']; - $zom['drop'] += 0.5; - $drop = $zom['drop']; - //echo $drop."\n"; - $dropy = $zo->getY() - ($olddrop * 0.05 + 0.0125); - $posd0 = new Vector3 (floor($zo->getX()), floor($dropy), floor($zo->getZ())); - $posd = new Vector3 ($zo->getX(), $dropy, $zo->getZ()); - if ($this->AIHolder->whatBlock($zo->getLevel(), $posd0) == "air") { - $zo->setPosition($posd->add(0,1,0)); //下降 - } else { - for ($i = 1; $i <= $drop; $i++) { - $posd0->y++; - if ($this->AIHolder->whatBlock($zo->getLevel(), $posd0) != "block") { - $posd->y = $posd0->y; - //$zo->setPosition($posd); //下降完成 - $h = $zom['drop'] * $zom['drop'] / 20; - $damage = $h - 3; - //echo($h . ": " . $damage . "\n"); - if ($damage > 0) { - $zo->setHealth($zo->getHealth() - $damage); - } - $zom['drop'] = false; - break; - } - } - } - } else { - $drop = 0; - } - - if ($zom['IsChasing'] !== false) { - //var_dump($zom['IsChasing']); - if (!$zom['knockBack']) { - //echo $zy; - $zom['up'] = 0; - if ($this->AIHolder->whatBlock($level, $pos) == "water") { - $zom['swim'] += 1; - if ($zom['swim'] >= 20) $zom['swim'] = 0; - } else { - $zom['swim'] = 0; - } - //echo("目标:".$zo->getY()." "); - //echo("原先:".$zom['oldv3']->y."\n"); - - if(abs($zo->getY() - $zom['oldv3']->y) == 1 and $zom['canjump'] === true){ - //var_dump("跳"); - $zom['canjump'] = false; - $zom['jump'] = 0.5; - } - else { - if ($zom['jump'] > 0.01) { - $zom['jump'] -= 0.1; - } - else { - $zom['jump'] = 0.01; - } - } - - - - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['xxx'] / 10, -$zom['swim'] / 100 + $zom['jump'] - $drop, $zom['zzz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - - $p = $this->AIHolder->getServer()->getPlayer($zom['IsChasing']); - if ($p instanceof Player) { - if ($p->distance($pos) <= 1.3) { - //苦力怕的火焰点燃人类 - // if ($zo->fireTicks > 0) { - // $p->setOnFire(5); - // } - } - - if ($p->distance($pos) <= 2) { - //boom - $zom['boom'] = 5; - } - - if ($p->distance($pos) <= 1.5) { - - if ($zom['canAttack'] == 0) { - $zom['canAttack'] = 20; - @$p->knockBack($zo, 0, $zom['xxx'] / 10, $zom['zzz'] / 10); - if ($p->isSurvival()) { - $damage = 0; - //echo $zoDamage."-".$damage."\n"; - //$p->attack($damage); - } - } - } - } - } - - } else { - //echo "."; - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10, 0, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - } - }else{ - $zom['boom'] = $zom['boom'] - 1 ; - if($zom['boom'] <= 0){ - unset($this->AIHolder->Creeper[$zo->getId()]); - $level->getEntity($zo->getId())->close(); - $e = new Explosion(new Position($zo->getX(), $zo->getY(), $zo->getZ(), $level),4); - if($this->AIHolder->getServer()->aiConfig["creeperexplode"]) $e->explode(); - else $e->explodeB(); - - } - - - } - } - } - } - } - } - -} diff --git a/src/devmine/creatures/entities/ai/IronGolemAI.php b/src/devmine/creatures/entities/ai/IronGolemAI.php deleted file mode 100644 index 5cc04f0..0000000 --- a/src/devmine/creatures/entities/ai/IronGolemAI.php +++ /dev/null @@ -1,563 +0,0 @@ -AIHolder = $AIHolder; - if($this->AIHolder->getServer()->aiConfig["irongolem"]){ - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieRandomWalkCalc" - ] ), 10); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieRandomWalk" - ] ), 1); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieHateWalk" - ] ), 10); - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieHateFinder" - ] ), 10); - /*$this->plugin->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieFire" - ] ), 40);*/ - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "array_clear" - ] ), 20 * 5); - } - } - - public function array_clear() { - if (count($this->AIHolder->irongolem) != 0) { - foreach ($this->AIHolder->irongolem as $eid=> $info) { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - if (!($level->getEntity($eid) instanceof Entity)) { - unset($this->AIHolder->irongolem[$eid]); - //echo "清除 $eid \n"; - } - } - } - } - } - - /** - * 僵尸初始化,常规化及自由行走模式循环计时器 - * 循环间隔:20 ticks - */ - public function ZombieRandomWalkCalc() { - $this->dif = $this->AIHolder->getServer()->getDifficulty(); - //$this->getLogger()->info("僵尸数量:".count($this->plugin->irongolem)); - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo){ - if($zo instanceof Zombie){ - if ($this->AIHolder->willMove($zo)) { - if (!isset($this->AIHolder->irongolem[$zo->getId()])){ - $this->AIHolder->irongolem[$zo->getId()] = array( - 'ID' => $zo->getId(), - 'IsChasing' => false, - 'motionx' => 0, - 'motiony' => 0, - 'motionz' => 0, - 'hurt' => 10, - 'time'=>10, - 'x' => 0, - 'y' => 0, - 'z' => 0, - 'oldv3' => $zo->getLocation(), - 'yup' => 20, - 'up' => 0, - 'yaw' => $zo->yaw, - 'pitch' => 0, - 'level' => $zo->getLevel()->getName(), - 'xxx' => 0, - 'zzz' => 0, - 'gotimer' => 10, - 'swim' => 0, - 'jump' => 0.01, - 'canjump' => true, - 'drop' => false, - 'canAttack' => 0, - 'knockBack' => false, - ); - $zom = &$this->AIHolder->irongolem[$zo->getId()]; - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - $zom = &$this->AIHolder->irongolem[$zo->getId()]; - - if ($zom['IsChasing'] === false) { //自由行走模式 - if ($zom['gotimer'] == 0 or $zom['gotimer'] == 10) { - //限制转动幅度 - $newmx = mt_rand(-5,5)/10; - while (abs($newmx - $zom['motionx']) >= 0.7) { - $newmx = mt_rand(-5,5)/10; - } - $zom['motionx'] = $newmx; - - $newmz = mt_rand(-5,5)/10; - while (abs($newmz - $zom['motionz']) >= 0.7) { - $newmz = mt_rand(-5,5)/10; - } - $zom['motionz'] = $newmz; - } - elseif ($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24) { - $zom['motionx'] = 0; - $zom['motionz'] = 0; - //僵尸停止 - } - - $zom['gotimer'] += 0.5; - if ($zom['gotimer'] >= 22) $zom['gotimer'] = 0; //重置走路计时器 - - //$zom['motionx'] = mt_rand(-10,10)/10; - //$zom['motionz'] = mt_rand(-10,10)/10; - $zom['yup'] = 0; - $zom['up'] = 0; - - //boybook的y轴判断法 - //$width = $this->width; - $pos = new Vector3 ($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1,$zom['z'] + $zom['motionz']); //目标坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(),$pos); - if ($zy === false) { //前方不可前进 - $pos2 = new Vector3 ($zom['x'], $zom['y'] ,$zom['z']); //目标坐标 - if ($this->AIHolder->ifjump($zo->getLevel(),$pos2) === false) { //原坐标依然是悬空 - $pos2 = new Vector3 ($zom['x'], $zom['y']-1,$zom['z']); //下降 - $zom['up'] = 1; - $zom['yup'] = 0; - } - else { - $zom['motionx'] = - $zom['motionx']; - $zom['motionz'] = - $zom['motionz']; - //转向180度,向身后走 - $zom['up'] = 0; - } - } - else { - $pos2 = new Vector3 ($zom['x'] + $zom['motionx'], $zy - 1 ,$zom['z'] + $zom['motionz']); //目标坐标 - if ($pos2->y - $zom['y'] < 0) { - $zom['up'] = 1; - } - else { - $zom['up'] = 0; - } - } - - if ($zom['motionx'] == 0 and $zom['motionz'] == 0) { //僵尸停止 - } - else { - //转向计算 - $yaw = $this->AIHolder->getyaw($zom['motionx'], $zom['motionz']); - //$zo->setRotation($yaw,0); - $zom['yaw'] = $yaw; - $zom['pitch'] = 0; - } - - //更新僵尸坐标 - if (!$zom['knockBack']) { - $zom['x'] = $pos2->getX(); - $zom['z'] = $pos2->getZ(); - $zom['y'] = $pos2->getY(); - } - $zom['motiony'] = $pos2->getY() - $zo->getY(); - //echo($zo->getY()."\n"); - //var_dump($pos2); - //var_dump($zom['motiony']); - $zo->setPosition($pos2); - //echo "SetPosition \n"; - } - } - } - } - } - } - - /** - * 僵尸仇恨刷新计时器 - * 循环间隔:10 ticks - */ - public function ZombieHateFinder() { - foreach ($this->AIHolder->getServer()->getLevels () as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Zombie) { - if (isset($this->AIHolder->irongolem[$zo->getId()])) { - $zom = &$this->AIHolder->irongolem[$zo->getId()]; - $h_r = $this->hatred_r; //仇恨半径 - $pos = new Vector3($zo->getX(), $zo->getY(), $zo->getZ()); - $hatred = false; - foreach ($zo->getViewers() as $p) { //获取附近玩家 - if ($p->distance($pos) <= $h_r) { //玩家在仇恨半径内 - if ($hatred === false) { - $hatred = $p; - } elseif ($hatred instanceof Monster) { - if ($p->distance($pos) <= $hatred->distance($pos)) { //比上一个更近 - $hatred = $p; - } - } - } - } - //echo ($zom['IsChasing']."\n"); - if ($hatred == false or $this->dif == 0) { - $zom['IsChasing'] = false; - } else { - $zom['IsChasing'] = $hatred; - } - } - } - } - } - } - - /** - * 僵尸仇恨模式坐标更新计时器 - * 循环间隔:10 ticks - */ - public function ZombieHateWalk() { - foreach ($this->AIHolder->getServer()->getLevels () as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Zombie) { - if (isset($this->AIHolder->irongolem[$zo->getId()])) { - $zom = &$this->AIHolder->irongolem[$zo->getId()]; - //$zom['yup'] = $zom['yup'] - 1; - if (!$zom['knockBack']) { - $zom['oldv3'] = $zo->getLocation(); - $zom['canjump'] = true; - - //僵尸碰撞检测 by boybook - foreach ($level->getEntities() as $zo0) { - if ($zo0 instanceof Zombie and !($zo0 == $zo)) { - if ($zo->distance($zo0) <= $this->width * 2) { - $dx = $zo->x - $zo0->x; - $dz = $zo->z - $zo0->z; - if ($dx == 0) { - $dx = mt_rand(-5,5) / 5; - if ($dx == 0) $dx = 1; - } - if ($dz == 0) { - $dz = mt_rand(-5,5) / 5; - if ($dz == 0) $dz = 1; - } - $zo->knockBack($zo0,0,$dx/5,$dz/5,0); - $newpos = new Vector3($zo->x + $dx * 5, $zo->y, $zo->z + $dz * 5); - $zom['x'] = $newpos->x; - $zom['y'] = $newpos->y; - $zom['z'] = $newpos->z; - $this->AIHolder->getServer()->getScheduler()->scheduleDelayedTask(new CallbackTask([$this->AIHolder,"knockBackover"],[$zo,$newpos]),5); - } - } - - } - - if ($zom['IsChasing'] !== false) { - //echo ("是属于仇恨模式\n"); - $p = $zom['IsChasing']; - if (($p instanceof Monster) === false) { - $zom['IsChasing'] = false; //取消仇恨模式 - } else { - //真正的行走方向计算 - $xx = $p->getX() - $zo->getX(); - $zz = $p->getZ() - $zo->getZ(); - $yaw = $this->AIHolder->getyaw($xx,$zz); - /* - * x = $xxx, z = $zzz - * x0 = $xx, z0 = $zz - * x^2 + z^2 = 0.7 - * x/z = x0/z0 => x = bi * z - * => - * bi^2 * z^2 + z^2 = 0.7 - * z^2 * (bi^2 + 1) = 0.7 - * */ - if ($zz != 0) { - $bi = $xx/$zz; - }else{ - $bi = 0; - } - - //根据wiki:僵尸掉血后走路更快 - if ($zo->getHealth() == $zo->getMaxHealth()) { - $zzz = sqrt(($this->zo_hate_v / 2.5) / ($bi * $bi + 1)); - }else{ - $zzz = sqrt(($this->zo_hate_v / 2) / ($bi * $bi + 1)); - } - - if ($zz < 0) $zzz = -$zzz; - $xxx = $zzz * $bi; - - $zo_v2 = new Vector2($zo->getX(),$zo->getZ()); - $p_v2 = new Vector2($p->getX(),$p->getZ()); - if ($zo_v2->distance($p_v2) <= $this->zo_hate_v/2) { - $xxx = $xx; - $zzz = $zz; - } - - $zom['xxx'] = $xxx; - $zom['zzz'] = $zzz; - - //计算y轴 - //$width = $this->width; - $pos0 = new Vector3 ($zo->getX(), $zo->getY() + 1, $zo->getZ()); //原坐标 - $pos = new Vector3 ($zo->getX() + $xxx, $zo->getY() + 1, $zo->getZ() + $zzz); //目标坐标 - //用来写僵尸宽度的 - //$v = $this->zo_hate_v/2; - //$pos_front = new Vector3 ($zo->getX() + ($xxx/$v*($v+$this->width)), $zo->getY() + 1, $zo->getZ() + ($zzz/$v*($v+$this->width))); //前方坐标 - //$pos_back = new Vector3 ($zo->getX() + (-$xxx/$v*(-$v-$this->width)), $zo->getY() + 1, $zo->getZ() + (-$zzz/$v*(-$v-$this->width))); //后方坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(), $pos, true); - - if ($zy === false or ($zy !== false and $this->AIHolder->ifjump($zo->getLevel(), $pos0, true, true) == 'fall')) { //前方不可前进 - //真正的自由落体 by boybook - if ($this->AIHolder->ifjump($zo->getLevel(), $pos0, false) === false) { //原坐标依然是悬空 - if ($zom['drop'] === false) { - $zom['drop'] = 0; //僵尸下落的速度 - } - $pos2 = new Vector3 ($zo->getX(), $zo->getY() - ($zom['drop'] / 2 + 1.25), $zo->getZ()); //下降 - } else { - $zom['drop'] = false; - if ($this->AIHolder->whatBlock($level, $pos0) == "climb") { //梯子 - $zy = $pos0->y + 0.7; - $pos2 = new Vector3 ($zo->getX(), $zy - 1, $zo->getZ()); //目标坐标 - } - elseif ($xxx != 0 and $zzz != 0) { //走向最近距离 - if ($this->AIHolder->ifjump($zo->getLevel(), new Vector3($zo->getX() + $xxx, $zo->getY() + 1, $zo->getZ()), true) !== false) { - $pos2 = new Vector3($zo->getX() + $xxx, floor($zo->getY()), $zo->getZ()); //目标坐标 - } elseif ($this->AIHolder->ifjump($zo->getLevel(), new Vector3($zo->getX(), $zo->getY() + 1, $zo->getZ() + $zzz), true) !== false) { - $pos2 = new Vector3($zo->getX(), floor($zo->getY()), $zo->getZ() + $zzz); //目标坐标 - } else { - $pos2 = new Vector3 ($zo->getX() - $xxx / 5, floor($zo->getY()), $zo->getZ() - $zzz / 5); //目标坐标 - //转向180度,向身后走 - } - } else { - $pos2 = new Vector3 ($zo->getX() - $xxx / 5, floor($zo->getY()), $zo->getZ() - $zzz / 5); //目标坐标 - } - } - } else { - $pos2 = new Vector3 ($zo->getX() + $xxx, $zy - 1, $zo->getZ() + $zzz); //目标坐标 - } - $zo->setPosition($pos2); - - $pos3 = $pos2; - $pos3->y = $pos3->y + 2.62; - $ppos = $p->getLocation(); - $ppos->y = $ppos->y + $p->getEyeHeight(); - $pitch = $this->AIHolder->getpitch($pos3,$ppos); - - $zom['yaw'] = $yaw; - $zom['pitch'] = $pitch; - if (!$zom['knockBack']) { - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - } - } - } - } - } - } - } - } - - /** - * 高密集型发包计时器 - * - 发送数据包 - * - 计算自由落体相关数据 - * 循环间隔:1 tick - */ - public function ZombieRandomWalk() { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Zombie) { - if (isset($this->AIHolder->irongolem[$zo->getId()])) { - $zom = &$this->AIHolder->irongolem[$zo->getId()]; - if ($zom['canAttack'] != 0) { - $zom['canAttack'] -= 1; - } - $pos = $zo->getLocation(); - //echo ($zom['IsChasing']."\n"); - - //真正的自由落体 by boybook - if ($zom['drop'] !== false) { - $olddrop = $zom['drop']; - $zom['drop'] += 0.5; - $drop = $zom['drop']; - //echo $drop."\n"; - $dropy = $zo->getY() - ($olddrop * 0.05 + 0.0125); - $posd0 = new Vector3 (floor($zo->getX()), floor($dropy), floor($zo->getZ())); - $posd = new Vector3 ($zo->getX(), $dropy, $zo->getZ()); - if ($this->AIHolder->whatBlock($zo->getLevel(), $posd0) == "air") { - $zo->setPosition($posd); //下降 - } else { - for ($i = 1; $i <= $drop; $i++) { - $posd0->y++; - if ($this->AIHolder->whatBlock($zo->getLevel(), $posd0) != "block") { - $posd->y = $posd0->y; - $zo->setPosition($posd); //下降完成 - $h = $zom['drop'] * $zom['drop'] / 20; - $damage = $h - 3; - //echo($h . ": " . $damage . "\n"); - if ($damage > 0) { - //$zo->attack($damage, EntityDamageEvent::CAUSE_FALL); - $zo->setHealth($zo->getHealth() - $damage); - } - $zom['drop'] = false; - break; - } - } - } - } else { - $drop = 0; - } - - if ($zom['IsChasing'] !== false) { - if (!$zom['knockBack']) { - //echo $zy; - $zom['up'] = 0; - if ($this->AIHolder->whatBlock($level, $pos) == "water") { - $zom['swim'] += 1; - if ($zom['swim'] >= 20) $zom['swim'] = 0; - } else { - $zom['swim'] = 0; - } - //echo("目标:".$zo->getY()." "); - //echo("原先:".$zom['oldv3']->y."\n"); - - if(abs($zo->getY() - $zom['oldv3']->y) == 1 and $zom['canjump'] === true){ - //var_dump("跳"); - $zom['canjump'] = false; - $zom['jump'] = 0.5; - } - else { - if ($zom['jump'] > 0.01) { - $zom['jump'] -= 0.1; - } - else { - $zom['jump'] = 0.01; - } - } - - - - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['xxx'] / 10, -$zom['swim'] / 100 + $zom['jump'] - $drop, $zom['zzz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - - $p = $zom['IsChasing']; - if ($p instanceof Monster) { - if ($p->distance($pos) <= 1.3) { - //僵尸的火焰点燃人类 - if ($zo->fireTicks > 0) { - $p->setOnFire(1); - } - } - if ($p->distance($pos) <= 1.5) { - - if ($zom['canAttack'] == 0) { - $zom['canAttack'] = 20; - //@$p->knockBack($zo, 0, $zom['xxx'] / 10, $zom['zzz'] / 10); - if ($p->isSurvival()) { - $damage = 21; - //$damage = $this->plugin->getPlayerDamage($p, $zoDamage); - //echo $zoDamage."-".$damage."\n"; - $p->attack($damage, new EntityDamageByEntityEvent($zo,$p,EntityDamageEvent::CAUSE_ENTITY_ATTACK,$damage)); - } - } - } - } - } - - } else { - if ($zom['up'] == 1) { - if ($zom['yup'] <= 10) { - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10, $zom['motiony'] / 10, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - } else { - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10 - $zom['motiony'] / 10, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - } - } else { - - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10, -$zom['motiony'] / 10, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - - } - } - } - } - } - } - } - } - - /** - * 僵尸着火计时器 - * PM时间修复 - */ - public function ZombieFire() { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo){ - if ($zo instanceof Zombie) { - //var_dump($p->getLevel()->getTime()); - if(0 < $level->getTime() and $level->getTime() < 13500){ - $v3 = new Vector3($zo->getX(), $zo->getY(), $zo->getZ()); - $ok = true; - for ($y0 = $zo->getY() + 2; $y0 <= $zo->getY()+10; $y0++) { - $v3->y = $y0; - if ($level->getBlock($v3)->getID() != 0) { - $ok = false; - break; - } - } - if ($this->AIHolder->whatBlock($level,new Vector3($zo->getX(), floor($zo->getY() - 1), $zo->getZ())) == "water") $ok = false; - if ($ok) $zo->setOnFire(2); - } - } - } - } - } - -} diff --git a/src/devmine/creatures/entities/ai/PigAI.php b/src/devmine/creatures/entities/ai/PigAI.php deleted file mode 100644 index 09c56ed..0000000 --- a/src/devmine/creatures/entities/ai/PigAI.php +++ /dev/null @@ -1,228 +0,0 @@ -AIHolder = $AIHolder; - if($this->AIHolder->getServer()->aiConfig["pig"]){ - $this->AIHolder->getServer()->getScheduler()->scheduleRepeatingTask(new CallbackTask ([ - $this, - "PigRandomWalkCalc" - ]), 5); - - $this->AIHolder->getServer()->getScheduler()->scheduleRepeatingTask(new CallbackTask ([ - $this, - "PigRandomWalk" - ]), 1); - } - } - - public function PigRandomWalkCalc(){ - $this->dif = $this->AIHolder->getServer()->getDifficulty(); - //$this->getLogger()->info("猪数量:".count($this->plugin->Pig)); - foreach($this->AIHolder->getServer()->getLevels() as $level){ - foreach($level->getEntities() as $zo){ - if($zo::NETWORK_ID == Pig::NETWORK_ID){ - if($this->AIHolder->willMove($zo)){ - if(!isset($this->AIHolder->Pig[$zo->getId()])){ - $this->AIHolder->Pig[$zo->getId()] = array( - 'ID' => $zo->getId(), - 'IsChasing' => false, - 'motionx' => 0, - 'motiony' => 0, - 'motionz' => 0, - 'hurt' => 10, - 'time' => 10, - 'x' => 0, - 'y' => 0, - 'z' => 0, - 'oldv3' => $zo->getLocation(), - 'yup' => 20, - 'up' => 0, - 'yaw' => $zo->yaw, - 'pitch' => 0, - 'level' => $zo->getLevel()->getName(), - 'xxx' => 0, - 'zzz' => 0, - 'gotimer' => 10, - 'swim' => 0, - 'jump' => 0.01, - 'canjump' => true, - 'drop' => false, - 'canAttack' => 0, - 'knockBack' => false, - ); - $zom = &$this->AIHolder->Pig[$zo->getId()]; - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - $zom = &$this->AIHolder->Pig[$zo->getId()]; - - //if ($zom['IsChasing'] === false) { //自由行走模式 - - if($zom['gotimer'] == 0 or $zom['gotimer'] == 10){ - //限制转动幅度 - $newmx = mt_rand(-5, 5) / 10; - while(abs($newmx - $zom['motionx']) >= 0.7){ - $newmx = mt_rand(-5, 5) / 10; - } - $zom['motionx'] = $newmx; - - $newmz = mt_rand(-5, 5) / 10; - while(abs($newmz - $zom['motionz']) >= 0.7){ - $newmz = mt_rand(-5, 5) / 10; - } - $zom['motionz'] = $newmz; - }elseif($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24){ - $zom['motionx'] = 0; - $zom['motionz'] = 0; - //猪停止 - } - - $zom['gotimer'] += 0.5; - if($zom['gotimer'] >= 22) $zom['gotimer'] = 0; //重置走路计时器 - - //$zom['motionx'] = mt_rand(-10,10)/10; - //$zom['motionz'] = mt_rand(-10,10)/10; - $zom['yup'] = 0; - $zom['up'] = 0; - - //boybook的y轴判断法 - //$width = $this->width; - $pos = new Vector3 ($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1, $zom['z'] + $zom['motionz']); //目标坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(), $pos); - - if($zy === false){ //前方不可前进 - $pos2 = new Vector3 ($zom['x'], $zom['y'], $zom['z']); //目标坐标 - if($this->AIHolder->ifjump($zo->getLevel(), $pos2) === false){ //原坐标依然是悬空 - // $pos2 = new Vector3 ($zom['x'], $zom['y'],$zom['z']); //下降 - // $zom['up'] = 1; - $zom['yup'] = 0; - }else{ - // print($zy-$pos->y); - $zom['motionx'] = -$zom['motionx']; - $zom['motionz'] = -$zom['motionz']; - //$zom['motiony'] = 0.01; - //转向180度,向身后走 - $zom['up'] = 0; - } - }else{ - $pos2 = new Vector3 ($zom['x'] + $zom['motionx'], $zy - 1, $zom['z'] + $zom['motionz']); //目标坐标 - if($pos2->y - $zom['y'] < 0){ - $zom['up'] = 1; - }else{ - $zom['up'] = 0; - } - } - - if($zom['motionx'] == 0 and $zom['motionz'] == 0){ //牛停止 - }else{ - //转向计算 - $yaw = $this->AIHolder->getyaw($zom['motionx'], $zom['motionz']); - //$zo->setRotation($yaw,0); - $zom['yaw'] = $yaw; - $zom['pitch'] = 0; - } - - //更新坐标 - if(!$zom['knockBack']){ - $zom['x'] = $pos2->getX(); - $zom['z'] = $pos2->getZ(); - $zom['y'] = $pos2->getY(); - } - - $zom['motiony'] = $pos2->getY() - $zo->getY(); - //echo($zo->getY()."\n"); - //var_dump($pos2); - //var_dump($zom['motiony']); - $zo->setPosition($pos2); - //echo "SetPosition \n"; - } - //} - - } - } - } - } - - public function PigRandomWalk(){ - foreach($this->AIHolder->getServer()->getLevels() as $level){ - foreach($level->getEntities() as $zo){ - if($zo::NETWORK_ID == Pig::NETWORK_ID){ - if(isset($this->AIHolder->Pig[$zo->getId()])){ - $zom = &$this->AIHolder->Pig[$zo->getId()]; - if($zom['canAttack'] != 0){ - $zom['canAttack'] -= 1; - } - $pos = $zo->getLocation(); - //echo ($zom['IsChasing']."\n"); - - //真正的自由落体 by boybook - $downly = $zo->onGround; - - /* if ($zo->onGround != false) { - $downly=true; - - //$zom['motionY']=-0.04; - //zom['drop'] += 0.01; - } else { - $drop = 0; - - }*/ - if(abs($zo->getY() - $zom['oldv3']->y) == 1 and $zom['canjump'] === true){ - //var_dump("跳"); - $zom['canjump'] = false; - $zom['jump'] = 0.3; - }else{ - if($zom['jump'] > 0.01){ - $zom['jump'] -= 0.1; - }else{ - $zom['jump'] = 0; - } - } - - //echo "."; - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['xxx'], $zom['jump'] - $downly ? 0.04 : 0, $zom['zzz']] - ]; - foreach($zo->getViewers() as $pl){ - $pl->dataPacket($pk3); - } - - } - } - } - } - } - - public function array_clear(){ - if(count($this->AIHolder->Pig) != 0){ - foreach($this->AIHolder->Pig as $eid => $info){ - foreach($this->AIHolder->getServer()->getLevels() as $level){ - if(!($level->getEntity($eid) instanceof Entity)){ - unset($this->AIHolder->Pig[$eid]); - //echo "清除 $eid \n"; - } - } - } - } - } - - -} diff --git a/src/devmine/creatures/entities/ai/PigZombieAI.php b/src/devmine/creatures/entities/ai/PigZombieAI.php deleted file mode 100644 index 20ee0c2..0000000 --- a/src/devmine/creatures/entities/ai/PigZombieAI.php +++ /dev/null @@ -1,563 +0,0 @@ -AIHolder = $AIHolder; - if($this->AIHolder->getServer()->aiConfig["pigzombie"]){ - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieRandomWalkCalc" - ] ), 10); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieRandomWalk" - ] ), 1); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieHateWalk" - ] ), 10); - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieHateFinder" - ] ), 10); - /*$this->plugin->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieFire" - ] ), 40);*/ - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "array_clear" - ] ), 20 * 5); - } - } - - public function array_clear() { - if (count($this->AIHolder->pigzombie) != 0) { - foreach ($this->AIHolder->pigzombie as $eid=> $info) { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - if (!($level->getEntity($eid) instanceof Entity)) { - unset($this->AIHolder->pigzombie[$eid]); - //echo "清除 $eid \n"; - } - } - } - } - } - - /** - * 僵尸初始化,常规化及自由行走模式循环计时器 - * 循环间隔:20 ticks - */ - public function ZombieRandomWalkCalc() { - $this->dif = $this->AIHolder->getServer()->getDifficulty(); - //$this->getLogger()->info("僵尸数量:".count($this->plugin->pigzombie)); - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo){ - if($zo instanceof Zombie){ - if ($this->AIHolder->willMove($zo)) { - if (!isset($this->AIHolder->pigzombie[$zo->getId()])){ - $this->AIHolder->pigzombie[$zo->getId()] = array( - 'ID' => $zo->getId(), - 'IsChasing' => false, - 'motionx' => 0, - 'motiony' => 0, - 'motionz' => 0, - 'hurt' => 10, - 'time'=>10, - 'x' => 0, - 'y' => 0, - 'z' => 0, - 'oldv3' => $zo->getLocation(), - 'yup' => 20, - 'up' => 0, - 'yaw' => $zo->yaw, - 'pitch' => 0, - 'level' => $zo->getLevel()->getName(), - 'xxx' => 0, - 'zzz' => 0, - 'gotimer' => 10, - 'swim' => 0, - 'jump' => 0.01, - 'canjump' => true, - 'drop' => false, - 'canAttack' => 0, - 'knockBack' => false, - ); - $zom = &$this->AIHolder->pigzombie[$zo->getId()]; - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - $zom = &$this->AIHolder->pigzombie[$zo->getId()]; - - if ($zom['IsChasing'] === false) { //自由行走模式 - if ($zom['gotimer'] == 0 or $zom['gotimer'] == 10) { - //限制转动幅度 - $newmx = mt_rand(-5,5)/10; - while (abs($newmx - $zom['motionx']) >= 0.7) { - $newmx = mt_rand(-5,5)/10; - } - $zom['motionx'] = $newmx; - - $newmz = mt_rand(-5,5)/10; - while (abs($newmz - $zom['motionz']) >= 0.7) { - $newmz = mt_rand(-5,5)/10; - } - $zom['motionz'] = $newmz; - } - elseif ($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24) { - $zom['motionx'] = 0; - $zom['motionz'] = 0; - //僵尸停止 - } - - $zom['gotimer'] += 0.5; - if ($zom['gotimer'] >= 22) $zom['gotimer'] = 0; //重置走路计时器 - - //$zom['motionx'] = mt_rand(-10,10)/10; - //$zom['motionz'] = mt_rand(-10,10)/10; - $zom['yup'] = 0; - $zom['up'] = 0; - - //boybook的y轴判断法 - //$width = $this->width; - $pos = new Vector3 ($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1,$zom['z'] + $zom['motionz']); //目标坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(),$pos); - if ($zy === false) { //前方不可前进 - $pos2 = new Vector3 ($zom['x'], $zom['y'] ,$zom['z']); //目标坐标 - if ($this->AIHolder->ifjump($zo->getLevel(),$pos2) === false) { //原坐标依然是悬空 - $pos2 = new Vector3 ($zom['x'], $zom['y']-1,$zom['z']); //下降 - $zom['up'] = 1; - $zom['yup'] = 0; - } - else { - $zom['motionx'] = - $zom['motionx']; - $zom['motionz'] = - $zom['motionz']; - //转向180度,向身后走 - $zom['up'] = 0; - } - } - else { - $pos2 = new Vector3 ($zom['x'] + $zom['motionx'], $zy - 1 ,$zom['z'] + $zom['motionz']); //目标坐标 - if ($pos2->y - $zom['y'] < 0) { - $zom['up'] = 1; - } - else { - $zom['up'] = 0; - } - } - - if ($zom['motionx'] == 0 and $zom['motionz'] == 0) { //僵尸停止 - } - else { - //转向计算 - $yaw = $this->AIHolder->getyaw($zom['motionx'], $zom['motionz']); - //$zo->setRotation($yaw,0); - $zom['yaw'] = $yaw; - $zom['pitch'] = 0; - } - - //更新僵尸坐标 - if (!$zom['knockBack']) { - $zom['x'] = $pos2->getX(); - $zom['z'] = $pos2->getZ(); - $zom['y'] = $pos2->getY(); - } - $zom['motiony'] = $pos2->getY() - $zo->getY(); - //echo($zo->getY()."\n"); - //var_dump($pos2); - //var_dump($zom['motiony']); - $zo->setPosition($pos2->add(0,-1,0)); - //echo "SetPosition \n"; - } - } - } - } - } - } - - /** - * 僵尸仇恨刷新计时器 - * 循环间隔:10 ticks - */ - public function ZombieHateFinder() { - foreach ($this->AIHolder->getServer()->getLevels () as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Zombie) { - if (isset($this->AIHolder->pigzombie[$zo->getId()])) { - $zom = &$this->AIHolder->pigzombie[$zo->getId()]; - $h_r = $this->hatred_r; //仇恨半径 - $pos = new Vector3($zo->getX(), $zo->getY(), $zo->getZ()); - $hatred = false; - foreach ($zo->getViewers() as $p) { //获取附近玩家 - if ($p->distance($pos) <= $h_r) { //玩家在仇恨半径内 - if ($hatred === false) { - $hatred = $p; - } elseif ($hatred instanceof Player) { - if ($p->distance($pos) <= $hatred->distance($pos)) { //比上一个更近 - $hatred = $p; - } - } - } - } - //echo ($zom['IsChasing']."\n"); - if ($hatred == false or $this->dif == 0) { - $zom['IsChasing'] = false; - } else { - $zom['IsChasing'] = $hatred->getName(); - } - } - } - } - } - } - - /** - * 僵尸仇恨模式坐标更新计时器 - * 循环间隔:10 ticks - */ - public function ZombieHateWalk() { - foreach ($this->AIHolder->getServer()->getLevels () as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Zombie) { - if (isset($this->AIHolder->pigzombie[$zo->getId()])) { - $zom = &$this->AIHolder->pigzombie[$zo->getId()]; - //$zom['yup'] = $zom['yup'] - 1; - if (!$zom['knockBack']) { - $zom['oldv3'] = $zo->getLocation(); - $zom['canjump'] = true; - - //僵尸碰撞检测 by boybook - foreach ($level->getEntities() as $zo0) { - if ($zo0 instanceof Zombie and !($zo0 == $zo)) { - if ($zo->distance($zo0) <= $this->width * 2) { - $dx = $zo->x - $zo0->x; - $dz = $zo->z - $zo0->z; - if ($dx == 0) { - $dx = mt_rand(-5,5) / 5; - if ($dx == 0) $dx = 1; - } - if ($dz == 0) { - $dz = mt_rand(-5,5) / 5; - if ($dz == 0) $dz = 1; - } - $zo->knockBack($zo0,0,$dx/5,$dz/5,0); - $newpos = new Vector3($zo->x + $dx * 5, $zo->y, $zo->z + $dz * 5); - $zom['x'] = $newpos->x; - $zom['y'] = $newpos->y; - $zom['z'] = $newpos->z; - $this->AIHolder->getServer()->getScheduler()->scheduleDelayedTask(new CallbackTask([$this->AIHolder,"knockBackover"],[$zo,$newpos]),5); - } - } - - } - - if ($zom['IsChasing'] !== false) { - //echo ("是属于仇恨模式\n"); - $p = $this->AIHolder->getServer()->getPlayer($zom['IsChasing']); - if (($p instanceof Player) === false) { - $zom['IsChasing'] = false; //取消仇恨模式 - } else { - //真正的行走方向计算 - $xx = $p->getX() - $zo->getX(); - $zz = $p->getZ() - $zo->getZ(); - $yaw = $this->AIHolder->getyaw($xx,$zz); - /* - * x = $xxx, z = $zzz - * x0 = $xx, z0 = $zz - * x^2 + z^2 = 0.7 - * x/z = x0/z0 => x = bi * z - * => - * bi^2 * z^2 + z^2 = 0.7 - * z^2 * (bi^2 + 1) = 0.7 - * */ - if ($zz != 0) { - $bi = $xx/$zz; - }else{ - $bi = 0; - } - - //根据wiki:僵尸掉血后走路更快 - if ($zo->getHealth() == $zo->getMaxHealth()) { - $zzz = sqrt(($this->zo_hate_v / 2.5) / ($bi * $bi + 1)); - }else{ - $zzz = sqrt(($this->zo_hate_v / 2) / ($bi * $bi + 1)); - } - - if ($zz < 0) $zzz = -$zzz; - $xxx = $zzz * $bi; - - $zo_v2 = new Vector2($zo->getX(),$zo->getZ()); - $p_v2 = new Vector2($p->getX(),$p->getZ()); - if ($zo_v2->distance($p_v2) <= $this->zo_hate_v/2) { - $xxx = $xx; - $zzz = $zz; - } - - $zom['xxx'] = $xxx; - $zom['zzz'] = $zzz; - - //计算y轴 - //$width = $this->width; - $pos0 = new Vector3 ($zo->getX(), $zo->getY() + 1, $zo->getZ()); //原坐标 - $pos = new Vector3 ($zo->getX() + $xxx, $zo->getY() + 1, $zo->getZ() + $zzz); //目标坐标 - //用来写僵尸宽度的 - //$v = $this->zo_hate_v/2; - //$pos_front = new Vector3 ($zo->getX() + ($xxx/$v*($v+$this->width)), $zo->getY() + 1, $zo->getZ() + ($zzz/$v*($v+$this->width))); //前方坐标 - //$pos_back = new Vector3 ($zo->getX() + (-$xxx/$v*(-$v-$this->width)), $zo->getY() + 1, $zo->getZ() + (-$zzz/$v*(-$v-$this->width))); //后方坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(), $pos, true); - - if ($zy === false or ($zy !== false and $this->AIHolder->ifjump($zo->getLevel(), $pos0, true, true) == 'fall')) { //前方不可前进 - //真正的自由落体 by boybook - if ($this->AIHolder->ifjump($zo->getLevel(), $pos0, false) === false) { //原坐标依然是悬空 - if ($zom['drop'] === false) { - $zom['drop'] = 0; //僵尸下落的速度 - } - $pos2 = new Vector3 ($zo->getX(), $zo->getY() - ($zom['drop'] / 2 + 1.25), $zo->getZ()); //下降 - } else { - $zom['drop'] = false; - if ($this->AIHolder->whatBlock($level, $pos0) == "climb") { //梯子 - $zy = $pos0->y + 0.7; - $pos2 = new Vector3 ($zo->getX(), $zy - 1, $zo->getZ()); //目标坐标 - } - elseif ($xxx != 0 and $zzz != 0) { //走向最近距离 - if ($this->AIHolder->ifjump($zo->getLevel(), new Vector3($zo->getX() + $xxx, $zo->getY() + 1, $zo->getZ()), true) !== false) { - $pos2 = new Vector3($zo->getX() + $xxx, floor($zo->getY()), $zo->getZ()); //目标坐标 - } elseif ($this->AIHolder->ifjump($zo->getLevel(), new Vector3($zo->getX(), $zo->getY() + 1, $zo->getZ() + $zzz), true) !== false) { - $pos2 = new Vector3($zo->getX(), floor($zo->getY()), $zo->getZ() + $zzz); //目标坐标 - } else { - $pos2 = new Vector3 ($zo->getX() - $xxx / 5, floor($zo->getY()), $zo->getZ() - $zzz / 5); //目标坐标 - //转向180度,向身后走 - } - } else { - $pos2 = new Vector3 ($zo->getX() - $xxx / 5, floor($zo->getY()), $zo->getZ() - $zzz / 5); //目标坐标 - } - } - } else { - $pos2 = new Vector3 ($zo->getX() + $xxx, $zy - 1, $zo->getZ() + $zzz); //目标坐标 - } - $zo->setPosition($pos2->add(0,-1,0)); - - $pos3 = $pos2; - $pos3->y = $pos3->y + 2.62; - $ppos = $p->getLocation(); - $ppos->y = $ppos->y + $p->getEyeHeight(); - $pitch = $this->AIHolder->getpitch($pos3,$ppos); - - $zom['yaw'] = $yaw; - $zom['pitch'] = $pitch; - if (!$zom['knockBack']) { - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - } - } - } - } - } - } - } - } - - /** - * 高密集型发包计时器 - * - 发送数据包 - * - 计算自由落体相关数据 - * 循环间隔:1 tick - */ - public function ZombieRandomWalk() { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Zombie) { - if (isset($this->AIHolder->pigzombie[$zo->getId()])) { - $zom = &$this->AIHolder->pigzombie[$zo->getId()]; - if ($zom['canAttack'] != 0) { - $zom['canAttack'] -= 1; - } - $pos = $zo->getLocation(); - //echo ($zom['IsChasing']."\n"); - - //真正的自由落体 by boybook - if ($zom['drop'] !== false) { - $olddrop = $zom['drop']; - $zom['drop'] += 0.5; - $drop = $zom['drop']; - //echo $drop."\n"; - $dropy = $zo->getY() - ($olddrop * 0.05 + 0.0125); - $posd0 = new Vector3 (floor($zo->getX()), floor($dropy), floor($zo->getZ())); - $posd = new Vector3 ($zo->getX(), $dropy, $zo->getZ()); - if ($this->AIHolder->whatBlock($zo->getLevel(), $posd0) == "air") { - $zo->setPosition($posd->add(0,-1,0)); //下降 - } else { - for ($i = 1; $i <= $drop; $i++) { - $posd0->y++; - if ($this->AIHolder->whatBlock($zo->getLevel(), $posd0) != "block") { - $posd->y = $posd0->y; - $zo->setPosition($posd->add(0,-1,0)); //下降完成 - $h = $zom['drop'] * $zom['drop'] / 20; - $damage = $h - 3; - //echo($h . ": " . $damage . "\n"); - if ($damage > 0) { - //$zo->attack($damage, EntityDamageEvent::CAUSE_FALL); - $zo->setHealth($zo->getHealth() - $damage); - } - $zom['drop'] = false; - break; - } - } - } - } else { - $drop = 0; - } - - if ($zom['IsChasing'] !== false) { - if (!$zom['knockBack']) { - //echo $zy; - $zom['up'] = 0; - if ($this->AIHolder->whatBlock($level, $pos) == "water") { - $zom['swim'] += 1; - if ($zom['swim'] >= 20) $zom['swim'] = 0; - } else { - $zom['swim'] = 0; - } - //echo("目标:".$zo->getY()." "); - //echo("原先:".$zom['oldv3']->y."\n"); - - if(abs($zo->getY() - $zom['oldv3']->y) == 1 and $zom['canjump'] === true){ - //var_dump("跳"); - $zom['canjump'] = false; - $zom['jump'] = 0.5; - } - else { - if ($zom['jump'] > 0.01) { - $zom['jump'] -= 0.1; - } - else { - $zom['jump'] = 0.01; - } - } - - - - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['xxx'] / 10, -$zom['swim'] / 100 + $zom['jump'] - $drop, $zom['zzz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - - $p = $this->AIHolder->getServer()->getPlayer($zom['IsChasing']); - if ($p instanceof Player) { - if ($p->distance($pos) <= 1.3) { - //僵尸的火焰点燃人类 - if ($zo->fireTicks > 0) { - $p->setOnFire(1); - } - } - if ($p->distance($pos) <= 1.5) { - - if ($zom['canAttack'] == 0) { - $zom['canAttack'] = 20; - //@$p->knockBack($zo, 0, $zom['xxx'] / 10, $zom['zzz'] / 10); - if ($p->isSurvival()) { - $zoDamage = $this->AIHolder->getZombieDamage($zo->getHealth()); - $damage = $this->AIHolder->getPlayerDamage($p, $zoDamage); - //echo $zoDamage."-".$damage."\n"; - $p->attack($damage, new EntityDamageByEntityEvent($zo,$p,EntityDamageEvent::CAUSE_ENTITY_ATTACK,$damage)); - } - } - } - } - } - - } else { - if ($zom['up'] == 1) { - if ($zom['yup'] <= 10) { - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10, $zom['motiony'] / 10, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - } else { - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10 - $zom['motiony'] / 10, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - } - } else { - - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10, -$zom['motiony'] / 10, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - - } - } - } - } - } - } - } - } - - /** - * 僵尸着火计时器 - * PM时间修复 - */ - public function ZombieFire() { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo){ - if ($zo instanceof Zombie) { - //var_dump($p->getLevel()->getTime()); - if(0 < $level->getTime() and $level->getTime() < 13500){ - $v3 = new Vector3($zo->getX(), $zo->getY(), $zo->getZ()); - $ok = true; - for ($y0 = $zo->getY() + 2; $y0 <= $zo->getY()+10; $y0++) { - $v3->y = $y0; - if ($level->getBlock($v3)->getID() != 0) { - $ok = false; - break; - } - } - if ($this->AIHolder->whatBlock($level,new Vector3($zo->getX(), floor($zo->getY() - 1), $zo->getZ())) == "water") $ok = false; - if ($ok) $zo->setOnFire(2); - } - } - } - } - } - -} diff --git a/src/devmine/creatures/entities/ai/SheepAI.php b/src/devmine/creatures/entities/ai/SheepAI.php deleted file mode 100644 index 454c54a..0000000 --- a/src/devmine/creatures/entities/ai/SheepAI.php +++ /dev/null @@ -1,237 +0,0 @@ -AIHolder = $AIHolder; - if($this->AIHolder->getServer()->aiConfig["sheep"]){ - $this->AIHolder->getServer()->getScheduler()->scheduleRepeatingTask(new CallbackTask ([ - $this, - "SheepRandomWalkCalc" - ]), 5); - - $this->AIHolder->getServer()->getScheduler()->scheduleRepeatingTask(new CallbackTask ([ - $this, - "SheepRandomWalk" - ]), 1); - $this->AIHolder->getServer()->getScheduler()->scheduleRepeatingTask(new CallbackTask ([ - $this, - "array_clear" - ]), 20 * 5); - } - } - - public function SheepRandomWalkCalc(){ - $this->dif = $this->AIHolder->getServer()->getDifficulty(); - //$this->getLogger()->info("羊数量:".count($this->plugin->Sheep)); - foreach($this->AIHolder->getServer()->getLevels() as $level){ - foreach($level->getEntities() as $zo){ - if($zo instanceof Sheep){ - if($this->AIHolder->willMove($zo)){ - if(!isset($this->AIHolder->Sheep[$zo->getId()])){ - $this->AIHolder->Sheep[$zo->getId()] = array( - 'ID' => $zo->getId(), - 'IsChasing' => false, - 'motionx' => 0, - 'motiony' => 0, - 'motionz' => 0, - 'hurt' => 10, - 'time' => 10, - 'x' => 0, - 'y' => 0, - 'z' => 0, - 'oldv3' => $zo->getLocation(), - 'yup' => 20, - 'up' => 0, - 'yaw' => $zo->yaw, - 'pitch' => 0, - 'level' => $zo->getLevel()->getName(), - 'xxx' => 0, - 'zzz' => 0, - 'gotimer' => 10, - 'swim' => 0, - 'jump' => 0.01, - 'canjump' => true, - 'drop' => false, - 'canAttack' => 0, - 'knockBack' => false, - ); - $zom = &$this->AIHolder->Sheep[$zo->getId()]; - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - $zom = &$this->AIHolder->Sheep[$zo->getId()]; - - if($zom['IsChasing'] === false){ //自由行走模式 - if($zom['gotimer'] == 0 or $zom['gotimer'] == 10){ - //限制转动幅度 - $newmx = mt_rand(-5, 5) / 10; - while(abs($newmx - $zom['motionx']) >= 0.7){ - $newmx = mt_rand(-5, 5) / 10; - } - $zom['motionx'] = $newmx; - - $newmz = mt_rand(-5, 5) / 10; - while(abs($newmz - $zom['motionz']) >= 0.7){ - $newmz = mt_rand(-5, 5) / 10; - } - $zom['motionz'] = $newmz; - }elseif($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24){ - $zom['motionx'] = 0; - $zom['motionz'] = 0; - //羊停止 - } - - $zom['gotimer'] += 0.5; - if($zom['gotimer'] >= 22) $zom['gotimer'] = 0; //重置走路计时器 - - //$zom['motionx'] = mt_rand(-10,10)/10; - //$zom['motionz'] = mt_rand(-10,10)/10; - $zom['yup'] = 0; - $zom['up'] = 0; - - //boybook的y轴判断法 - //$width = $this->width; - $pos = new Vector3 ($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1, $zom['z'] + $zom['motionz']); //目标坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(), $pos); - if($zy === false){ //前方不可前进 - $pos2 = new Vector3 ($zom['x'], $zom['y'], $zom['z']); //目标坐标 - if($this->AIHolder->ifjump($zo->getLevel(), $pos2) === false){ //原坐标依然是悬空 - $pos2 = new Vector3 ($zom['x'], $zom['y'] - 1, $zom['z']); //下降 - $zom['up'] = 1; - $zom['yup'] = 0; - }else{ - $zom['motionx'] = -$zom['motionx']; - $zom['motionz'] = -$zom['motionz']; - //转向180度,向身后走 - $zom['up'] = 0; - } - }else{ - $pos2 = new Vector3 ($zom['x'] + $zom['motionx'], $zy - 1, $zom['z'] + $zom['motionz']); //目标坐标 - if($pos2->y - $zom['y'] < 0){ - $zom['up'] = 1; - }else{ - $zom['up'] = 0; - } - } - - if($zom['motionx'] == 0 and $zom['motionz'] == 0){ //羊停止 - }else{ - //转向计算 - $yaw = $this->AIHolder->getyaw($zom['motionx'], $zom['motionz']); - //$zo->setRotation($yaw,0); - $zom['yaw'] = $yaw; - $zom['pitch'] = 0; - } - - //更新坐标 - if(!$zom['knockBack']){ - $zom['x'] = $pos2->getX(); - $zom['z'] = $pos2->getZ(); - $zom['y'] = $pos2->getY(); - } - $zom['motiony'] = $pos2->getY() - $zo->getY(); - //echo($zo->getY()."\n"); - //var_dump($pos2); - //var_dump($zom['motiony']); - $zo->setPosition($pos2); - //echo "SetPosition \n"; - } - } - } - } - } - } - - public function SheepRandomWalk(){ - foreach($this->AIHolder->getServer()->getLevels() as $level){ - foreach($level->getEntities() as $zo){ - if($zo instanceof Sheep){ - if(isset($this->AIHolder->Sheep[$zo->getId()])){ - $zom = &$this->AIHolder->Sheep[$zo->getId()]; - if($zom['canAttack'] != 0){ - $zom['canAttack'] -= 1; - } - $pos = $zo->getLocation(); - //echo ($zom['IsChasing']."\n"); - - //真正的自由落体 by boybook - if($zom['drop'] !== false){ - $olddrop = $zom['drop']; - $zom['drop'] += 0.5; - $drop = $zom['drop']; - //echo $drop."\n"; - $dropy = $zo->getY() - ($olddrop * 0.05 + 0.0125); - $posd0 = new Vector3 (floor($zo->getX()), floor($dropy), floor($zo->getZ())); - $posd = new Vector3 ($zo->getX(), $dropy, $zo->getZ()); - if($this->AIHolder->whatBlock($zo->getLevel(), $posd0) == "air"){ - $zo->setPosition($posd); //下降 - }else{ - for($i = 1; $i <= $drop; $i++){ - $posd0->y++; - if($this->AIHolder->whatBlock($zo->getLevel(), $posd0) != "block"){ - $posd->y = $posd0->y; - //$zo->setPosition($posd); //下降完成 - $h = $zom['drop'] * $zom['drop'] / 20; - $damage = $h - 3; - //echo($h . ": " . $damage . "\n"); - if($damage > 0){ - $zo->attack($damage, EntityDamageEvent::CAUSE_FALL); - } - $zom['drop'] = false; - break; - } - } - } - }else{ - $drop = 0; - } - //echo "."; - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10, 0, $zom['motionz'] / 10] - ]; - foreach($zo->getViewers() as $pl){ - $pl->dataPacket($pk3); - } - - } - } - } - } - } - - public function array_clear(){ - if(count($this->AIHolder->Sheep) != 0){ - foreach($this->AIHolder->Sheep as $eid => $info){ - foreach($this->AIHolder->getServer()->getLevels() as $level){ - if(!($level->getEntity($eid) instanceof Entity)){ - unset($this->AIHolder->Sheep[$eid]); - //echo "清除 $eid \n"; - } - } - } - } - } - - -} diff --git a/src/devmine/creatures/entities/ai/SkeletonAI.php b/src/devmine/creatures/entities/ai/SkeletonAI.php deleted file mode 100644 index 649c4e7..0000000 --- a/src/devmine/creatures/entities/ai/SkeletonAI.php +++ /dev/null @@ -1,609 +0,0 @@ -AIHolder = $AIHolder; - if($this->AIHolder->getServer()->aiConfig["skeleton"]){ - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "SkeletonRandomWalkCalc" - ] ), 10); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "SkeletonRandomWalk" - ] ), 1); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "SkeletonHateWalk" - ] ), 10); - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "SkeletonHateFinder" - ] ), 10); - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "SkeletonFire" - ] ), 40); - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "array_clear" - ] ), 20 * 5); - } - } - - public function array_clear() { - if (count($this->AIHolder->Skeleton) != 0) { - foreach ($this->AIHolder->Skeleton as $eid=> $info) { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - if (!($level->getEntity($eid) instanceof Entity)) { - unset($this->AIHolder->Skeleton[$eid]); - //echo "清除 $eid \n"; - } - } - } - } - } - - public function SkeletonRandomWalkCalc() { - $this->dif = $this->AIHolder->getServer()->getDifficulty(); - //$this->getLogger()->info("僵尸数量:".count($this->plugin->Skeleton)); - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo){ - if($zo instanceof Skeleton){ - if ($this->AIHolder->willMove($zo)) { - if (!isset($this->AIHolder->Skeleton[$zo->getId()])){ - $this->AIHolder->Skeleton[$zo->getId()] = array( - 'ID' => $zo->getId(), - 'IsChasing' => false, - 'motionx' => 0, - 'motiony' => 0, - 'motionz' => 0, - 'hurt' => 10, - 'time'=>10, - 'x' => 0, - 'y' => 0, - 'z' => 0, - 'oldv3' => $zo->getLocation(), - 'yup' => 20, - 'up' => 0, - 'yaw' => $zo->yaw, - 'pitch' => 0, - 'level' => $zo->getLevel()->getName(), - 'xxx' => 0, - 'zzz' => 0, - 'gotimer' => 10, - 'swim' => 0, - 'jump' => 0.01, - 'canjump' => true, - 'drop' => false, - 'canAttack' => 0, - 'shoot' => 20, - 'knockBack' => false, - ); - $zom = &$this->AIHolder->Skeleton[$zo->getId()]; - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - $zom = &$this->AIHolder->Skeleton[$zo->getId()]; - - if ($zom['IsChasing'] === false) { //自由行走模式 - if ($zom['gotimer'] == 0 or $zom['gotimer'] == 10) { - //限制转动幅度 - $newmx = mt_rand(-5,5)/10; - while (abs($newmx - $zom['motionx']) >= 0.7) { - $newmx = mt_rand(-5,5)/10; - } - $zom['motionx'] = $newmx; - - $newmz = mt_rand(-5,5)/10; - while (abs($newmz - $zom['motionz']) >= 0.7) { - $newmz = mt_rand(-5,5)/10; - } - $zom['motionz'] = $newmz; - } - elseif ($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24) { - $zom['motionx'] = 0; - $zom['motionz'] = 0; - //僵尸停止 - } - - $zom['gotimer'] += 0.5; - if ($zom['gotimer'] >= 22) $zom['gotimer'] = 0; //重置走路计时器 - - //$zom['motionx'] = mt_rand(-10,10)/10; - //$zom['motionz'] = mt_rand(-10,10)/10; - $zom['yup'] = 0; - $zom['up'] = 0; - - //boybook的y轴判断法 - //$width = $this->width; - $pos = new Vector3 ($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1,$zom['z'] + $zom['motionz']); //目标坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(),$pos); - if ($zy === false) { //前方不可前进 - $pos2 = new Vector3 ($zom['x'], $zom['y'] ,$zom['z']); //目标坐标 - if ($this->AIHolder->ifjump($zo->getLevel(),$pos2) === false) { //原坐标依然是悬空 - $pos2 = new Vector3 ($zom['x'], $zom['y']-1,$zom['z']); //下降 - $zom['up'] = 1; - $zom['yup'] = 0; - } - else { - $zom['motionx'] = - $zom['motionx']; - $zom['motionz'] = - $zom['motionz']; - //转向180度,向身后走 - $zom['up'] = 0; - } - } - else { - $pos2 = new Vector3 ($zom['x'] + $zom['motionx'], $zy - 1 ,$zom['z'] + $zom['motionz']); //目标坐标 - if ($pos2->y - $zom['y'] < 0) { - $zom['up'] = 1; - } - else { - $zom['up'] = 0; - } - } - - if ($zom['motionx'] == 0 and $zom['motionz'] == 0) { //僵尸停止 - } - else { - //转向计算 - $yaw = $this->AIHolder->getyaw($zom['motionx'], $zom['motionz']); - //$zo->setRotation($yaw,0); - $zom['yaw'] = $yaw; - $zom['pitch'] = 0; - } - - //更新僵尸坐标 - if (!$zom['knockBack']) { - $zom['x'] = $pos2->getX(); - $zom['z'] = $pos2->getZ(); - $zom['y'] = $pos2->getY(); - } - $zom['motiony'] = $pos2->getY() - $zo->getY(); - //echo($zo->getY()."\n"); - //var_dump($pos2); - //var_dump($zom['motiony']); - $zo->setPosition($pos2->add(0,1,0)); - //echo "SetPosition \n"; - } - } - } - } - } - } - - public function SkeletonHateFinder() { - foreach ($this->AIHolder->getServer()->getLevels () as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Skeleton) { - if (isset($this->AIHolder->Skeleton[$zo->getId()])) { - $zom = &$this->AIHolder->Skeleton[$zo->getId()]; - $h_r = $this->hatred_r; //仇恨半径 - $pos = new Vector3($zo->getX(), $zo->getY(), $zo->getZ()); - $hatred = false; - foreach ($zo->getViewers() as $p) { //获取附近玩家 - if ($p->distance($pos) <= $h_r) { //玩家在仇恨半径内 - if ($hatred === false) { - $hatred = $p; - } elseif ($hatred instanceof Player) { - if ($p->distance($pos) <= $hatred->distance($pos)) { //比上一个更近 - $hatred = $p; - } - } - } - } - //echo ($zom['IsChasing']."\n"); - if ($hatred == false or $this->dif == 0) { - $zom['IsChasing'] = false; - } else { - $zom['IsChasing'] = $hatred->getName(); - } - } - } - } - } - } - - public function SkeletonHateWalk() { - foreach ($this->AIHolder->getServer()->getLevels () as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Skeleton) { - if (isset($this->AIHolder->Skeleton[$zo->getId()])) { - $zom = &$this->AIHolder->Skeleton[$zo->getId()]; - //$zom['yup'] = $zom['yup'] - 1; - if (!$zom['knockBack']) { - $zom['oldv3'] = $zo->getLocation(); - $zom['canjump'] = true; - - //僵尸碰撞检测 by boybook - foreach ($level->getEntities() as $zo0) { - if ($zo0 instanceof Skeleton and !($zo0 == $zo)) { - if ($zo->distance($zo0) <= $this->width * 2) { - $dx = $zo->x - $zo0->x; - $dz = $zo->z - $zo0->z; - if ($dx == 0) { - $dx = mt_rand(-5,5) / 5; - if ($dx == 0) $dx = 1; - } - if ($dz == 0) { - $dz = mt_rand(-5,5) / 5; - if ($dz == 0) $dz = 1; - } - $zo->knockBack($zo0,0,$dx/5,$dz/5,0); - $newpos = new Vector3($zo->x + $dx * 5, $zo->y, $zo->z + $dz * 5); - $zom['x'] = $newpos->x; - $zom['y'] = $newpos->y; - $zom['z'] = $newpos->z; - $this->AIHolder->getServer()->getScheduler()->scheduleDelayedTask(new CallbackTask([$this->AIHolder,"knockBackover"],[$zo,$newpos]),5); - } - } - - } - - if ($zom['IsChasing'] !== false) { - //echo ("是属于仇恨模式\n"); - $p = $this->AIHolder->getServer()->getPlayer($zom['IsChasing']); - if (($p instanceof Player) === false) { - $zom['IsChasing'] = false; //取消仇恨模式 - } else { - //真正的行走方向计算 - $xx = $p->getX() - $zo->getX(); - $zz = $p->getZ() - $zo->getZ(); - $yaw = $this->AIHolder->getyaw($xx,$zz); - /* - * x = $xxx, z = $zzz - * x0 = $xx, z0 = $zz - * x^2 + z^2 = 0.7 - * x/z = x0/z0 => x = bi * z - * => - * bi^2 * z^2 + z^2 = 0.7 - * z^2 * (bi^2 + 1) = 0.7 - * */ - if ($zz != 0) { - $bi = $xx/$zz; - }else{ - $bi = 0; - } - - //根据wiki:僵尸掉血后走路更快 - if ($zo->getHealth() == $zo->getMaxHealth()) { - $zzz = sqrt(($this->zo_hate_v / 2.5) / ($bi * $bi + 1)); - }else{ - $zzz = sqrt(($this->zo_hate_v / 2) / ($bi * $bi + 1)); - } - - if ($zz < 0) $zzz = -$zzz; - $xxx = $zzz * $bi; - - $zo_v2 = new Vector2($zo->getX(),$zo->getZ()); - $p_v2 = new Vector2($p->getX(),$p->getZ()); - if ($zo_v2->distance($p_v2) <= $this->zo_hate_v/2) { - $xxx = $xx; - $zzz = $zz; - } - - $zom['xxx'] = $xxx; - $zom['zzz'] = $zzz; - - //计算y轴 - //$width = $this->width; - $pos0 = new Vector3 ($zo->getX(), $zo->getY() + 1, $zo->getZ()); //原坐标 - $pos = new Vector3 ($zo->getX() + $xxx, $zo->getY() + 1, $zo->getZ() + $zzz); //目标坐标 - //用来写僵尸宽度的 - //$v = $this->zo_hate_v/2; - //$pos_front = new Vector3 ($zo->getX() + ($xxx/$v*($v+$this->width)), $zo->getY() + 1, $zo->getZ() + ($zzz/$v*($v+$this->width))); //前方坐标 - //$pos_back = new Vector3 ($zo->getX() + (-$xxx/$v*(-$v-$this->width)), $zo->getY() + 1, $zo->getZ() + (-$zzz/$v*(-$v-$this->width))); //后方坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(), $pos, true); - - if ($zy === false or ($zy !== false and $this->AIHolder->ifjump($zo->getLevel(), $pos0, true, true) == 'fall')) { //前方不可前进 - //真正的自由落体 by boybook - if ($this->AIHolder->ifjump($zo->getLevel(), $pos0, false) === false) { //原坐标依然是悬空 - if ($zom['drop'] === false) { - $zom['drop'] = 0; //僵尸下落的速度 - } - $pos2 = new Vector3 ($zo->getX(), $zo->getY() - ($zom['drop'] / 2 + 1.25), $zo->getZ()); //下降 - } else { - $zom['drop'] = false; - if ($this->AIHolder->whatBlock($level, $pos0) == "climb") { //梯子 - $zy = $pos0->y + 0.7; - $pos2 = new Vector3 ($zo->getX(), $zy - 1, $zo->getZ()); //目标坐标 - } - elseif ($xxx != 0 and $zzz != 0) { //走向最近距离 - if ($this->AIHolder->ifjump($zo->getLevel(), new Vector3($zo->getX() + $xxx, $zo->getY() + 1, $zo->getZ()), true) !== false) { - $pos2 = new Vector3($zo->getX() + $xxx, floor($zo->getY()), $zo->getZ()); //目标坐标 - } elseif ($this->AIHolder->ifjump($zo->getLevel(), new Vector3($zo->getX(), $zo->getY() + 1, $zo->getZ() + $zzz), true) !== false) { - $pos2 = new Vector3($zo->getX(), floor($zo->getY()), $zo->getZ() + $zzz); //目标坐标 - } else { - $pos2 = new Vector3 ($zo->getX() - $xxx / 5, floor($zo->getY()), $zo->getZ() - $zzz / 5); //目标坐标 - //转向180度,向身后走 - } - } else { - $pos2 = new Vector3 ($zo->getX() - $xxx / 5, floor($zo->getY()), $zo->getZ() - $zzz / 5); //目标坐标 - } - } - } else { - $pos2 = new Vector3 ($zo->getX() + $xxx, $zy - 1, $zo->getZ() + $zzz); //目标坐标 - } - $zo->setPosition($pos2->add(0,1,0)); - - $pos3 = $pos2; - $pos3->y = $pos3->y + 2.62; - $ppos = $p->getLocation(); - $ppos->y = $ppos->y + $p->getEyeHeight(); - $pitch = $this->AIHolder->getpitch($pos3,$ppos); - - $zom['yaw'] = $yaw; - $zom['pitch'] = $pitch; - if (!$zom['knockBack']) { - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - } - } - } - } - } - } - } - } - - public function SkeletonRandomWalk() { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Skeleton) { - if (isset($this->AIHolder->Skeleton[$zo->getId()])) { - $zom = &$this->AIHolder->Skeleton[$zo->getId()]; - if ($zom['canAttack'] != 0) { - $zom['canAttack'] -= 1; - } - $pos = $zo->getLocation(); - //echo ($zom['IsChasing']."\n"); - - //真正的自由落体 by boybook - if ($zom['drop'] !== false) { - $olddrop = $zom['drop']; - $zom['drop'] += 0.5; - $drop = $zom['drop']; - //echo $drop."\n"; - $dropy = $zo->getY() - ($olddrop * 0.05 + 0.0125); - $posd0 = new Vector3 (floor($zo->getX()), floor($dropy), floor($zo->getZ())); - $posd = new Vector3 ($zo->getX(), $dropy, $zo->getZ()); - if ($this->AIHolder->whatBlock($zo->getLevel(), $posd0) == "air") { - $zo->setPosition($posd->add(0,1,0)); //下降 - } else { - for ($i = 1; $i <= $drop; $i++) { - $posd0->y++; - if ($this->AIHolder->whatBlock($zo->getLevel(), $posd0) != "block") { - $posd->y = $posd0->y; - $zo->setPosition($posd->add(0,1,0)); //下降完成 - $h = $zom['drop'] * $zom['drop'] / 20; - $damage = $h - 3; - //echo($h . ": " . $damage . "\n"); - if ($damage > 0) { - //$zo->attack($damage, EntityDamageEvent::CAUSE_FALL); - $zo->setHealth($zo->getHealth() - $damage); - } - $zom['drop'] = false; - break; - } - } - } - } else { - $drop = 0; - } - - if ($zom['IsChasing'] !== false) { - if (!$zom['knockBack']) { - //echo $zy; - $zom['up'] = 0; - if ($this->AIHolder->whatBlock($level, $pos) == "water") { - $zom['swim'] += 1; - if ($zom['swim'] >= 20) $zom['swim'] = 0; - } else { - $zom['swim'] = 0; - } - //echo("目标:".$zo->getY()." "); - //echo("原先:".$zom['oldv3']->y."\n"); - - if(abs($zo->getY() - $zom['oldv3']->y) == 1 and $zom['canjump'] === true){ - //var_dump("跳"); - $zom['canjump'] = false; - $zom['jump'] = 0.5; - } - else { - if ($zom['jump'] > 0.01) { - $zom['jump'] -= 0.1; - } - else { - $zom['jump'] = 0.01; - } - } - - - - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['xxx'] / 10, -$zom['swim'] / 100 + $zom['jump'] - $drop, $zom['zzz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - - $p = $this->AIHolder->getServer()->getPlayer($zom['IsChasing']); - if ($p instanceof Player) { - $zom['shoot'] = $zom['shoot'] -1; - if ($zom['shoot'] <= 0) { - //boom - $zom['shoot'] = 20; - $v3 = new Vector3($zo->getX(),$zo->getY()+2,$zo->getZ()); - $chunk = $level->getChunk($v3->x >> 4, $v3->z >> 4, true); - $posnn = new Vector3($zo->getX(),$p->getY(),$zo->getZ()); - $my =$p->getY() - $zo->getY(); - $d = $p->distance($posnn); - $pitch = $this->getmypitch($my, $d); - - $nbt2 = new CompoundTag("", [ - "Pos" => new ListTag("Pos", [ - new DoubleTag("", $zo->getX()), - new DoubleTag("", $zo->getY()), - new DoubleTag("", $zo->getZ()) - ]), - "Motion" => new ListTag("Motion", [ - new DoubleTag("", -\sin($zom['yaw']) * \cos($pitch / 180 * M_PI)), - new DoubleTag("", -\sin($pitch / 180 * M_PI)), - new DoubleTag("", \cos($zom['yaw'] / 180 * M_PI) * \cos($pitch / 180 * M_PI)) - ]), - "Rotation" => new ListTag("Rotation", [ - new FloatTag("", $zom['yaw']), - new FloatTag("", $pitch) - ]), - ]); - $f = 1.5; - - - - - - //$ev = new EntityShootBowEvent($this, $bow, Entity::createEntity("Arrow", $this->chunk, $nbt, $this), $f); - //ToDo: Make Strays shoot arrows of slowness - $ev = new EntityShootBowEvent($zo, new ITEM(262,0), Entity::createEntity("Arrow", $chunk, $nbt2, $zo), $f); - - } - - } - } - - } else { - if ($zom['up'] == 1) { - if ($zom['yup'] <= 10) { - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10, $zom['motiony'] / 10, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - } else { - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10 - $zom['motiony'] / 10, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - } - } else { - - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx'] / 10, -$zom['motiony'] / 10, $zom['motionz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - - } - } - } - } - } - } - } - } - - public function getmypitch($my, $d) { //根据距离计算转向角度 - //转向计算 - if ($d == 0) { //斜率不存在 - if ($my < 0) { - $yaw = -90; - } - else { - $yaw = 90; - } - } - else { //存在斜率 - if ($my >= 0 and $d > 0) { //第一象限 - $atan = atan($my/$d); - $yaw = rad2deg($atan); - } - elseif ($my >= 0 and $d < 0) { //第二象限 - $atan = atan($my/abs($d)); - $yaw = 180 - rad2deg($atan); - } - elseif ($my < 0 and $d < 0) { //第三象限 - $atan = atan($my/$d); - $yaw = -(180 - rad2deg($atan)); - } - elseif ($my < 0 and $d > 0) { //第四象限 - $atan = atan(abs($my)/$d); - $yaw = -(rad2deg($atan)); - } - } - - $yaw = - $yaw; - return $yaw; - } - - public function SkeletonFire() { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo){ - if ($zo instanceof Skeleton) { - //var_dump($p->getLevel()->getTime()); - /* Don't use time directly - * Instead, get remainder of current time divided by 24,000 - * This tells us the time of day, which is what we really need - */ - $timeOfDay = abs($level->getTime() % 24000); - if(0 < $timeOfDay and $timeOfDay < 13000){ - $v3 = new Vector3($zo->getX(), $zo->getY(), $zo->getZ()); - $ok = true; - for ($y0 = $zo->getY() + 2; $y0 <= $zo->getY()+10; $y0++) { - $v3->y = $y0; - if ($level->getBlock($v3)->getID() != 0) { - $ok = false; - break; - } - } - if ($this->AIHolder->whatBlock($level,new Vector3($zo->getX(), floor($zo->getY() - 1), $zo->getZ())) == "water") $ok = false; - if ($ok) $zo->setOnFire(2); - } - } - } - } - } - -} diff --git a/src/devmine/creatures/entities/ai/ZombieAI.php b/src/devmine/creatures/entities/ai/ZombieAI.php deleted file mode 100644 index e50ed38..0000000 --- a/src/devmine/creatures/entities/ai/ZombieAI.php +++ /dev/null @@ -1,556 +0,0 @@ -AIHolder = $AIHolder; - if($this->AIHolder->getServer()->aiConfig["zombie"] == 1){ - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieRandomWalkCalc" - ] ), 10); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieRandomWalk" - ] ), 2); - - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieHateWalk" - ] ), 10); - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieHateFinder" - ] ), 10); - $this->AIHolder->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "ZombieFire" - ] ), 40); - /*$this->plugin->getServer()->getScheduler ()->scheduleRepeatingTask ( new CallbackTask ( [ - $this, - "array_clear" - ] ), 20 * 5);*/ - } - } - - public function array_clear() { - if (count($this->AIHolder->zombie) != 0) { - foreach ($this->AIHolder->zombie as $eid=> $info) { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - if (!($level->getEntity($eid) instanceof Entity)) { - unset($this->AIHolder->zombie[$eid]); - //echo "清除 $eid \n"; - } - } - } - } - } - - /** - * 僵尸初始化,常规化及自由行走模式循环计时器 - * 循环间隔:20 ticks - */ - public function ZombieRandomWalkCalc() { - $this->dif = $this->AIHolder->getServer()->getDifficulty(); - //$this->getLogger()->info("僵尸数量:".count($this->plugin->zombie)); - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo){ - if($zo instanceof Zombie){ - if ($this->AIHolder->willMove($zo)) { - if (!isset($this->AIHolder->zombie[$zo->getId()])){ - $this->AIHolder->zombie[$zo->getId()] = array( - 'ID' => $zo->getId(), - 'IsChasing' => false, - 'motionx' => 0, - 'motiony' => 0, - 'motionz' => 0, - 'hurt' => 10, - 'time'=>10, - 'x' => 0, - 'y' => 0, - 'z' => 0, - 'oldv3' => $zo->getLocation(), - 'yup' => 20, - 'up' => 0, - 'yaw' => $zo->yaw, - 'pitch' => 0, - 'level' => $zo->getLevel()->getName(), - 'xxx' => 0, - 'zzz' => 0, - 'gotimer' => 10, - 'swim' => 0, - 'jump' => 0.01, - 'canjump' => true, - 'drop' => false, - 'canAttack' => 0, - 'knockBack' => false, - ); - $zom = &$this->AIHolder->zombie[$zo->getId()]; - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - $zom = &$this->AIHolder->zombie[$zo->getId()]; - - if ($zom['IsChasing'] === false) { //自由行走模式 - if ($zom['gotimer'] == 0 or $zom['gotimer'] == 10) { - //限制转动幅度 - $newmx = mt_rand(-5,5)/10; - while (abs($newmx - $zom['motionx']) >= 0.7) { - $newmx = mt_rand(-5,5)/10; - } - $zom['motionx'] = $newmx; - - $newmz = mt_rand(-5,5)/10; - while (abs($newmz - $zom['motionz']) >= 0.7) { - $newmz = mt_rand(-5,5)/10; - } - $zom['motionz'] = $newmz; - } - elseif ($zom['gotimer'] >= 20 and $zom['gotimer'] <= 24) { - $zom['motionx'] = 0; - $zom['motionz'] = 0; - //僵尸停止 - } - - $zom['gotimer'] += 0.5; - if ($zom['gotimer'] >= 22) $zom['gotimer'] = 0; //重置走路计时器 - - //$zom['motionx'] = mt_rand(-10,10)/10; - //$zom['motionz'] = mt_rand(-10,10)/10; - $zom['yup'] = 0; - $zom['up'] = 0; - - //boybook的y轴判断法 - //$width = $this->width; - $pos = new Vector3 ($zom['x'] + $zom['motionx'], floor($zo->getY()) + 1,$zom['z'] + $zom['motionz']); //目标坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(),$pos); - $pos2 = new Vector3 ($zom['x'], $zom['y'] ,$zom['z']); //目标坐标 - - if ($this->AIHolder->ifjump($zo->getLevel(),$pos2) === false) { //原坐标依然是悬空 - - $pos2 = new Vector3 ($zom['x'], $zom['y']-1,$zom['z']); //下降 - $zom['up'] = 1; - $zom['yup'] = 0; - } - if ($zy === false) { //前方不可前进 - - // else { - $zom['motionx'] = - $zom['motionx']; - $zom['motionz'] = - $zom['motionz']; - //转向180度,向身后走 - $zom['up'] = 0; - //} - } - else { - $pos2 = new Vector3 ($zom['x'] + $zom['motionx'], $zy - 1 ,$zom['z'] + $zom['motionz']); //目标坐标 - if ($pos2->y - $zom['y'] < 0) { - $zom['up'] = 1; - } - else { - $zom['up'] = 0; - } - } - - if ($zom['motionx'] == 0 and $zom['motionz'] == 0) { //僵尸停止 - } - else { - //转向计算 - $yaw = $this->AIHolder->getyaw($zom['motionx'], $zom['motionz']); - //$zo->setRotation($yaw,0); - $zom['yaw'] = $yaw; - $zom['pitch'] = 0; - } - - //更新僵尸坐标 - if (!$zom['knockBack']) { - $zom['x'] = $pos2->getX(); - $zom['z'] = $pos2->getZ(); - $zom['y'] = $pos2->getY(); - } - $zom['motiony'] = $pos2->getY() - $zo->getY(); - //echo($zo->getY()."\n"); - //var_dump($pos2); - //var_dump($zom['motiony']); - $zo->setPosition($pos2); - //echo "SetPosition \n"; - } - } - } - } - } - } - - /** - * 僵尸仇恨刷新计时器 - * 循环间隔:10 ticks - */ - public function ZombieHateFinder() { - foreach ($this->AIHolder->getServer()->getLevels () as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Zombie) { - if (isset($this->AIHolder->zombie[$zo->getId()])) { - $zom = &$this->AIHolder->zombie[$zo->getId()]; - $h_r = $this->hatred_r; //仇恨半径 - $pos = new Vector3($zo->getX(), $zo->getY(), $zo->getZ()); - $hatred = false; - foreach ($zo->getViewers() as $p) { //获取附近玩家 - if ($p->distance($pos) <= $h_r) { //玩家在仇恨半径内 - if ($hatred === false) { - $hatred = $p; - } elseif ($hatred instanceof Player) { - if ($p->distance($pos) <= $hatred->distance($pos)) { //比上一个更近 - $hatred = $p; - } - } - } - } - //echo ($zom['IsChasing']."\n"); - if ($hatred == false or $this->dif == 0) { - $zom['IsChasing'] = false; - } else { - $zom['IsChasing'] = $hatred->getName(); - } - } - } - } - } - } - - /** - * 僵尸仇恨模式坐标更新计时器 - * 循环间隔:10 ticks - */ - public function ZombieHateWalk() { - foreach ($this->AIHolder->getServer()->getLevels () as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Zombie) { - if (isset($this->AIHolder->zombie[$zo->getId()])) { - $zom = &$this->AIHolder->zombie[$zo->getId()]; - //$zom['yup'] = $zom['yup'] - 1; - if (!$zom['knockBack']) { - $zom['oldv3'] = $zo->getLocation(); - $zom['canjump'] = true; - - //僵尸碰撞检测 by boybook - /* - foreach ($level->getEntities() as $zo0) { - if ($zo0 instanceof Zombie and !($zo0 == $zo)) { - if ($zo->distance($zo0) <= $this->width * 2) { - $dx = $zo->x - $zo0->x; - $dz = $zo->z - $zo0->z; - if ($dx == 0) { - $dx = mt_rand(-5,5) / 5; - if ($dx == 0) $dx = 1; - } - if ($dz == 0) { - $dz = mt_rand(-5,5) / 5; - if ($dz == 0) $dz = 1; - } - $zo->knockBack($zo0,0,$dx/5,$dz/5,0); - $newpos = new Vector3($zo->x + $dx * 5, $zo->y, $zo->z + $dz * 5); - $zom['x'] = $newpos->x; - $zom['y'] = $newpos->y; - $zom['z'] = $newpos->z; - $this->plugin->getServer()->getScheduler()->scheduleDelayedTask(new CallbackTask([$this->plugin,"knockBackover"],[$zo,$newpos]),5); - } - } - - }*/ - - if ($zom['IsChasing'] !== false) { - //echo ("是属于仇恨模式\n"); - $p = $this->AIHolder->getServer()->getPlayer($zom['IsChasing']); - if (($p instanceof Player) === false) { - $zom['IsChasing'] = false; //取消仇恨模式 - } else { - //真正的行走方向计算 - $xx = $p->getX() - $zo->getX(); - $zz = $p->getZ() - $zo->getZ(); - $yaw = $this->AIHolder->getyaw($xx,$zz); - /* - * x = $xxx, z = $zzz - * x0 = $xx, z0 = $zz - * x^2 + z^2 = 0.7 - * x/z = x0/z0 => x = bi * z - * => - * bi^2 * z^2 + z^2 = 0.7 - * z^2 * (bi^2 + 1) = 0.7 - * */ - if ($zz != 0) { - $bi = $xx/$zz; - }else{ - $bi = 0; - } -$xxx =0;$zzz=0; - //根据wiki:僵尸掉血后走路更快 - - $zzz = sqrt(($this->zo_hate_v / 2.5) / ($bi * $bi + 1)); - - - if ($zz < 0) $zzz = -$zzz; - $xxx = $zzz * $bi; - - $zo_v2 = new Vector2($zo->getX(),$zo->getZ()); - $p_v2 = new Vector2($p->getX(),$p->getZ()); - if ($zo_v2->distance($p_v2) <= $this->zo_hate_v/2) { - $xxx = $xx; - $zzz = $zz; - } - //严重加速bug - $zom['xxx'] = $xxx; - $zom['zzz'] = $zzz; - - //计算y轴 - //$width = $this->width; - $pos0 = new Vector3 ($zo->getX(), $zo->getY() + 1, $zo->getZ()); //原坐标 - $pos = new Vector3 ($zo->getX() + $xxx, $zo->getY() + 1, $zo->getZ()+ $zzz); //目标坐标 - - //用来写僵尸宽度的 - //$v = $this->zo_hate_v/2; - //$pos_front = new Vector3 ($zo->getX() + ($xxx/$v*($v+$this->width)), $zo->getY() + 1, $zo->getZ() + ($zzz/$v*($v+$this->width))); //前方坐标 - //$pos_back = new Vector3 ($zo->getX() + (-$xxx/$v*(-$v-$this->width)), $zo->getY() + 1, $zo->getZ() + (-$zzz/$v*(-$v-$this->width))); //后方坐标 - $zy = $this->AIHolder->ifjump($zo->getLevel(), $pos, true); - - if ($zy === false or ($zy !== false and $this->AIHolder->ifjump($zo->getLevel(), $pos0, true, true) == 'fall')) { //前方不可前进 - //真正的自由落体 by boybook - if ($this->AIHolder->ifjump($zo->getLevel(), $pos0, false) === false) { //原坐标依然是悬空 - if ($zom['drop'] === false) { - $zom['drop'] = 0; //僵尸下落的速度 - } - $pos2 = new Vector3 ($zo->getX(), $zo->getY() - ($zom['drop'] / 2 + 1.25), $zo->getZ()); //下降 - - } else { - $zom['drop'] = false; - if ($this->AIHolder->whatBlock($level, $pos0) == "climb") { //梯子 - $zy = $pos0->y + 0.7; - $pos2 = new Vector3 ($zo->getX(), $zy - 1, $zo->getZ()); //目标坐标 - } - elseif ($xxx != 0 and $zzz != 0) { //走向最近距离 - if ($this->AIHolder->ifjump($zo->getLevel(), new Vector3($zo->getX() + $xxx, $zo->getY() + 1, $zo->getZ()), true) !== false) { - $pos2 = new Vector3($zo->getX() + $xxx, floor($zo->getY()), $zo->getZ()); //目标坐标 - } elseif ($this->AIHolder->ifjump($zo->getLevel(), new Vector3($zo->getX(), $zo->getY() + 1, $zo->getZ() + $zzz), true) !== false) { - $pos2 = new Vector3($zo->getX(), floor($zo->getY()), $zo->getZ() + $zzz); //目标坐标 - } else { - $pos2 = new Vector3 ($zo->getX() - $xxx / 5, floor($zo->getY()), $zo->getZ() - $zzz / 5); //目标坐标 - //转向180度,向身后走 - } - } else { - $pos2 = new Vector3 ($zo->getX() - $xxx / 5, floor($zo->getY()), $zo->getZ() - $zzz / 5); //目标坐标 - } - } - } else { - $pos2 = new Vector3 ($zo->getX() + $xxx, $zy - 1, $zo->getZ() + $zzz); //目标坐标 - } - $zo->setPosition($pos2); - - $pos3 = $pos2; - $pos3->y = $pos3->y + 2.62; - - $ppos = $p->getLocation(); - $ppos->y = $ppos->y + $p->getEyeHeight(); - $pitch = $this->AIHolder->getpitch($pos3,$ppos); - - $zom['yaw'] = $yaw; - $zom['pitch'] = $pitch; - if (!$zom['knockBack']) { - $zom['x'] = $zo->getX(); - $zom['y'] = $zo->getY(); - $zom['z'] = $zo->getZ(); - } - } - } - } - } - } - } - } - } - - /** - * 高密集型发包计时器 - * - 发送数据包 - * - 计算自由落体相关数据 - * 循环间隔:1 tick - */ - public function ZombieRandomWalk() { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo) { - if ($zo instanceof Zombie) { - if (isset($this->AIHolder->zombie[$zo->getId()])) { - $zom = &$this->AIHolder->zombie[$zo->getId()]; - if ($zom['canAttack'] != 0) { - $zom['canAttack'] -= 1; - } - $pos = $zo->getLocation(); - //echo ($zom['IsChasing']."\n"); - - //真正的自由落体 by boybook - $drop = $zom['drop']; - - if ($zom['drop'] !== false) { - - - //$zo->motionY= $zom['drop'] = $zo->onGround?-0.04,-(abs(1+$zo->motionY)*1.5-1); - $zom['drop']+=0.01; - // print($zom['drop']); - } else { - $drop = 0; - - } - - if ($zom['IsChasing'] !== false) { - if (!$zom['knockBack']) { - //echo $zy; - $zom['up'] = 0; - if ($this->AIHolder->whatBlock($level, $pos) == "water") { - $zom['swim'] += 1; - if ($zom['swim'] >= 20) $zom['swim'] = 0; - } else { - $zom['swim'] = 0; - } - //echo("目标:".$zo->getY()." "); - //echo("原先:".$zom['oldv3']->y."\n"); - - if(abs($zo->getY() - $zom['oldv3']->y) == 1 and $zom['canjump'] === true){ - //var_dump("跳"); - $zom['canjump'] = false; - $zom['jump'] = 0.3; - } - else { - if ($zom['jump'] > 0.01) { - $zom['jump'] -= 0.1; - } - else { - $zom['jump'] = 0; - } - } - - - - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['xxx'] / 10, $zom['jump'] - $zo->onGround?0.04:0, $zom['zzz'] / 10] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - - $p = $this->AIHolder->getServer()->getPlayer($zom['IsChasing']); - if ($p instanceof Player) { - if ($p->distance($pos) <= 1.3) { - //僵尸的火焰点燃人类 - if ($zo->fireTicks > 0) { - $p->setOnFire(1); - } - } - if ($p->distance($pos) <= 1.5) { - - if ($zom['canAttack'] == 0) { - $zom['canAttack'] = 20; - //@$p->knockBack($zo, 0, $zom['xxx'] / 10, $zom['zzz'] / 10); - if ($p->isSurvival()) { - $zoDamage = $this->AIHolder->getZombieDamage($zo->getHealth()); - $damage = $this->AIHolder->getPlayerDamage($p, $zoDamage); - //echo $zoDamage."-".$damage."\n"; - $p->attack($damage, new EntityDamageByEntityEvent($zo,$p,EntityDamageEvent::CAUSE_ENTITY_ATTACK,$damage)); - } - } - } - } - } - - } else { - if ($zom['up'] == 1) { - if ($zom['yup'] <= 10) { - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx']/10 , $zom['motiony'] , $zom['motionz']/10 ] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - } else { - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx']/10 , $zom['motiony'] , $zom['motionz']/10 ] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - } - } - } else { - - $pk3 = new SetEntityMotionPacket; - $pk3->entities = [ - [$zo->getID(), $zom['motionx']/10, $zom['motiony'] , $zom['motionz']/10 ] - ]; - foreach ($zo->getViewers() as $pl) { - $pl->dataPacket($pk3); - - } - } - } - } - } - } - } - } - - /** - * 僵尸着火计时器 - * PM时间修复 - */ - public function ZombieFire() { - foreach ($this->AIHolder->getServer()->getLevels() as $level) { - foreach ($level->getEntities() as $zo){ - if ($zo instanceof Zombie and !($zo instanceof Husk)) { - //var_dump($p->getLevel()->getTime()); - /* Don't use time directly - * Instead, get remainder of current time divided by 24,000 - * This tells us the time of day, which is what we really need - */ - $timeOfDay = abs($level->getTime() % 24000); - if(0 < $timeOfDay and $timeOfDay < 13000){ - $v3 = new Vector3($zo->getX(), $zo->getY(), $zo->getZ()); - $ok = true; - for ($y0 = $zo->getY() + 2; $y0 <= $zo->getY()+10; $y0++) { - $v3->y = $y0; - if ($level->getBlock($v3)->getID() != 0) { - $ok = false; - break; - } - } - if ($this->AIHolder->whatBlock($level,new Vector3($zo->getX(), floor($zo->getY() - 1), $zo->getZ())) == "water") $ok = false; - if ($ok) $zo->setOnFire(2); - } - } - } - } - } - -} diff --git a/src/devmine/creatures/player/IPlayer.php b/src/devmine/creatures/player/IPlayer.php index 193dcdf..80802f4 100644 --- a/src/devmine/creatures/player/IPlayer.php +++ b/src/devmine/creatures/player/IPlayer.php @@ -4,7 +4,7 @@ namespace devmine\creatures\player; -use devmine\server\permissions\ServerOperator; +use devmine\server\perms\ServerOperator; interface IPlayer extends ServerOperator{ diff --git a/src/devmine/creatures/player/NBT.php b/src/devmine/creatures/player/NBT.php index cf5e027..b17060f 100644 --- a/src/devmine/creatures/player/NBT.php +++ b/src/devmine/creatures/player/NBT.php @@ -57,49 +57,6 @@ class NBT{ public $endianness; private $data; - - /** - * @param Item $item - * @param int $slot - * @return CompoundTag - */ - public static function putItemHelper(Item $item, $slot = null){ - $tag = new CompoundTag(null, [ - "id" => new ShortTag("id", $item->getId()), - "Count" => new ByteTag("Count", $item->getCount()), - "Damage" => new ShortTag("Damage", $item->getDamage()) - ]); - - if($slot !== null){ - $tag->Slot = new ByteTag("Slot", (int) $slot); - } - - if($item->hasCompoundTag()){ - $tag->tag = clone $item->getNamedTag(); - $tag->tag->setName("tag"); - } - - return $tag; - } - - /** - * @param CompoundTag $tag - * @return Item - */ - public static function getItemHelper(CompoundTag $tag){ - if(!isset($tag->id) or !isset($tag->Count)){ - return Item::get(0); - } - - $item = Item::get($tag->id->getValue(), !isset($tag->Damage) ? 0 : $tag->Damage->getValue(), $tag->Count->getValue()); - - if(isset($tag->tag) and $tag->tag instanceof CompoundTag){ - $item->setNamedTag($tag->tag); - } - - return $item; - } - public static function matchList(ListTag $tag1, ListTag $tag2){ if($tag1->getName() !== $tag2->getName() or $tag1->getCount() !== $tag2->getCount()){ return false; @@ -416,7 +373,7 @@ private static function readKey($data, &$offset){ if($c === ":"){ ++$offset; break; - }elseif($c !== " " and $c !== "\r" and $c !== "\n" and $c !== "\t"){ + }elseif($c !== " " and $c !== "\r" and $c !== "\n" and $c !== "\t" and $c !== "\""){ $key .= $c; } } @@ -452,14 +409,14 @@ public function __construct($endianness = self::LITTLE_ENDIAN){ $this->endianness = $endianness & 0x01; } - public function read($buffer, $doMultiple = false){ + public function read($buffer, $doMultiple = false, bool $network = false){ $this->offset = 0; $this->buffer = $buffer; - $this->data = $this->readTag(); + $this->data = $this->readTag($network); if($doMultiple and $this->offset < strlen($this->buffer)){ $this->data = [$this->data]; do{ - $this->data[] = $this->readTag(); + $this->data[] = $this->readTag($network); }while($this->offset < strlen($this->buffer)); } $this->buffer = ""; @@ -469,20 +426,25 @@ public function readCompressed($buffer, $compression = ZLIB_ENCODING_GZIP){ $this->read(zlib_decode($buffer)); } + public function readNetworkCompressed($buffer, $compression = ZLIB_ENCODING_GZIP){ + $this->read(zlib_decode($buffer), false, true); + } + + /** * @return string|bool */ - public function write(){ + public function write(bool $network = false){ $this->offset = 0; $this->buffer = ""; if($this->data instanceof CompoundTag){ - $this->writeTag($this->data); + $this->writeTag($this->data, $network); return $this->buffer; }elseif(is_array($this->data)){ foreach($this->data as $tag){ - $this->writeTag($tag); + $this->writeTag($tag, $network); } return $this->buffer; } @@ -498,51 +460,64 @@ public function writeCompressed($compression = ZLIB_ENCODING_GZIP, $level = 7){ return false; } - public function readTag(){ - switch($this->getByte()){ + public function writeNetworkCompressed($compression = ZLIB_ENCODING_GZIP, $level = 7){ + if(($write = $this->write(true)) !== false){ + return zlib_encode($write, $compression, $level); + } + + return false; + } + + public function readTag(bool $network = false){ + if($this->feof()){ + $tagType = -1; //prevent crashes for empty tags + }else{ + $tagType = $this->getByte(); + } + switch($tagType){ case NBT::TAG_Byte: - $tag = new ByteTag($this->getString()); - $tag->read($this); + $tag = new ByteTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_Short: - $tag = new ShortTag($this->getString()); - $tag->read($this); + $tag = new ShortTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_Int: - $tag = new IntTag($this->getString()); - $tag->read($this); + $tag = new IntTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_Long: - $tag = new LongTag($this->getString()); - $tag->read($this); + $tag = new LongTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_Float: - $tag = new FloatTag($this->getString()); - $tag->read($this); + $tag = new FloatTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_Double: - $tag = new DoubleTag($this->getString()); - $tag->read($this); + $tag = new DoubleTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_ByteArray: - $tag = new ByteArrayTag($this->getString()); - $tag->read($this); + $tag = new ByteArrayTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_String: - $tag = new StringTag($this->getString()); - $tag->read($this); + $tag = new StringTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_List: - $tag = new ListTag($this->getString()); - $tag->read($this); + $tag = new ListTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_Compound: - $tag = new CompoundTag($this->getString()); - $tag->read($this); + $tag = new CompoundTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_IntArray: - $tag = new IntArrayTag($this->getString()); - $tag->read($this); + $tag = new IntArrayTag($this->getString($network)); + $tag->read($this, $network); break; case NBT::TAG_End: //No named tag @@ -553,12 +528,12 @@ public function readTag(){ return $tag; } - public function writeTag(Tag $tag){ + public function writeTag(Tag $tag, bool $network = false){ $this->putByte($tag->getType()); if($tag instanceof NamedTAG){ - $this->putString($tag->getName()); + $this->putString($tag->getName(), $network); } - $tag->write($this); + $tag->write($this, $network); } public function getByte(){ @@ -577,12 +552,19 @@ public function putShort($v){ $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeShort($v) : Binary::writeLShort($v); } - public function getInt(){ + public function getInt(bool $network = false){ + if($network === true){ + return Binary::readVarInt($this); + } return $this->endianness === self::BIG_ENDIAN ? Binary::readInt($this->get(4)) : Binary::readLInt($this->get(4)); } - public function putInt($v){ - $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeInt($v) : Binary::writeLInt($v); + public function putInt($v, bool $network = false){ + if($network === true){ + $this->buffer .= Binary::writeVarInt($v); + }else{ + $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeInt($v) : Binary::writeLInt($v); + } } public function getLong(){ @@ -609,18 +591,24 @@ public function putDouble($v){ $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeDouble($v) : Binary::writeLDouble($v); } - public function getString(){ - return $this->get($this->getShort()); + public function getString(bool $network = false){ + $len = $network ? $this->getByte() : $this->getShort(); + return $this->get($len); } - public function putString($v){ - $this->putShort(strlen($v)); + public function putString($v, bool $network = false){ + if($network === true){ + $this->putByte(strlen($v)); + }else{ + $this->putShort(strlen($v)); + } $this->buffer .= $v; } public function getArray(){ $data = []; self::toArray($data, $this->data); + return $data; } private static function toArray(array &$data, Tag $tag){ diff --git a/src/devmine/creatures/player/OfflinePlayer.php b/src/devmine/creatures/player/OfflinePlayer.php index fc3f9ca..ddc33db 100644 --- a/src/devmine/creatures/player/OfflinePlayer.php +++ b/src/devmine/creatures/player/OfflinePlayer.php @@ -5,11 +5,12 @@ namespace devmine\creatures\player; -use devmine\server\epilogos\epilogosValue; +use devmine\server\meta\MetadataValue; +use devmine\server\meta\Metadatable; use devmine\creatures\player\tag\CompoundTag; -use devmine\pluginfeatures\Plugin; +use devmine\consumer\plugin\Plugin; -class OfflinePlayer implements IPlayer{ +class OfflinePlayer implements IPlayer, Metadatable{ private $name; private $server; @@ -97,20 +98,20 @@ public function hasPlayedBefore(){ return $this->namedtag instanceof CompoundTag; } - public function setepilogos($epilogosKey, epilogosValue $epilogosValue){ - $this->server->getPlayerepilogos()->setepilogos($this, $epilogosKey, $epilogosValue); + public function setMetadata($metadataKey, MetadataValue $metadataValue){ + $this->server->getPlayerMetadata()->setMetadata($this, $metadataKey, $metadataValue); } - public function getepilogos($epilogosKey){ - return $this->server->getPlayerepilogos()->getepilogos($this, $epilogosKey); + public function getMetadata($metadataKey){ + return $this->server->getPlayerMetadata()->getMetadata($this, $metadataKey); } - public function hasepilogos($epilogosKey){ - return $this->server->getPlayerepilogos()->hasepilogos($this, $epilogosKey); + public function hasMetadata($metadataKey){ + return $this->server->getPlayerMetadata()->hasMetadata($this, $metadataKey); } - public function removeepilogos($epilogosKey, Plugin $plugin){ - $this->server->getPlayerepilogos()->removeepilogos($this, $epilogosKey, $plugin); + public function removeMetadata($metadataKey, Plugin $plugin){ + $this->server->getPlayerMetadata()->removeMetadata($this, $metadataKey, $plugin); } diff --git a/src/devmine/creatures/player/Player.php b/src/devmine/creatures/player/Player.php index 4b039f5..6313619 100644 --- a/src/devmine/creatures/player/Player.php +++ b/src/devmine/creatures/player/Player.php @@ -4,10 +4,11 @@ namespace devmine\creatures\player; -use devmine\inventory\blocks\Block; use devmine\inventory\blocks\Air; +use devmine\inventory\blocks\Block; use devmine\inventory\blocks\Fire; use devmine\inventory\blocks\PressurePlate; +use devmine\server\commands\Command; use devmine\server\commands\CommandSender; use devmine\creatures\entities\Animal; use devmine\creatures\entities\Arrow; @@ -21,56 +22,58 @@ use devmine\creatures\entities\Item as DroppedItem; use devmine\creatures\entities\Living; use devmine\creatures\entities\Minecart; -use devmine\creatures\entities\Projecsolidentity; +use devmine\creatures\entities\Projectile; use devmine\creatures\entities\ThrownExpBottle; use devmine\creatures\entities\ThrownPotion; -use devmine\server\events\block\BlockBreakEvent; -use devmine\server\events\block\ItemFrameDropItemEvent; -use devmine\server\events\block\SignChangeEvent; -use devmine\server\events\entity\EntityCombustByEntityEvent; -use devmine\server\events\entity\EntityDamageByBlockEvent; -use devmine\server\events\entity\EntityDamageByEntityEvent; -use devmine\server\events\entity\EntityDamageEvent; -use devmine\server\events\entity\EntityRegainHealthEvent; -use devmine\server\events\entity\EntityShootBowEvent; -use devmine\server\events\entity\ProjecsolidentityLaunchEvent; -use devmine\server\events\inventory\CraftItemEvent; -use devmine\server\events\inventory\InventoryCloseEvent; -use devmine\server\events\inventory\InventoryPickupArrowEvent; -use devmine\server\events\inventory\InventoryPickupItemEvent; -use devmine\server\events\player\PlayerTextPreSendEvent; -use devmine\server\events\player\PlayerAchievementAwardedEvent; -use devmine\server\events\player\PlayerAnimationEvent; -use devmine\server\events\player\PlayerBedEnterEvent; -use devmine\server\events\player\PlayerBedLeaveEvent; -use devmine\server\events\player\PlayerChatEvent; -use devmine\server\events\player\PlayerCommandPreprocessEvent; -use devmine\server\events\player\PlayerDeathEvent; -use devmine\server\events\player\PlayerDropItemEvent; -use devmine\server\events\player\PlayerExperienceChangeEvent; -use devmine\server\events\player\PlayerGameModeChangeEvent; -use devmine\server\events\player\PlayerHungerChangeEvent; -use devmine\server\events\player\PlayerInteractEvent; -use devmine\server\events\player\PlayerItemConsumeEvent; -use devmine\server\events\player\PlayerJoinEvent; -use devmine\server\events\player\PlayerKickEvent; -use devmine\server\events\player\PlayerLoginEvent; -use devmine\server\events\player\PlayerMoveEvent; -use devmine\server\events\player\PlayerPreLoginEvent; -use devmine\server\events\player\PlayerQuitEvent; -use devmine\server\events\player\PlayerRespawnEvent; -use devmine\server\events\player\PlayerToggleSneakEvent; -use devmine\server\events\player\PlayerToggleSprintEvent; -use devmine\server\events\player\PlayerUseFishingRodEvent; -use devmine\server\events\server\DataPacketReceiveEvent; -use devmine\server\events\server\DataPacketSendEvent; -use devmine\server\events\TextContainer; -use devmine\server\events\Timings; -use devmine\server\events\TranslationContainer; +use devmine\events\block\BlockBreakEvent; +use devmine\events\block\ItemFrameDropItemEvent; +use devmine\events\entity\EntityCombustByEntityEvent; +use devmine\events\entity\EntityDamageByBlockEvent; +use devmine\events\entity\EntityDamageByEntityEvent; +use devmine\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityRegainHealthEvent; +use devmine\events\entity\EntityShootBowEvent; +use devmine\events\entity\ProjectileLaunchEvent; +use devmine\events\inventory\CraftItemEvent; +use devmine\events\inventory\InventoryCloseEvent; +use devmine\events\inventory\InventoryPickupArrowEvent; +use devmine\events\inventory\InventoryPickupItemEvent; +use devmine\events\player\PlayerExhaustEvent; +use devmine\events\player\PlayerTextPreSendEvent; +use devmine\events\player\PlayerAchievementAwardedEvent; +use devmine\events\player\PlayerAnimationEvent; +use devmine\events\player\PlayerBedEnterEvent; +use devmine\events\player\PlayerBedLeaveEvent; +use devmine\events\player\PlayerChatEvent; +use devmine\events\player\PlayerCommandPreprocessEvent; +use devmine\events\player\PlayerDeathEvent; +use devmine\events\player\PlayerDropItemEvent; +use devmine\events\player\PlayerGameModeChangeEvent; +use devmine\events\player\PlayerHungerChangeEvent; +use devmine\events\player\PlayerInteractEvent; +use devmine\events\player\PlayerItemConsumeEvent; +use devmine\events\player\PlayerJoinEvent; +use devmine\events\player\PlayerKickEvent; +use devmine\events\player\PlayerLoginEvent; +use devmine\events\player\PlayerMoveEvent; +use devmine\events\player\PlayerPreLoginEvent; +use devmine\events\player\PlayerQuitEvent; +use devmine\events\player\PlayerRespawnEvent; +use devmine\events\player\PlayerToggleFlightEvent; +use devmine\events\player\PlayerToggleSneakEvent; +use devmine\events\player\PlayerToggleSprintEvent; +use devmine\events\player\PlayerToggleGlideEvent; +use devmine\events\player\PlayerUseFishingRodEvent; +use devmine\events\server\DataPacketReceiveEvent; +use devmine\events\server\DataPacketSendEvent; +use devmine\events\TextContainer; +use devmine\events\Timings; +use devmine\events\TranslationContainer; use devmine\inventory\layout\AnvilInventory; use devmine\inventory\layout\BaseTransaction; use devmine\inventory\layout\BigShapedRecipe; use devmine\inventory\layout\BigShapelessRecipe; +use devmine\inventory\layout\DropItemTransaction; use devmine\inventory\layout\EnchantInventory; use devmine\inventory\layout\FurnaceInventory; use devmine\inventory\layout\Inventory; @@ -78,21 +81,21 @@ use devmine\inventory\layout\PlayerInventory; use devmine\inventory\layout\ShapedRecipe; use devmine\inventory\layout\ShapelessRecipe; -use devmine\inventory\layout\SimpleTransactionGroup; use devmine\inventory\items\enchantment\Enchantment; use devmine\inventory\items\FoodSource; use devmine\inventory\items\Item; use devmine\inventory\items\Potion; -use devmine\levels\ChunkLoader; -use devmine\levels\format\FullChunk; -use devmine\levels\Level; -use devmine\levels\Location; -use devmine\levels\Position; -use devmine\levels\sound\LaunchSound; +use devmine\worlds\ChunkLoader; +use devmine\worlds\format\Chunk; +use devmine\worlds\Level; +use devmine\worlds\Location; +use devmine\worlds\Position; +use devmine\worlds\sound\LaunchSound; +use devmine\worlds\WeakPosition; use devmine\server\calculations\AxisAlignedBB; use devmine\server\calculations\Vector2; use devmine\server\calculations\Vector3; -use devmine\server\epilogos\epilogosValue; +use devmine\server\meta\MetadataValue; use devmine\creatures\player\NBT; use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\CompoundTag; @@ -106,6 +109,7 @@ use devmine\server\network\Network; use devmine\server\network\protocol\AdventureSettingsPacket; use devmine\server\network\protocol\AnimatePacket; +use devmine\server\network\protocol\AvailableCommandsPacket; use devmine\server\network\protocol\BatchPacket; use devmine\server\network\protocol\ChunkRadiusUpdatedPacket; use devmine\server\network\protocol\ContainerClosePacket; @@ -120,6 +124,7 @@ use devmine\server\network\protocol\MovePlayerPacket; use devmine\server\network\protocol\PlayerActionPacket; use devmine\server\network\protocol\PlayStatusPacket; +use devmine\server\network\protocol\ResourcePacksInfoPacket; use devmine\server\network\protocol\RespawnPacket; use devmine\server\network\protocol\SetDifficultyPacket; use devmine\server\network\protocol\SetEntityMotionPacket; @@ -134,16 +139,16 @@ use devmine\server\network\protocol\UpdateAttributesPacket; use devmine\server\network\protocol\UpdateBlockPacket; use devmine\server\network\SourceInterface; -use devmine\server\permissions\PermissibleBase; -use devmine\server\permissions\PermissionAttachment; -use devmine\pluginfeatures\Plugin; +use devmine\server\perms\PermissibleBase; +use devmine\server\perms\PermissionAttachment; +use devmine\consumer\plugin\Plugin; use devmine\inventory\solidentity\ItemFrame; use devmine\inventory\solidentity\Sign; use devmine\inventory\solidentity\Spawnable; -use devmine\inventory\solidentity\solidentity; +use devmine\inventory\solidentity\Tile; +use devmine\utilities\main\Binary; use devmine\utilities\main\TextFormat; use devmine\utilities\main\UUID; -use raklib\Binary; /** * Main class that handles networking, recovery, and packet sending to the server part @@ -156,8 +161,10 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade const SPECTATOR = 3; const VIEW = Player::SPECTATOR; - const SURVIVAL_SLOTS = 36; - const CREATIVE_SLOTS = 112; + const CRAFTING_SMALL = 0; + const CRAFTING_BIG = 1; + const CRAFTING_ANVIL = 2; + const CRAFTING_ENCHANT = 3; /** @var SourceInterface */ protected $interface; @@ -187,17 +194,10 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade public $blocked = false; public $achievements = []; public $lastCorrect; - /** @var SimpleTransactionGroup */ - protected $currentTransaction = null; - public $craftingType = 0; //0 = 2x2 crafting, 1 = 3x3 crafting, 2 = stonecutter - protected $isCrafting = false; + public $craftingType = self::CRAFTING_SMALL; //0 = 2x2 crafting, 1 = 3x3 crafting, 2 = anvil, 3 = enchanting - /** - * @deprecated - * @var array - */ - public $loginData = []; + protected $isCrafting = false; public $creationTime = 0; @@ -240,15 +240,16 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade protected $viewDistance; protected $chunksPerTick; protected $spawnThreshold; - /** @var null|Position */ - protected $spawnPosition = null; + /** @var null|WeakPosition */ + private $spawnPosition = null; protected $inAirTicks = 0; protected $startAirTicks = 5; + //TODO: Abilities protected $autoJump = true; - protected $allowFlight = false; + protected $flying = false; private $needACK = []; @@ -276,9 +277,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade /** @var Item[] */ protected $personalCreativeItems = []; - - /** @var Item */ - private $anvilItem; public function linkHookToPlayer(FishingHook $entity){ if($entity->isAlive()){ @@ -322,106 +320,113 @@ public function setFishingHook(FishingHook $entity = null){ public function getItemInHand(){ return $this->inventory->getItemInHand(); } - + public function getLeaveMessage(){ return new TranslationContainer(TextFormat::YELLOW . "%multiplayer.player.left", [ $this->getDisplayName() ]); } - protected $expLevel = 0; - protected $exp = 0; - + /** + * @deprecated Use Human::setTotalXp($xp), this method will be removed in the future. + */ public function setExperienceAndLevel(int $exp, int $level){ - $this->server->getPluginManager()->callEvent($ev = new PlayerExperienceChangeEvent($this, $exp, $level)); - if(!$ev->isCancelled()){ - $this->expLevel = $level; - $this->exp = $exp; - $this->calcExpLevel(); - $this->updateExperience(); - return true; - } - return false; + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + return $this->setTotalXp(self::getTotalXpRequirement($level) + $exp); } + /** + * @deprecated Use Human::setTotalXp($xp), this method will be removed in the future. + */ public function setExp(int $exp){ - $this->server->getPluginManager()->callEvent($ev = new PlayerExperienceChangeEvent($this, $exp, 0)); - if($ev->isCancelled()){ - $this->exp = $ev->getExp(); - $this->calcExpLevel(); - $this->updateExperience(); - return true; - } - return false; + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + return $this->setTotalXp($exp); } + /** + * @deprecated Use Human::setXpLevel($level), this method will be removed in the future. + */ public function setExpLevel(int $level){ - $this->server->getPluginManager()->callEvent($ev = new PlayerExperienceChangeEvent($this, 0, $level)); - if(!$ev->isCancelled()){ - $this->expLevel = $level; - $this->exp = $this->server->getExpectedExperience($level); - $this->updateExperience(); - return true; - } - return false; + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + return $this->setXpLevel($level); } + /** + * @deprecated Use Human::getTotalXpRequirement($level), this method will be removed in the future. + */ public function getExpectedExperience(){ - return $this->server->getExpectedExperience($this->expLevel + 1); + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + return self::getTotalXpRequirement($this->getXpLevel() + 1); } + /** + * @deprecated Use Human::getLevelXpRequirement($level), this method will be removed in the future. + */ public function getLevelUpExpectedExperience(){ - /*if($this->explevel < 16) return 2 * $this->explevel + 7; - elseif($this->explevel < 31) return 5 * $this->explevel - 38; - else return 9 * $this->explevel - 158;*/ - return $this->getExpectedExperience() - $this->server->getExpectedExperience($this->expLevel); + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + return self::getLevelXpRequirement($this->getXpLevel() + 1); } + /** + * @deprecated + */ public function calcExpLevel(){ - while($this->exp >= $this->getExpectedExperience()){ - $this->expLevel++; - } - while($this->exp < $this->server->getExpectedExperience($this->expLevel - 1)){ - $this->expLevel--; - } + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); } + /** + * @deprecated Use Human::addXp($xp), this method will be removed in the future. + */ public function addExperience(int $exp){ - $this->server->getPluginManager()->callEvent($ev = new PlayerExperienceChangeEvent($this, $exp, 0, PlayerExperienceChangeEvent::ADD_EXPERIENCE)); - if(!$ev->isCancelled()){ - $this->exp = $this->exp + $ev->getExp(); - $this->calcExpLevel(); - $this->updateExperience(); - return true; - } - return false; + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + return $this->addXp($exp); } + /** + * @deprecated Use Human::addXpLevel(), this method will be removed in the future. + */ public function addExpLevel(int $level){ - $this->server->getPluginManager()->callEvent($ev = new PlayerExperienceChangeEvent($this, 0, $level, PlayerExperienceChangeEvent::ADD_EXPERIENCE)); - if(!$ev->isCancelled()){ - $this->expLevel = $this->expLevel + $ev->getExpLevel(); - $this->exp = $this->server->getExpectedExperience($this->expLevel); - $this->calcExpLevel(); - $this->updateExperience(); - return true; - } - return false; + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + return $this->addXpLevel($level); } + /** + * @deprecated Use Human::getTotalXp(), this method will be removed in the future. + */ public function getExp(){ - return $this->exp; + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + return $this->getTotalXp(); } + /** + * @deprecated Use Human::getXpLevel(), this method will be removed in the future. + */ public function getExpLevel(){ - return $this->expLevel; + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + return $this->getXpLevel(); + } + + /** + * @deprecated Use Human::canPickupXp(), this method will be removed in the future. + */ + public function canPickupExp(): bool{ + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + return $this->canPickupXp(); + } + + /** + * @deprecated Use Human::resetXpCooldown(), this method will be removed in the future. + */ + public function resetExpCooldown(){ + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); + $this->resetXpCooldown(); } + /** + * @deprecated + */ public function updateExperience(){ - if($this->getAttributeMap() instanceof AttributeMap){ - $this->getAttributeMap()->getAttribute(Attribute::EXPERIENCE)->setValue(($this->exp - $this->server->getExpectedExperience($this->expLevel)) / ($this->getLevelUpExpectedExperience())); - $this->getAttributeMap()->getAttribute(Attribute::EXPERIENCE_LEVEL)->setValue($this->expLevel); - } + trigger_error("This method is deprecated, do not use it", E_USER_DEPRECATED); } /** @@ -487,6 +492,15 @@ public function getAllowFlight() : bool{ return $this->allowFlight; } + public function setFlying(bool $value){ + $this->flying = $value; + $this->sendSettings(); + } + + public function isFlying() : bool{ + return $this->flying; + } + public function setAutoJump($value){ $this->autoJump = $value; $this->sendSettings(); @@ -600,6 +614,7 @@ public function setOp($value){ } $this->recalculatePermissions(); + $this->sendSettings(); } /** @@ -661,6 +676,8 @@ public function recalculatePermissions(){ if($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)){ $this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this); } + + $this->sendCommandData(); } /** @@ -670,6 +687,25 @@ public function getEffectivePermissions(){ return $this->perm->getEffectivePermissions(); } + public function sendCommandData(){ + $pk = new AvailableCommandsPacket(); + $data = new \stdClass(); + $count = 0; + foreach($this->server->getCommandMap()->getCommands() as $command){ + //TODO: fix command permission checks on join + /*if(!$command->testPermissionSilent($this)){ + continue; + }*/ + ++$count; + $data->{$command->getName()}->versions[0] = $command->generateCustomCommandData($this); + } + + if($count > 0){ + //TODO: structure checking + $pk->commands = json_encode($data); + $this->dataPacket($pk); + } + } /** * @param SourceInterface $interface @@ -810,17 +846,6 @@ protected function switchLevel(Level $targetLevel){ $pk->started = $this->level->stopTime == false; $this->dataPacket($pk); - if($targetLevel->getDimension() != $oldLevel->getDimension()){ - $pk = new ChangeDimensionPacket(); - $pk->dimension = $targetLevel->getDimension(); - $pk->x = $this->x; - $pk->y = $this->y; - $pk->z = $this->z; - $this->dataPacket($pk); - $this->shouldSendStatus = true; - } - $targetLevel->getWeather()->sendWeather($this); - if($this->spawned){ $this->spawnToAll(); } @@ -846,8 +871,8 @@ private function unloadChunk($x, $z, Level $level = null){ /** * @return Position */ - public function getSpawn() : Position{ - if($this->spawnPosition instanceof Position and $this->spawnPosition->getLevel() instanceof Level){ + public function getSpawn(){ + if($this->hasValidSpawnPosition()){ return $this->spawnPosition; }else{ $level = $this->server->getDefaultLevel(); @@ -856,7 +881,14 @@ public function getSpawn() : Position{ } } - public function sendChunk($x, $z, $payload, $ordering = FullChunkDataPacket::ORDER_COLUMNS){ + /** + * @return bool + */ + public function hasValidSpawnPosition() : bool{ + return $this->spawnPosition instanceof WeakPosition and $this->spawnPosition->isValid(); + } + + public function sendChunk($x, $z, $payload){ if($this->connected === false){ return; } @@ -870,7 +902,6 @@ public function sendChunk($x, $z, $payload, $ordering = FullChunkDataPacket::ORD $pk = new FullChunkDataPacket(); $pk->chunkX = $x; $pk->chunkZ = $z; - $pk->order = $ordering; $pk->data = $payload; $this->batchDataPacket($pk); } @@ -941,7 +972,6 @@ protected function sendNextChunk(){ protected function doFirstSpawn(){ $this->spawned = true; - $this->sendSettings(); $this->sendPotionEffects($this); $this->sendData($this); @@ -980,31 +1010,28 @@ protected function doFirstSpawn(){ $this->teleport($pos); + $this->allowFlight = (($this->gamemode == 3) or ($this->gamemode == 1)); + $this->setHealth($this->getHealth()); + $this->server->getPluginManager()->callEvent($ev = new PlayerJoinEvent($this, new TranslationContainer(TextFormat::YELLOW . "%multiplayer.player.joined", [ $this->getDisplayName() ]))); + $this->sendSettings(); + if(strlen(trim($msg = $ev->getJoinMessage())) > 0){ if($this->server->playerMsgType === Server:: PLAYER_MSG_TYPE_MESSAGE) $this->server->broadcastMessage($msg); elseif($this->server->playerMsgType === Server::PLAYER_MSG_TYPE_TIP) $this->server->broadcastTip(str_replace("@player", $this->getName(), $this->server->playerLoginMsg)); elseif($this->server->playerMsgType === Server::PLAYER_MSG_TYPE_POPUP) $this->server->broadcastPopup(str_replace("@player", $this->getName(), $this->server->playerLoginMsg)); } - $this->setAllowFlight($this->gamemode == 3 || $this->gamemode == 1); - $this->server->onPlayerLogin($this); $this->spawnToAll(); - $this->level->getWeather()->sendWeather($this); - if($this->server->expEnabled){ - //$this->checkExpLevel(); - $this->updateExperience(); - } - $this->setHealth($this->getHealth()); - if($this->server->foodEnabled) $this->setFood($this->getFood()); - else $this->setFood(20); - if($this->server->dserverConfig["enable"] and $this->server->dserverConfig["queryAutoUpdate"]) $this->server->updateQuery(); + if($this->server->dserverConfig["enable"] and $this->server->dserverConfig["queryAutoUpdate"]){ + $this->server->updateQuery(); + } /*if($this->server->getUpdater()->hasUpdate() and $this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)){ $this->server->getUpdater()->showPlayerUpdate($this); @@ -1217,10 +1244,9 @@ public function sleepOn(Vector3 $pos){ } $this->sleeping = clone $pos; - $this->teleport(new Position($pos->x + 0.5, $pos->y - 1, $pos->z + 0.5, $this->level)); $this->setDataProperty(self::DATA_PLAYER_BED_POSITION, self::DATA_TYPE_POS, [$pos->x, $pos->y, $pos->z]); - $this->setDataFlag(self::DATA_PLAYER_FLAGS, self::DATA_PLAYER_FLAG_SLEEP, true); + $this->setDataFlag(self::DATA_PLAYER_FLAGS, self::DATA_PLAYER_FLAG_SLEEP, true, self::DATA_TYPE_BYTE); $this->setSpawn($pos); @@ -1242,7 +1268,7 @@ public function setSpawn(Vector3 $pos){ }else{ $level = $pos->getLevel(); } - $this->spawnPosition = new Position($pos->x, $pos->y, $pos->z, $level); + $this->spawnPosition = new WeakPosition($pos->x, $pos->y, $pos->z, $level); $pk = new SetSpawnPositionPacket(); $pk->x = (int) $this->spawnPosition->x; $pk->y = (int) $this->spawnPosition->y; @@ -1256,14 +1282,14 @@ public function stopSleep(){ $this->sleeping = null; $this->setDataProperty(self::DATA_PLAYER_BED_POSITION, self::DATA_TYPE_POS, [0, 0, 0]); - $this->setDataFlag(self::DATA_PLAYER_FLAGS, self::DATA_PLAYER_FLAG_SLEEP, false); + $this->setDataFlag(self::DATA_PLAYER_FLAGS, self::DATA_PLAYER_FLAG_SLEEP, false, self::DATA_TYPE_BYTE); $this->level->sleepTicks = 0; $pk = new AnimatePacket(); $pk->eid = 0; - $pk->action = 3; //Wake up + $pk->action = PlayerAnimationEvent::WAKE_UP; $this->dataPacket($pk); } @@ -1276,8 +1302,8 @@ public function stopSleep(){ */ public function awardAchievement($achievementId){ if(isset(Achievement::$list[$achievementId]) and !$this->hasAchievement($achievementId)){ - foreach(Achievement::$list[$achievementId]["requires"] as $requerimentId){ - if(!$this->hasAchievement($requerimentId)){ + foreach(Achievement::$list[$achievementId]["requires"] as $requirementId){ + if(!$this->hasAchievement($requirementId)){ return false; } } @@ -1305,17 +1331,24 @@ public function getGamemode() : int{ /** * Sets the gamemode, and if needed, kicks the Player. * - * @param int $gm + * @param int $gm + * @param bool $client if the client made this change in their GUI * * @return bool */ - public function setGamemode(int $gm){ + public function setGamemode(int $gm, bool $client = false){ if($gm < 0 or $gm > 3 or $this->gamemode === $gm){ return false; } $this->server->getPluginManager()->callEvent($ev = new PlayerGameModeChangeEvent($this, $gm)); if($ev->isCancelled()){ + if($client){ //gamemode change by client in the GUI + $pk = new SetPlayerGameTypePacket(); + $pk->gamemode = $this->gamemode & 0x01; + $this->dataPacket($pk); + $this->sendSettings(); + } return false; } @@ -1326,32 +1359,32 @@ public function setGamemode(int $gm){ $this->gamemode = $gm; $this->allowFlight = $this->isCreative(); - if($this->isSpectator()){ + $this->flying = true; $this->despawnFromAll(); + + // Client automatically turns off flight controls when on the ground. + // A combination of this hack and a new AdventureSettings flag FINALLY + // fixes spectator flight controls. Thank @robske110 for this hack. + $this->teleport($this->temporalVector->setComponents($this->x, $this->y + 0.1, $this->z)); }else{ + if($this->isSurvival()){ + $this->flying = false; + } $this->spawnToAll(); } - $this->namedtag->playerGameType = new IntTag("playerGameType", $this->gamemode); + $this->resetFallDistance(); - /*$spawnPosition = $this->getSpawn(); + $this->namedtag->playerGameType = new IntTag("playerGameType", $this->gamemode); - $pk = new StartGamePacket(); - $pk->seed = -1; - $pk->x = $this->x; - $pk->y = $this->y; - $pk->z = $this->z; - $pk->spawnX = (int)$spawnPosition->x; - $pk->spawnY = (int)$spawnPosition->y; - $pk->spawnZ = (int)$spawnPosition->z; - $pk->generator = 1; //0 old, 1 infinite, 2 flat - $pk->gamemode = $this->gamemode & 0x01; - $pk->eid = 0;*/ - $pk = new SetPlayerGameTypePacket(); - $pk->gamemode = $this->gamemode & 0x01; - $this->dataPacket($pk); - $this->sendSettings(); + if(!$client){ //Gamemode changed by server, do not send for client changes + $pk = new SetPlayerGameTypePacket(); + $pk->gamemode = $this->gamemode & 0x01; + $this->dataPacket($pk); + }else{ + Command::broadcastCommandMessage($this, new TranslationContainer("commands.gamemode.success.self", [Server::getGamemodeString($gm)])); + } if($this->gamemode === Player::SPECTATOR){ $pk = new ContainerSetContentPacket(); @@ -1363,7 +1396,9 @@ public function setGamemode(int $gm){ $pk->slots = array_merge(Item::getCreativeItems(), $this->personalCreativeItems); $this->dataPacket($pk); } - + + $this->sendSettings(); + $this->inventory->sendContents($this); $this->inventory->sendContents($this->getViewers()); $this->inventory->sendHeldItem($this->hasSpawned); @@ -1374,87 +1409,43 @@ public function setGamemode(int $gm){ * Sends all the option flags */ public function sendSettings(){ - /* - bit mask | flag name - 0x00000001 world_inmutable - 0x00000002 no_pvp - 0x00000004 no_pvm - 0x00000008 no_mvp - 0x00000010 static_time - 0x00000020 nametags_visible - 0x00000040 auto_jump - 0x00000080 allow_fly - 0x00000100 noclip - 0x00000200 ? - 0x00000400 ? - 0x00000800 ? - 0x00001000 ? - 0x00002000 ? - 0x00004000 ? - 0x00008000 ? - 0x00010000 ? - 0x00020000 ? - 0x00040000 ? - 0x00080000 ? - 0x00100000 ? - 0x00200000 ? - 0x00400000 ? - 0x00800000 ? - 0x01000000 ? - 0x02000000 ? - 0x04000000 ? - 0x08000000 ? - 0x10000000 ? - 0x20000000 ? - 0x40000000 ? - 0x80000000 ? - */ - $flags = 0; - if($this->isAdventure()){ - $flags |= 0x01; //Do not allow placing/breaking blocks, adventure mode - } - - /*if($nametags !== false){ - $flags |= 0x20; //Show Nametags - }*/ - - if($this->autoJump){ - $flags |= 0x40; - } - - if($this->allowFlight){ - $flags |= 0x80; - } - - if($this->isSpectator()){ - $flags |= 0x100; - } - - $flags |= 0x02; // No PvP (Remove hit markers client-side). - $flags |= 0x04; // No PvM (Remove hit markers client-side). - $flags |= 0x08; // No PvE (Remove hit markers client-side). - $pk = new AdventureSettingsPacket(); - $pk->flags = $flags; - $pk->userPermission = 2; - $pk->globalPermission = 2; + $pk->flags = 0; + $pk->worldImmutable = $this->isAdventure(); + $pk->autoJump = $this->autoJump; + $pk->allowFlight = $this->allowFlight; + $pk->noClip = $this->isSpectator(); + $pk->isFlying = $this->flying; + $pk->userPermission = ($this->isOp() ? AdventureSettingsPacket::PERMISSION_OPERATOR : AdventureSettingsPacket::PERMISSION_NORMAL); $this->dataPacket($pk); } - - public function isSurvival() : bool{ - return ($this->gamemode & 0x01) === 0; + + public function isSurvival(bool $literal = false) : bool{ + if($literal){ + return $this->gamemode === Player::SURVIVAL; + }else{ + return ($this->gamemode & 0x01) === 0; + } } - public function isCreative() : bool{ - return ($this->gamemode & 0x01) > 0; + public function isCreative(bool $literal = false) : bool{ + if($literal){ + return $this->gamemode === Player::CREATIVE; + }else{ + return ($this->gamemode & 0x01) === 1; + } } public function isSpectator() : bool{ - return $this->gamemode === 3; + return $this->gamemode === Player::SPECTATOR; } - public function isAdventure() : bool{ - return ($this->gamemode & 0x02) > 0; + public function isAdventure(bool $literal = false) : bool{ + if($literal){ + return $this->gamemode === Player::ADVENTURE; + }else{ + return ($this->gamemode & 0x02) > 0; + } } public function getDrops() : array{ @@ -1465,31 +1456,6 @@ public function getDrops() : array{ return []; } - /** - * @deprecated - * @param $entityId - * @param $x - * @param $y - * @param $z - */ - public function addEntityMotion($entityId, $x, $y, $z){ - - } - - /** - * @deprecated - * @param $entityId - * @param $x - * @param $y - * @param $z - * @param $yaw - * @param $pitch - * @param null $headYaw - */ - public function addEntityMovement($entityId, $x, $y, $z, $yaw, $pitch, $headYaw = null){ - - } - public function setDataProperty($id, $type, $value){ if(parent::setDataProperty($id, $type, $value)){ $this->sendData($this, [$id => $this->dataProperties[$id]]); @@ -1516,19 +1482,15 @@ protected function checkGroundState($movX, $movY, $movZ, $dx, $dy, $dz){ protected function checkBlockCollision(){ foreach($blocksaround = $this->getBlocksAround() as $block){ $block->onEntityCollide($this); - if($this->getServer()->redstoneEnabled){ if($block instanceof PressurePlate){ $this->activatedPressurePlates[Level::blockHash($block->x, $block->y, $block->z)] = $block; } - } } - if($this->getServer()->redstoneEnabled){ /** @var \devmine\inventory\blocks\PressurePlate $block * */ foreach($this->activatedPressurePlates as $key => $block){ if(!isset($blocksaround[$key])) $block->checkActivation(); } - } } protected function checkNearEntities($tickDiff){ @@ -1541,8 +1503,15 @@ protected function checkNearEntities($tickDiff){ if($entity instanceof Arrow and $entity->hadCollision){ $item = Item::get(Item::ARROW, $entity->getPotionId(), 1); - if($this->isSurvival() and !$this->inventory->canAddItem($item)){ - continue; + + $add = false; + if(!$this->server->allowInventoryCheats and !$this->isCreative()){ + if(!$this->getFloatingInventory()->canAddItem($item) or !$this->inventory->canAddItem($item)){ + //The item is added to the floating inventory to allow client to handle the pickup + //We have to also check if it can be added to the real inventory before sending packets. + continue; + } + $add = true; } $this->server->getPluginManager()->callEvent($ev = new InventoryPickupArrowEvent($this->inventory, $entity)); @@ -1550,7 +1519,7 @@ protected function checkNearEntities($tickDiff){ continue; } - /*$pk = new TakeItemEntityPacket(); + $pk = new TakeItemEntityPacket(); $pk->eid = $this->getId(); $pk->target = $entity->getId(); Server::broadcastPacket($entity->getViewers(), $pk); @@ -1558,18 +1527,23 @@ protected function checkNearEntities($tickDiff){ $pk = new TakeItemEntityPacket(); $pk->eid = 0; $pk->target = $entity->getId(); - $this->dataPacket($pk);*/ - //This may cause client crash + $this->dataPacket($pk); - $this->inventory->addItem(clone $item); + if($add){ + $this->getFloatingInventory()->addItem(clone $item); + } $entity->kill(); }elseif($entity instanceof DroppedItem){ if($entity->getPickupDelay() <= 0){ $item = $entity->getItem(); if($item instanceof Item){ - if($this->isSurvival() and !$this->inventory->canAddItem($item)){ - continue; + $add = false; + if(!$this->server->allowInventoryCheats and !$this->isCreative()){ + if(!$this->getFloatingInventory()->canAddItem($item) or !$this->inventory->canAddItem($item)){ + continue; + } + $add = true; } $this->server->getPluginManager()->callEvent($ev = new InventoryPickupItemEvent($this->inventory, $entity)); @@ -1580,7 +1554,7 @@ protected function checkNearEntities($tickDiff){ switch($item->getId()){ case Item::WOOD: $this->awardAchievement("mineWood"); - + break; case Item::DIAMOND: $this->awardAchievement("diamond"); @@ -1597,7 +1571,9 @@ protected function checkNearEntities($tickDiff){ $pk->target = $entity->getId(); $this->dataPacket($pk); - $this->inventory->addItem(clone $item); + if($add){ + $this->getFloatingInventory()->addItem(clone $item); + } $entity->kill(); } } @@ -1615,25 +1591,7 @@ protected function processMovement($tickDiff){ $distanceSquared = $newPos->distanceSquared($this); $revert = false; - - if($this->server->checkMovement){ - if(($distanceSquared / ($tickDiff ** 2)) > 200){ - $revert = true; - }else{ - if($this->chunk === null or !$this->chunk->isGenerated()){ - $chunk = $this->level->getChunk($newPos->x >> 4, $newPos->z >> 4, false); - if($chunk === null or !$chunk->isGenerated()){ - $revert = true; - $this->nextChunkOrderRun = 0; - }else{ - if($this->chunk !== null){ - $this->chunk->removeEntity($this); - } - $this->chunk = $chunk; - } - } - } - }else{ + { if($this->chunk === null or !$this->chunk->isGenerated()){ $chunk = $this->level->getChunk($newPos->x >> 4, $newPos->z >> 4, false); if($chunk === null or !$chunk->isGenerated()){ @@ -1659,29 +1617,9 @@ protected function processMovement($tickDiff){ $diffY = $this->y - $newPos->y; $diffZ = $this->z - $newPos->z; - $yS = 0.5 + $this->ySize; - if($diffY >= -$yS or $diffY <= $yS){ - $diffY = 0; - } - $diff = ($diffX ** 2 + $diffY ** 2 + $diffZ ** 2) / ($tickDiff ** 2); - /*if($this->isSurvival()){ - if(!$revert and !$this->isSleeping()){ - if($diff > 0.0625){ - $revert = true; - $this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("devmine.player.invalidMove", [$this->getName()])); - } - } - } - if($diff > 0){ - $this->x = $newPos->x; - $this->y = $newPos->y; - $this->z = $newPos->z; - $radius = $this->width / 2; - $this->boundingBox->setBounds($this->x - $radius, $this->y, $this->z - $radius, $this->x + $radius, $this->y + $this->height, $this->z + $radius); - }*/ } $from = new Location($this->lastX, $this->lastY, $this->lastZ, $this->lastYaw, $this->lastPitch, $this->level); @@ -1708,7 +1646,6 @@ protected function processMovement($tickDiff){ $this->server->getPluginManager()->callEvent($ev); if(!($revert = $ev->isCancelled())){ //Yes, this is intended - //$teleported = false; if($this->server->netherEnabled){ if($this->isInsideOfPortal()){ if($this->portalTime == 0){ @@ -1719,13 +1656,10 @@ protected function processMovement($tickDiff){ } } - //if($this->server->redstoneEnabled) $this->getLevel()->updateAround($ev->getTo()->round()); - - // if(!$teleported){ if($to->distanceSquared($ev->getTo()) > 0.01){ //If plugins modify the destination $this->teleport($ev->getTo()); }else{ - $this->level->addEntityMovement($this->x >> 4, $this->z >> 4, $this->getId(), $this->x, $this->y + $this->getEyeHeight(), $this->z, $this->yaw, $this->pitch, $this->yaw); + $this->addMovement($this->x, $this->y + $this->getEyeHeight(), $this->z, $this->yaw, $this->pitch, $this->yaw); } if($this->fishingHook instanceof FishingHook){ @@ -1733,17 +1667,6 @@ protected function processMovement($tickDiff){ $this->setFishingHook(); } } - // } - - /*if($this->server->expEnabled){ - /** @var \devmine\creatures\entities\ExperienceOrb $e * - foreach($this->level->getNearbyExperienceOrb(new AxisAlignedBB($this->x - 1, $this->y - 1, $this->z - 1, $this->x + 1, $this->y + 2, $this->z + 1)) as $e){ - if($e->getExperience() > 0){ - $e->close(); - $this->addExperience($e->getExperience()); - } - } - }*/ } } @@ -1778,12 +1701,21 @@ protected function processMovement($tickDiff){ $this->newPosition = null; } + /*public function addMovement($x, $y, $z, $yaw, $pitch, $headYaw = null){ + if($this->chunk !== null){ + $this->level->addPlayerMovement($this->chunk->getX(), $this->chunk->getZ(), $this->id, $x, $y, $z, $yaw, $pitch, $this->onGround, $headYaw === null ? $yaw : $headYaw); + } + }*/ + public function setMotion(Vector3 $mot){ if(parent::setMotion($mot)){ if($this->chunk !== null){ $this->level->addEntityMotion($this->chunk->getX(), $this->chunk->getZ(), $this->getId(), $this->motionX, $this->motionY, $this->motionZ); $pk = new SetEntityMotionPacket(); - $pk->entities[] = [0, $mot->x, $mot->y, $mot->z]; + $pk->eid = 0; + $pk->motionX = $mot->x; + $pk->motionY = $mot->y; + $pk->motionZ = $mot->z; $this->dataPacket($pk); } @@ -1817,8 +1749,8 @@ public function isMoving() : bool{ return $this->moving; } - public function sendAttributes(){ - $entries = $this->attributeMap->needSend(); + public function sendAttributes(bool $sendAll = false){ + $entries = $sendAll ? $this->attributeMap->getAll() : $this->attributeMap->needSend(); if(count($entries) > 0){ $pk = new UpdateAttributesPacket(); $pk->entityId = 0; @@ -1900,90 +1832,20 @@ public function onUpdate($currentTick){ } } } - $this->processMovement($tickDiff); + if(!$this->isSleeping()){ + $this->processMovement($tickDiff); + } if(!$this->isSpectator()) $this->entityBaseTick($tickDiff); if($this->isOnFire() or $this->lastUpdate % 10 == 0){ if($this->isCreative() and !$this->isInsideOfFire()){ $this->extinguish(); - }elseif($this->getLevel()->getWeather()->isRainy()){ - if($this->getLevel()->canBlockSeeSky($this)){ - $this->extinguish(); - } - } - } - - if($this->server->antiFly){ - if(!$this->isSpectator() and $this->speed !== null){ - if($this->onGround){ - if($this->inAirTicks !== 0){ - $this->startAirTicks = 5; - } - $this->inAirTicks = 0; - }else{ - if(!$this->allowFlight and $this->inAirTicks > 10 and !$this->isSleeping() and $this->getDataProperty(self::DATA_NO_AI) !== 1){ - //expectedVelocity here is not calculated correctly - //This causes players to fall too fast when bouncing on slime when antiFly is enabled - $expectedVelocity = (-$this->gravity) / $this->drag - ((-$this->gravity) / $this->drag) * exp(-$this->drag * ($this->inAirTicks - $this->startAirTicks)); - $diff = ($this->speed->y - $expectedVelocity) ** 2; - if(!$this->hasEffect(Effect::JUMP) and $diff > 0.6 and $expectedVelocity < $this->speed->y and !$this->server->getAllowFlight()){ - $this->setMotion($this->temporalVector->setComponents(0, $expectedVelocity, 0)); - /*if($this->inAirTicks < 1000){ - - }elseif($this->kick("Flying is not enabled on this server")){ - $this->timings->stopTiming(); - return false; - }*/ - } - } - ++$this->inAirTicks; - } } } - if($this->server->foodEnabled){ - if($this->starvationTick >= 20){ - $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_STARVATION, 1); - if($this->getHealth() > $this->server->hungerHealth) $this->attack(1, $ev); - $this->starvationTick = 0; - } - if($this->getFood() <= 0){ - $this->starvationTick++; - } - - if($this->isMoving() && $this->isSurvival()){ - if($this->isSprinting()){ - $this->foodUsageTime += 500; - }else{ - $this->foodUsageTime += 250; - } - } - - if($this->foodUsageTime >= 200000 && $this->foodEnabled){ - $this->foodUsageTime -= 200000; - $this->subtractFood(1); - } - - if((($currentTick % 80) == 0) and $this->getHealth() < $this->getMaxHealth() && $this->getFood() >= 18 && $this->foodEnabled){ - $ev = new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_EATING); - $this->heal(1, $ev); - } - - if($this->foodTick >= $this->server->hungerTimer){ - if($this->foodEnabled){ - if($this->foodDepletion >= 2){ - $this->subtractFood(1); - $this->foodDepletion = 0; - }else{ - $this->foodDepletion++; - } - } - $this->foodTick = 0; - } - if($this->getHealth() < $this->getMaxHealth()){ - $this->foodTick++; - } + if($this->getTransactionQueue() !== null){ + $this->getTransactionQueue()->execute(); } } @@ -1994,26 +1856,6 @@ public function onUpdate($currentTick){ return true; } - public $eatCoolDown = 0; - - public function consumeHeldItem(){ - //TODO: Move this into entity class so that any mob can eat/drink - if($this->eatCoolDown + 2000 >= time() || !$this->spawned){ - return; - } - $item = $this->inventory->getItemInHand(); - if($item instanceof FoodSource or $item instanceof Potion){ - if($item->canBeConsumedBy($this)){ - $this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $item)); - if($ev->isCancelled()){ - $this->inventory->sendContents($this); - return; - } - $item->onConsume($this); - } - } - } - public function checkNetwork(){ if(!$this->isOnline()){ return; @@ -2035,36 +1877,21 @@ public function checkNetwork(){ } public function canInteract(Vector3 $pos, $maxDistance, $maxDiff = 0.5){ - if($this->distanceSquared($pos) > $maxDistance ** 2){ + $eyePos = $this->getPosition()->add(0, $this->getEyeHeight(), 0); + if($eyePos->distanceSquared($pos) > $maxDistance ** 2){ return false; } $dV = $this->getDirectionPlane(); - $dot = $dV->dot(new Vector2($this->x, $this->z)); + $dot = $dV->dot(new Vector2($eyePos->x, $eyePos->z)); $dot1 = $dV->dot(new Vector2($pos->x, $pos->z)); return ($dot1 - $dot) >= -$maxDiff; } public function onPlayerPreLogin(){ - //TODO: implement auth - $this->tryAuthenticate(); - } - - public function tryAuthenticate(){ $pk = new PlayStatusPacket(); $pk->status = PlayStatusPacket::LOGIN_SUCCESS; $this->dataPacket($pk); - //TODO: implement authentication after it is available - $this->authenticateCallback(true); - } - - public function authenticateCallback($valid){ - - //TODO add more stuff after authentication is available - if(!$valid){ - $this->close("", "disconnectionScreen.invalidSession"); - return; - } $this->processLogin(); } @@ -2130,7 +1957,7 @@ protected function processLogin(){ } } $this->setNameTag($this->getDisplayName()); - + $nbt = $this->server->getOfflinePlayerData($this->username); $this->playedBefore = ($nbt["lastPlayed"] - $nbt["firstPlayed"]) > 1; if(!isset($nbt->NameTag)){ @@ -2138,19 +1965,15 @@ protected function processLogin(){ }else{ $nbt["NameTag"] = $this->username; } - if(!isset($nbt->Hunger) or !isset($nbt->Experience) or !isset($nbt->ExpLevel) or !isset($nbt->Health) or !isset($nbt->MaxHealth)){ + if(!isset($nbt->Hunger) or !isset($nbt->Health) or !isset($nbt->MaxHealth)){ $nbt->Hunger = new ShortTag("Hunger", 20); - $nbt->Experience = new LongTag("Experience", 0); - $nbt->ExpLevel = new LongTag("ExpLevel", 0); $nbt->Health = new ShortTag("Health", 20); $nbt->MaxHealth = new ShortTag("MaxHealth", 20); } $this->food = $nbt["Hunger"]; $this->setMaxHealth($nbt["MaxHealth"]); Entity::setHealth(($nbt["Health"] <= 0) ? 20 : $nbt["Health"]); - $this->exp = ($nbt["Experience"] > 0) ? $nbt["Experience"] : 0; - $this->expLevel = ($nbt["ExpLevel"] >= 0) ? $nbt["ExpLevel"] : 0; - $this->calcExpLevel(); + $this->gamemode = $nbt["playerGameType"] & 0x03; if($this->server->getForceGamemode()){ $this->gamemode = $this->server->getGamemode(); @@ -2198,34 +2021,37 @@ protected function processLogin(){ return; } - if($this->isCreative()){ - $this->inventory->setHeldItemSlot(0); - }else{ - $this->inventory->setHeldItemSlot($this->inventory->getHotbarSlotIndex(0)); + if(!$this->isConnected()){ + return; } - $pk = new PlayStatusPacket(); - $pk->status = PlayStatusPacket::LOGIN_SUCCESS; - $this->dataPacket($pk); - if($this->spawnPosition === null and isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName($this->namedtag["SpawnLevel"])) instanceof Level){ - $this->spawnPosition = new Position($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level); + $this->dataPacket(new ResourcePacksInfoPacket()); + + if(!$this->hasValidSpawnPosition() and isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName($this->namedtag["SpawnLevel"])) instanceof Level){ + $this->spawnPosition = new WeakPosition($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level); } $spawnPosition = $this->getSpawn(); $pk = new StartGamePacket(); - $pk->seed = -1; - $pk->dimension = $this->level->getDimension(); + $pk->entityUniqueId = 0; + $pk->entityRuntimeId = 0; $pk->x = $this->x; $pk->y = $this->y; $pk->z = $this->z; - $pk->spawnX = (int) $spawnPosition->x; - $pk->spawnY = (int) $spawnPosition->y; - $pk->spawnZ = (int) $spawnPosition->z; - $pk->generator = 1; //0 old, 1 infinite, 2 flat + $pk->seed = -1; $pk->gamemode = $this->gamemode & 0x01; - $pk->eid = 0; //Always use EntityID as zero for the actual player - /*$pk = new SetPlayerGameTypePacket(); - $pk->gamemode = $this->gamemode & 0x01;*/ + $pk->difficulty = $this->server->getDifficulty(); + $pk->spawnX = $spawnPosition->getFloorX(); + $pk->spawnY = $spawnPosition->getFloorY(); + $pk->spawnZ = $spawnPosition->getFloorZ(); + $pk->hasBeenLoadedInCreative = 1; + $pk->dayCycleStopTime = -1; //TODO: implement this properly + $pk->eduMode = 0; + $pk->rainLevel = 0; //TODO: implement these properly + $pk->lightningLevel = 0; + $pk->commandsEnabled = 1; + $pk->unknown = "UNKNOWN"; + $pk->worldName = $this->server->getMotd(); $this->dataPacket($pk); $pk = new SetTimePacket(); @@ -2233,20 +2059,11 @@ protected function processLogin(){ $pk->started = $this->level->stopTime == false; $this->dataPacket($pk); - $pk = new SetSpawnPositionPacket(); - $pk->x = (int) $spawnPosition->x; - $pk->y = (int) $spawnPosition->y; - $pk->z = (int) $spawnPosition->z; - $this->dataPacket($pk); - - $pk = new SetHealthPacket(); - $pk->health = $this->getHealth(); - $this->dataPacket($pk); + $this->sendAttributes(true); + $this->setNameTagVisible(true); + $this->setNameTagAlwaysVisible(true); - $pk = new SetDifficultyPacket(); - $pk->difficulty = $this->server->getDifficulty(); - $this->dataPacket($pk); - $this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("devmine.player.logIn", [ + $this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("DevMine.player.logIn", [ TextFormat::AQUA . $this->username . TextFormat::WHITE, $this->ip, $this->port, @@ -2270,12 +2087,9 @@ protected function processLogin(){ $pk->slots = array_merge(Item::getCreativeItems(), $this->personalCreativeItems); $this->dataPacket($pk); } - - $pk = new SetEntityDataPacket(); - $pk->eid = 0; - $pk->epilogos = [self::DATA_LEAD_HOLDER => [self::DATA_TYPE_LONG, -1]]; - $this->dataPacket($pk); - + + $this->sendCommandData(); + $this->forceMovement = $this->teleportPosition = $this->getPosition(); } @@ -2293,7 +2107,7 @@ public function getProtocol(){ * @param DataPacket $packet */ public function handleDataPacket(DataPacket $packet){ - + if($this->connected === false){ return; } @@ -2316,23 +2130,23 @@ public function handleDataPacket(DataPacket $packet){ switch($packet::NETWORK_ID){ case ProtocolInfo::ITEM_FRAME_DROP_ITEM_PACKET: - $solidentity = $this->level->getsolidentity($this->temporalVector->setComponents($packet->x, $packet->y, $packet->z)); - if($solidentity instanceof ItemFrame){ - $block = $this->level->getBlock($solidentity); + $tile = $this->level->getTile($this->temporalVector->setComponents($packet->x, $packet->y, $packet->z)); + if($tile instanceof ItemFrame){ + $block = $this->level->getBlock($tile); $this->server->getPluginManager()->callEvent($ev = new BlockBreakEvent($this, $block, $this->getInventory()->getItemInHand(), true)); if(!$ev->isCancelled()){ - $item = $solidentity->getItem(); - $this->server->getPluginManager()->callEvent($ev = new ItemFrameDropItemEvent($this, $block, $solidentity, $item)); + $item = $tile->getItem(); + $this->server->getPluginManager()->callEvent($ev = new ItemFrameDropItemEvent($this, $block, $tile, $item)); if(!$ev->isCancelled()){ if($item->getId() !== Item::AIR){ - if((mt_rand(0, 10) / 10) < $solidentity->getItemDropChance()){ - $this->level->dropItem($solidentity, $item); + if((mt_rand(0, 10) / 10) < $tile->getItemDropChance()){ + $this->level->dropItem($tile, $item); } - $solidentity->setItem(Item::get(Item::AIR)); - $solidentity->setItemRotation(0); + $tile->setItem(Item::get(Item::AIR)); + $tile->setItemRotation(0); } - }else $solidentity->spawnTo($this); - }else $solidentity->spawnTo($this); + }else $tile->spawnTo($this); + }else $tile->spawnTo($this); } break; case ProtocolInfo::REQUEST_CHUNK_RADIUS_PACKET: @@ -2343,6 +2157,9 @@ public function handleDataPacket(DataPacket $packet){ $pk->radius = ($this->server->chunkRadius != -1) ? $this->server->chunkRadius : $packet->radius; $this->dataPacket($pk); break; + case ProtocolInfo::PLAYER_FALL_PACKET: + $this->fallDistance = $packet->fallDistance; + break; case ProtocolInfo::PLAYER_INPUT_PACKET: break; case ProtocolInfo::LOGIN_PACKET: @@ -2360,11 +2177,16 @@ public function handleDataPacket(DataPacket $packet){ $this->iusername = strtolower($this->username); $this->protocol = $packet->protocol; + if($this->server->getConfigBoolean("online-mode", false) && $packet->identityPublicKey === null){ + $this->kick("disconnectionScreen.notAuthenticated", false); + break; + } + if(count($this->server->getOnlinePlayers()) >= $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)){ break; } - if(!in_array($packet->protocol, ProtocolInfo::ACCEPTED_PROTOCOLS)){ + if($packet->protocol !== ProtocolInfo::CURRENT_PROTOCOL){ if($packet->protocol < ProtocolInfo::CURRENT_PROTOCOL){ $message = "disconnectionScreen.outdatedClient"; @@ -2384,7 +2206,6 @@ public function handleDataPacket(DataPacket $packet){ } $this->randomClientId = $packet->clientId; - $this->loginData = ["clientId" => $packet->clientId, "loginData" => null]; $this->uuid = UUID::fromString($packet->clientUUID); $this->rawUUID = $this->uuid->toBinary(); @@ -2425,10 +2246,16 @@ public function handleDataPacket(DataPacket $packet){ break; } - $this->onPlayerPreLogin(); + if($this->isConnected()){ + $this->onPlayerPreLogin(); + } break; case ProtocolInfo::MOVE_PLAYER_PACKET: + if($this->teleportPosition !== null){ + break; + } + if($this->linkedEntity instanceof Entity){ $entity = $this->linkedEntity; if($entity instanceof Boat){ @@ -2449,8 +2276,8 @@ public function handleDataPacket(DataPacket $packet){ $this->forceMovement = new Vector3($this->x, $this->y, $this->z); } - if($this->teleportPosition !== null or ($this->forceMovement instanceof Vector3 and (($dist = $newPos->distanceSquared($this->forceMovement)) > 0.1 or $revert))){ - if($this->forceMovement instanceof Vector3) $this->sendPosition($this->forceMovement, $packet->yaw, $packet->pitch); + if($this->forceMovement instanceof Vector3 and (($dist = $newPos->distanceSquared($this->forceMovement)) > 0.1 or $revert)){ + $this->sendPosition($this->forceMovement, $packet->yaw, $packet->pitch); }else{ $packet->yaw %= 360; $packet->pitch %= 360; @@ -2461,75 +2288,36 @@ public function handleDataPacket(DataPacket $packet){ $this->setRotation($packet->yaw, $packet->pitch); $this->newPosition = $newPos; - $this->forceMovement = null; } + $this->forceMovement = null; break; - case ProtocolInfo::MOB_EQUIPMENT_PACKET: - if($this->spawned === false or !$this->isAlive()){ + case ProtocolInfo::ADVENTURE_SETTINGS_PACKET: + //TODO: player abilities, check for other changes + if($packet->isFlying and !$this->allowFlight){ + $this->kick("Flying is not enabled on this server"); break; - } - - if($packet->slot === 0x28 or $packet->slot === 0 or $packet->slot === 255){ //0 for 0.8.0 compatibility - $packet->slot = -1; //Air }else{ - $packet->slot -= 9; //Get real block slot - } - - /** @var Item $item */ - $item = null; - - if($this->isCreative()){ //Creative mode match - $item = $packet->item; - $slot = Item::getCreativeItemIndex($item); - }else{ - $item = $this->inventory->getItem($packet->slot); - $slot = $packet->slot; - } - - if($packet->slot === -1){ //Air - if($this->isCreative()){ - $found = false; - for($i = 0; $i < $this->inventory->getHotbarSize(); ++$i){ - if($this->inventory->getHotbarSlotIndex($i) === -1){ - $this->inventory->setHeldItemIndex($i); - $found = true; - break; - } - } - - if(!$found){ //couldn't find a empty slot (error) - $this->inventory->sendContents($this); - break; - } + $this->server->getPluginManager()->callEvent($ev = new PlayerToggleFlightEvent($this, $packet->isFlying)); + if($ev->isCancelled()){ + $this->sendSettings(); }else{ - if($packet->selectedSlot >= 0 and $packet->selectedSlot < 9){ - $this->inventory->setHeldItemIndex($packet->selectedSlot, false); - $this->inventory->setHeldItemSlot($packet->slot); - $this->inventory->sendHeldItem($this->getViewers()); - }else{ - $this->inventory->sendContents($this); - break; - } + $this->flying = $ev->isFlying(); } - }elseif($item === null or $slot === -1 or !$item->deepEquals($packet->item)){ // packet error or not implemented - $this->inventory->sendContents($this); break; - }elseif($this->isCreative()){ - $this->inventory->setHeldItemIndex($packet->selectedSlot, false); - $this->inventory->setItem($packet->selectedSlot, $item); - $this->inventory->setHeldItemSlot($packet->selectedSlot); - $this->inventory->sendHeldItem($this->getViewers()); - }else{ - if($packet->selectedSlot >= 0 and $packet->selectedSlot < $this->inventory->getHotbarSize()){ - $this->inventory->setHeldItemIndex($packet->selectedSlot, false); - $this->inventory->setHeldItemSlot($slot); - $this->inventory->sendHeldItem($this->getViewers()); - }else{ - $this->inventory->sendContents($this); - break; - } } + break; + case ProtocolInfo::MOB_EQUIPMENT_PACKET: + if($this->spawned === false or !$this->isAlive()){ + break; + } + /** + * Handle hotbar slot remapping + * This is the only time and place when hotbar mapping should ever be changed. + * Changing hotbar slot mapping at will has been deprecated because it causes far too many + * issues with Windows 10 Edition Beta. + */ + $this->inventory->setHeldItemIndex($packet->selectedSlot, false, $packet->slot); $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); break; @@ -2540,12 +2328,12 @@ public function handleDataPacket(DataPacket $packet){ $blockVector = new Vector3($packet->x, $packet->y, $packet->z); - $this->craftingType = 0; + $this->craftingType = self::CRAFTING_SMALL; if($packet->face >= 0 and $packet->face <= 5){ //Use Block, place $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); - if(!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13) or $this->isSpectator()){ + if($this->isSpectator()){ }elseif($this->isCreative()){ $item = $this->inventory->getItemInHand(); @@ -2576,11 +2364,7 @@ public function handleDataPacket(DataPacket $packet){ $this->level->sendBlocks([$this], [$target, $block], UpdateBlockPacket::FLAG_ALL_PRIORITY); break; - }elseif($packet->face === 0xff){ - if($this->isSpectator()){ - break; - } - + }elseif($packet->face === -1){ $aimPos = (new Vector3($packet->x / 32768, $packet->y / 32768, $packet->z / 32768))->normalize(); if($this->isCreative()){ @@ -2663,9 +2447,9 @@ public function handleDataPacket(DataPacket $packet){ $item->setCount($item->getCount() - 1); $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR)); } - if($snowball instanceof Projecsolidentity){ - $this->server->getPluginManager()->callEvent($projecsolidentityEv = new ProjecsolidentityLaunchEvent($snowball)); - if($projecsolidentityEv->isCancelled()){ + if($snowball instanceof Projectile){ + $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($snowball)); + if($projectileEv->isCancelled()){ $snowball->kill(); }else{ $snowball->spawnToAll(); @@ -2699,9 +2483,9 @@ public function handleDataPacket(DataPacket $packet){ $item->setCount($item->getCount() - 1); $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR)); } - if($egg instanceof Projecsolidentity){ - $this->server->getPluginManager()->callEvent($projecsolidentityEv = new ProjecsolidentityLaunchEvent($egg)); - if($projecsolidentityEv->isCancelled()){ + if($egg instanceof Projectile){ + $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($egg)); + if($projectileEv->isCancelled()){ $egg->kill(); }else{ $egg->spawnToAll(); @@ -2735,9 +2519,9 @@ public function handleDataPacket(DataPacket $packet){ $item->setCount($item->getCount() - 1); $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR)); } - if($thrownExpBottle instanceof Projecsolidentity){ - $this->server->getPluginManager()->callEvent($projecsolidentityEv = new ProjecsolidentityLaunchEvent($thrownExpBottle)); - if($projecsolidentityEv->isCancelled()){ + if($thrownExpBottle instanceof Projectile){ + $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($thrownExpBottle)); + if($projectileEv->isCancelled()){ $thrownExpBottle->kill(); }else{ $thrownExpBottle->spawnToAll(); @@ -2772,9 +2556,9 @@ public function handleDataPacket(DataPacket $packet){ $item->setCount($item->getCount() - 1); $this->inventory->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR)); } - if($thrownPotion instanceof Projecsolidentity){ - $this->server->getPluginManager()->callEvent($projecsolidentityEv = new ProjecsolidentityLaunchEvent($thrownPotion)); - if($projecsolidentityEv->isCancelled()){ + if($thrownPotion instanceof Projectile){ + $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($thrownPotion)); + if($projectileEv->isCancelled()){ $thrownPotion->kill(); }else{ $thrownPotion->spawnToAll(); @@ -2790,7 +2574,6 @@ public function handleDataPacket(DataPacket $packet){ } break; case ProtocolInfo::PLAYER_ACTION_PACKET: - //$this->consumeHeldItem(); if($this->spawned === false or $this->blocked === true or (!$this->isAlive() and $packet->action !== PlayerActionPacket::ACTION_SPAWN_SAME_DIMENSION and $packet->action !== PlayerActionPacket::ACTION_SPAWN_OVERWORLD)){ break; } @@ -2800,8 +2583,7 @@ public function handleDataPacket(DataPacket $packet){ switch($packet->action){ case PlayerActionPacket::ACTION_START_BREAK: - //Fixes fire breaking in creative. - if(/*$this->lastBreak !== PHP_INT_MAX or */$pos->distanceSquared($this) > 10000){ + if($this->lastBreak !== PHP_INT_MAX){ break; } $target = $this->level->getBlock($pos); @@ -2811,6 +2593,7 @@ public function handleDataPacket(DataPacket $packet){ $side = $target->getSide($packet->face); if($side instanceof Fire){ $side->getLevel()->setBlock($side, new Air()); + break; } $this->lastBreak = microtime(true); }else{ @@ -2871,10 +2654,10 @@ public function handleDataPacket(DataPacket $packet){ $this->server->getPluginManager()->callEvent($ev); if($ev->isCancelled()){ - $ev->getProjecsolidentity()->kill(); + $ev->getProjectile()->kill(); $this->inventory->sendContents($this); }else{ - $ev->getProjecsolidentity()->setMotion($ev->getProjecsolidentity()->getMotion()->multiply($ev->getForce())); + $ev->getProjectile()->setMotion($ev->getProjectile()->getMotion()->multiply($ev->getForce())); if($this->isSurvival()){ $this->inventory->removeItem(Item::get(Item::ARROW, $arrow->getDamage(), 1)); $bow->setDamage($bow->getDamage() + 1); @@ -2884,16 +2667,16 @@ public function handleDataPacket(DataPacket $packet){ $this->inventory->setItemInHand($bow); } } - if($ev->getProjecsolidentity() instanceof Projecsolidentity){ - $this->server->getPluginManager()->callEvent($projecsolidentityEv = new ProjecsolidentityLaunchEvent($ev->getProjecsolidentity())); - if($projecsolidentityEv->isCancelled()){ - $ev->getProjecsolidentity()->kill(); + if($ev->getProjectile() instanceof Projectile){ + $this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($ev->getProjectile())); + if($projectileEv->isCancelled()){ + $ev->getProjectile()->kill(); }else{ - $ev->getProjecsolidentity()->spawnToAll(); + $ev->getProjectile()->spawnToAll(); $this->level->addSound(new LaunchSound($this), $this->getViewers()); } }else{ - $ev->getProjecsolidentity()->spawnToAll(); + $ev->getProjectile()->spawnToAll(); } } } @@ -2926,7 +2709,7 @@ public function handleDataPacket(DataPacket $packet){ case PlayerActionPacket::ACTION_STOP_SLEEPING: $this->stopSleep(); break; - case PlayerActionPacket::ACTION_SPAWN_SAME_DIMENSION: + case PlayerActionPacket::ACTION_SPAWN_SAME_DIMENSION: case PlayerActionPacket::ACTION_SPAWN_OVERWORLD: if($this->isAlive() or !$this->isOnline()){ break; @@ -2937,33 +2720,30 @@ public function handleDataPacket(DataPacket $packet){ break; } - $this->craftingType = 0; - + $this->craftingType = self::CRAFTING_SMALL; + if($this->server->netherEnabled){ if($this->level == $this->server->netherLevel){ $this->teleport($pos = $this->server->getDefaultLevel()->getSafeSpawn()); } } - + $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $this->getSpawn())); $this->teleport($ev->getRespawnPosition()); $this->setSprinting(false); $this->setSneaking(false); + $this->setGliding(false); $this->extinguish(); - $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 300); + $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 400); $this->deadTicks = 0; $this->noDamageTicks = 60; $this->removeAllEffects(); $this->setHealth($this->getMaxHealth()); $this->setFood(20); - if($this->server->expEnabled){ - $this->updateExperience(); - } - $this->starvationTick = 0; $this->foodTick = 0; $this->foodUsageTime = 0; @@ -2987,7 +2767,7 @@ public function handleDataPacket(DataPacket $packet){ }else{ $this->setSprinting(true); } - break; + break 2; case PlayerActionPacket::ACTION_STOP_SPRINT: $ev = new PlayerToggleSprintEvent($this, false); $this->server->getPluginManager()->callEvent($ev); @@ -2996,7 +2776,7 @@ public function handleDataPacket(DataPacket $packet){ }else{ $this->setSprinting(false); } - break; + break 2; case PlayerActionPacket::ACTION_START_SNEAK: $ev = new PlayerToggleSneakEvent($this, true); $this->server->getPluginManager()->callEvent($ev); @@ -3005,7 +2785,7 @@ public function handleDataPacket(DataPacket $packet){ }else{ $this->setSneaking(true); } - break; + break 2; case PlayerActionPacket::ACTION_STOP_SNEAK: $ev = new PlayerToggleSneakEvent($this, false); $this->server->getPluginManager()->callEvent($ev); @@ -3014,7 +2794,27 @@ public function handleDataPacket(DataPacket $packet){ }else{ $this->setSneaking(false); } - break; + break 2; + case PlayerActionPacket::ACTION_START_GLIDE: + $ev = new PlayerToggleGlideEvent($this, true); + $this->server->getPluginManager()->callEvent($ev); + if($ev->isCancelled()){ + $this->sendData($this); + }else{ + $this->setGliding(true); + } + break 2; + case PlayerActionPacket::ACTION_STOP_GLIDE: + $ev = new PlayerToggleGlideEvent($this, false); + $this->server->getPluginManager()->callEvent($ev); + if($ev->isCancelled()){ + $this->sendData($this); + }else{ + $this->setGliding(false); + } + break 2; + case PlayerActionPacket::ACTION_JUMP: + break 2; } $this->startAction = -1; @@ -3025,17 +2825,11 @@ public function handleDataPacket(DataPacket $packet){ if($this->spawned === false or $this->blocked === true or !$this->isAlive()){ break; } - $this->craftingType = 0; + $this->craftingType = self::CRAFTING_SMALL; $vector = new Vector3($packet->x, $packet->y, $packet->z); - - if($this->isCreative()){ - $item = $this->inventory->getItemInHand(); - }else{ - $item = $this->inventory->getItemInHand(); - } - + $item = $this->inventory->getItemInHand(); $oldItem = clone $item; if($this->canInteract($vector->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 6) and $this->level->useBreakOn($vector, $item, $this, $this->server->destroyBlockParticle)){ @@ -3044,24 +2838,27 @@ public function handleDataPacket(DataPacket $packet){ $this->inventory->setItemInHand($item); $this->inventory->sendHeldItem($this); } + + $this->exhaust(0.025, PlayerExhaustEvent::CAUSE_MINING); } break; } $this->inventory->sendContents($this); $target = $this->level->getBlock($vector); - $solidentity = $this->level->getsolidentity($vector); + $tile = $this->level->getTile($vector); $this->level->sendBlocks([$this], [$target], UpdateBlockPacket::FLAG_ALL_PRIORITY); $this->inventory->sendHeldItem($this); - if($solidentity instanceof Spawnable){ - $solidentity->spawnTo($this); + if($tile instanceof Spawnable){ + $tile->spawnTo($this); } break; case ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET: + //This packet is ignored. Armour changes are also sent by ContainerSetSlotPackets, and are handled there instead. break; case ProtocolInfo::INTERACT_PACKET: @@ -3069,15 +2866,13 @@ public function handleDataPacket(DataPacket $packet){ break; } - $this->craftingType = 0; + $this->craftingType = self::CRAFTING_SMALL; $target = $this->level->getEntity($packet->target); $cancelled = false; - if($target instanceof Player and $this->server->getConfigBoolean("pvp", true) === false - - ){ + if($target instanceof Player and $this->server->getConfigBoolean("pvp", true) === false){ $cancelled = true; } @@ -3100,12 +2895,14 @@ public function handleDataPacket(DataPacket $packet){ //TODO: Feed } break; + }elseif($packet->action === InteractPacket::ACTION_MOUSEOVER){ + break; } if($target instanceof Entity and $this->getGamemode() !== Player::VIEW and $this->isAlive() and $target->isAlive()){ if($target instanceof DroppedItem or $target instanceof Arrow){ $this->kick("Attempting to attack an invalid entity"); - $this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("devmine.player.invalidEntity", [$this->getName()])); + $this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("DevMine.player.invalidEntity", [$this->getName()])); break; } @@ -3113,10 +2910,8 @@ public function handleDataPacket(DataPacket $packet){ $damage = [ EntityDamageEvent::MODIFIER_BASE => $item->getModifyAttackDamage($target), ]; - - if(!$this->canInteract($target, 8)){ - $cancelled = true; - }elseif($target instanceof Player){ + + if($target instanceof Player){ if(($target->getGamemode() & 0x01) > 0){ break; }elseif($this->server->getConfigBoolean("pvp") !== true or $this->server->getDifficulty() === 0){ @@ -3132,12 +2927,25 @@ public function handleDataPacket(DataPacket $packet){ if($target->attack($ev->getFinalDamage(), $ev) === true){ $fireAspectL = $item->getEnchantmentLevel(Enchantment::TYPE_WEAPON_FIRE_ASPECT); if($fireAspectL > 0){ - $fireEv = new EntityCombustByEntityEvent($this, $target, $fireAspectL * 4 - 1, $ev->getFireProtectL()); + $fireEv = new EntityCombustByEntityEvent($this, $target, $fireAspectL * 4, $ev->getFireProtectL()); Server::getInstance()->getPluginManager()->callEvent($fireEv); if(!$fireEv->isCancelled()){ $target->setOnFire($fireEv->getDuration()); } } + //Thorns + if($this->isSurvival()){ + $ev->createThornsDamage(); + if($ev->getThornsDamage() > 0){ + $thornsEvent = new EntityDamageByEntityEvent($target, $this, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $ev->getThornsDamage(), 0); + if(!$thornsEvent->isCancelled()){ + if($this->attack($thornsEvent->getFinalDamage(), $thornsEvent) === true){ + $thornsEvent->useArmors(); + $ev->setThornsArmorUse(); + } + } + } + } $ev->useArmors(); } @@ -3148,12 +2956,16 @@ public function handleDataPacket(DataPacket $packet){ break; } - if($item->isTool() and $this->isSurvival()){ - if($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()){ - $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1)); - }else{ - $this->inventory->setItemInHand($item); + if($this->isSurvival()){ + if($item->isTool()){ + if($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()){ + $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1)); + }else{ + $this->inventory->setItemInHand($item); + } } + + $this->exhaust(0.3, PlayerExhaustEvent::CAUSE_ATTACK); } } @@ -3180,13 +2992,26 @@ public function handleDataPacket(DataPacket $packet){ if($this->spawned === false or $this->blocked === true or !$this->isAlive()){ break; } - $this->craftingType = 0; + $this->craftingType = self::CRAFTING_SMALL; $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); //TODO: check if this should be true switch($packet->event){ - case 9: //Eating - $this->consumeHeldItem(); + case EntityEventPacket::USE_ITEM: //Eating + $slot = $this->inventory->getItemInHand(); + + if($slot->canBeConsumed()){ + $ev = new PlayerItemConsumeEvent($this, $slot); + if(!$slot->canBeConsumedBy($this)){ + $ev->setCancelled(); + } + $this->server->getPluginManager()->callEvent($ev); + if(!$ev->isCancelled()){ + $slot->onConsume($this); + }else{ + $this->inventory->sendContents($this); + } + } break; } break; @@ -3194,42 +3019,53 @@ public function handleDataPacket(DataPacket $packet){ if($this->spawned === false or $this->blocked === true or !$this->isAlive()){ break; } + if($packet->item->getId() === Item::AIR){ + /** + * This is so stupid it's unreal. + * Windows 10 Edition Beta drops the contents of the crafting grid when the inventory closes - including air. + */ + break; + } - if(!$this->inventory->contains($packet->item) or ($this->isCreative() and $this->server->limitedCreative)){ - $this->inventory->sendContents($this); + if(($this->isCreative() and $this->server->limitedCreative)){ break; } - $slot = $this->inventory->first($packet->item); - if($slot == -1){ - $this->inventory->sendContents($this); + $this->getTransactionQueue()->addTransaction(new DropItemTransaction($packet->item)); + break; + case ProtocolInfo::COMMAND_STEP_PACKET: + if($this->spawned === false or !$this->isAlive()){ break; } - $dropItem = $this->inventory->getItem($slot); - $ev = new PlayerDropItemEvent($this, $dropItem); - $this->server->getPluginManager()->callEvent($ev); + $this->craftingType = 0; + $commandText = $packet->command; + if($packet->args !== null){ + foreach($packet->args as $arg){ //command ordering will be an issue + $commandText .= " " . $arg; + } + } + $this->server->getPluginManager()->callEvent($ev = new PlayerCommandPreprocessEvent($this, "/" . $commandText)); if($ev->isCancelled()){ - $this->inventory->sendSlot($slot, $this); break; } - $this->inventory->remove($dropItem); - //$this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1)); - $motion = $this->getDirectionVector()->multiply(0.4); - - $this->level->dropItem($this->add(0, 1.3, 0), $dropItem, $motion, 40); - - $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); + Timings::$playerCommandTimer->startTiming(); + $this->server->dispatchCommand($ev->getPlayer(), substr($ev->getMessage(), 1)); + Timings::$playerCommandTimer->stopTiming(); break; case ProtocolInfo::TEXT_PACKET: if($this->spawned === false or !$this->isAlive()){ break; } - $this->craftingType = 0; + $this->craftingType = self::CRAFTING_SMALL; if($packet->type === TextPacket::TYPE_CHAT){ $packet->message = TextFormat::clean($packet->message, $this->removeFormat); foreach(explode("\n", $packet->message) as $message){ if(trim($message) != "" and strlen($message) <= 255 and $this->messageCounter-- > 0){ + if(substr($message, 0, 2) === "./"){ //Command (./ = fast hack for old plugins post 0.16) + $message = substr($message, 1); + } + $ev = new PlayerCommandPreprocessEvent($this, $message); if(mb_strlen($ev->getMessage(), "UTF-8") > 320){ @@ -3240,7 +3076,7 @@ public function handleDataPacket(DataPacket $packet){ if($ev->isCancelled()){ break; } - if(substr($ev->getMessage(), 0, 1) === "/"){ //Command + if(substr($ev->getMessage(), 0, 1) === "/"){ Timings::$playerCommandTimer->startTiming(); $this->server->dispatchCommand($ev->getPlayer(), substr($ev->getMessage(), 1)); Timings::$playerCommandTimer->stopTiming(); @@ -3261,34 +3097,74 @@ public function handleDataPacket(DataPacket $packet){ if($this->spawned === false or $packet->windowid === 0){ break; } - $this->craftingType = 0; - $this->currentTransaction = null; + $this->craftingType = self::CRAFTING_SMALL; if(isset($this->windowIndex[$packet->windowid])){ - if($this->windowIndex[$packet->windowid] instanceof AnvilInventory){ - $this->anvilItem = null; - } $this->server->getPluginManager()->callEvent(new InventoryCloseEvent($this->windowIndex[$packet->windowid], $this)); $this->removeWindow($this->windowIndex[$packet->windowid]); - }else{ - unset($this->windowIndex[$packet->windowid]); + } + + /** + * Drop anything still left in the crafting inventory + * This will usually never be needed since Windows 10 clients will send DropItemPackets + * which will cause this to happen anyway, but this is here for when transactions + * fail and items end up stuck in the crafting inventory. + */ + foreach($this->getFloatingInventory()->getContents() as $item){ + $this->getTransactionQueue()->addTransaction(new DropItemTransaction($item)); } break; case ProtocolInfo::CRAFTING_EVENT_PACKET: if($this->spawned === false or !$this->isAlive()){ break; - }elseif(!isset($this->windowIndex[$packet->windowId])){ + } + /** + * For some annoying reason, anvils send window ID 255 when crafting with them instead of the _actual_ anvil window ID + * The result of this is anvils immediately closing when used. This is highly unusual, especially since the + * container set slot packets send the correct window ID, but... eh + */ + /*elseif(!isset($this->windowIndex[$packet->windowId])){ $this->inventory->sendContents($this); $pk = new ContainerClosePacket(); $pk->windowid = $packet->windowId; $this->dataPacket($pk); break; - } + }*/ $recipe = $this->server->getCraftingManager()->getRecipe($packet->id); + if($this->craftingType === self::CRAFTING_ANVIL){ + $anvilInventory = $this->windowIndex[$packet->windowId] ?? null; + if($anvilInventory === null){ + foreach($this->windowIndex as $window){ + if($window instanceof AnvilInventory){ + $anvilInventory = $window; + break; + } + } + if($anvilInventory === null){ //If it's _still_ null, then the player doesn't have a valid anvil window, cannot proceed. + $this->getServer()->getLogger()->debug("Couldn't find an anvil window for ".$this->getName().", exiting"); + $this->inventory->sendContents($this); + break; + } + } - if($recipe === null or (($recipe instanceof BigShapelessRecipe or $recipe instanceof BigShapedRecipe) and $this->craftingType === 0)){ + if($recipe === null){ + //Item renamed + if(!$anvilInventory->onRename($this, $packet->output[0])){ + $this->getServer()->getLogger()->debug($this->getName()." failed to rename an item in an anvil"); + $this->inventory->sendContents($this); + } + }else{ + //TODO: Anvil crafting recipes + } + break; + }elseif(($recipe instanceof BigShapelessRecipe or $recipe instanceof BigShapedRecipe) and $this->craftingType === 0){ + $this->server->getLogger()->debug("Received big crafting recipe from ".$this->getName()." with no crafting table open"); + $this->inventory->sendContents($this); + break; + }elseif($recipe === null){ + $this->server->getLogger()->debug("Null (unknown) crafting recipe received from ".$this->getName()." for ".$packet->output[0]); $this->inventory->sendContents($this); break; } @@ -3299,131 +3175,192 @@ public function handleDataPacket(DataPacket $packet){ $item->setDamage(null); } - if($i < 9 and $item->getId() > 0){ + if($i < 9 and $item->getId() > 0){ //TODO: Get rid of this hack. $item->setCount(1); } } $canCraft = true; - - if($recipe instanceof ShapedRecipe){ - for($x = 0; $x < 3 and $canCraft; ++$x){ - for($y = 0; $y < 3; ++$y){ - $item = $packet->input[$y * 3 + $x]; - $ingredient = $recipe->getIngredient($x, $y); - if($item->getCount() > 0 and $item->getId() > 0){ - if($ingredient == null){ - $canCraft = false; - break; - } - if($ingredient->getId() != 0 and !$ingredient->deepEquals($item, $ingredient->getDamage() !== null, $ingredient->getCompoundTag() !== null)){ - $canCraft = false; - break; - } - - }elseif($ingredient !== null and $item->getId() !== 0){ + if(count($packet->input) === 0){ + /* If the packet "input" field is empty this needs to be handled differently. + * "input" is used to tell the server what items to remove from the client's inventory + * Because crafting takes the materials in the crafting grid, nothing needs to be taken from the inventory + * Instead, we take the materials from the crafting inventory + * To know what materials we need to take, we have to guess the crafting recipe used based on the + * output item and the materials stored in the crafting items + * The reason we have to guess is because Win10 sometimes sends a different recipe UUID + * say, if you put the wood for a door in the right hand side of the crafting grid instead of the left + * it will send the recipe UUID for a wooden pressure plate. Unknown currently whether this is a client + * bug or if there is something wrong with the way the server handles recipes. + * TODO: Remove recipe correction and fix desktop crafting recipes properly. + * In fact, TODO: Rewrite crafting entirely. + */ + $possibleRecipes = $this->server->getCraftingManager()->getRecipesByResult($packet->output[0]); + if(!$packet->output[0]->deepEquals($recipe->getResult())){ + $this->server->getLogger()->debug("Mismatched desktop recipe received from player ".$this->getName().", expected ".$recipe->getResult().", got ".$packet->output[0]); + } + $recipe = null; + foreach($possibleRecipes as $r){ + /* Check the ingredient list and see if it matches the ingredients we've put into the crafting grid + * As soon as we find a recipe that we have all the ingredients for, take it and run with it. */ + + //Make a copy of the floating inventory that we can make changes to. + $floatingInventory = clone $this->floatingInventory; + $ingredients = $r->getIngredientList(); + + //Check we have all the necessary ingredients. + foreach($ingredients as $ingredient){ + if(!$floatingInventory->contains($ingredient)){ + //We're short on ingredients, try the next recipe $canCraft = false; break; } + //This will only be reached if we have the item to take away. + $floatingInventory->removeItem($ingredient); + } + if($canCraft){ + //Found a recipe that works, take it and run with it. + $recipe = $r; + break; } } - }elseif($recipe instanceof ShapelessRecipe){ - $needed = $recipe->getIngredientList(); - for($x = 0; $x < 3 and $canCraft; ++$x){ - for($y = 0; $y < 3; ++$y){ - $item = clone $packet->input[$y * 3 + $x]; + if($recipe !== null){ + $this->server->getPluginManager()->callEvent($ev = new CraftItemEvent($this, $ingredients, $recipe)); - foreach($needed as $k => $n){ - if($n->deepEquals($item, $n->getDamage() !== null, $n->getCompoundTag() !== null)){ - $remove = min($n->getCount(), $item->getCount()); - $n->setCount($n->getCount() - $remove); - $item->setCount($item->getCount() - $remove); + if($ev->isCancelled()){ + $this->inventory->sendContents($this); + break; + } - if($n->getCount() === 0){ - unset($needed[$k]); + $this->floatingInventory = $floatingInventory; //Set player crafting inv to the idea one created in this process + $this->floatingInventory->addItem(clone $recipe->getResult()); //Add the result to our picture of the crafting inventory + }else{ + $this->server->getLogger()->debug("Unmatched desktop crafting recipe " . $packet->id . " from player " . $this->getName()); + $this->inventory->sendContents($this); + break; + } + }else{ + if($recipe instanceof ShapedRecipe){ + for($x = 0; $x < 3 and $canCraft; ++$x){ + for($y = 0; $y < 3; ++$y){ + $item = $packet->input[$y * 3 + $x]; + $ingredient = $recipe->getIngredient($x, $y); + if($item->getCount() > 0 and $item->getId() > 0){ + if($ingredient == null){ + $canCraft = false; + break; + } + if($ingredient->getId() != 0 and !$ingredient->deepEquals($item, $ingredient->getDamage() !== null, $ingredient->getCompoundTag() !== null)){ + $canCraft = false; + break; } + + }elseif($ingredient !== null and $item->getId() !== 0){ + $canCraft = false; + break; } } + } + }elseif($recipe instanceof ShapelessRecipe){ + $needed = $recipe->getIngredientList(); - if($item->getCount() > 0){ - $canCraft = false; - break; + for($x = 0; $x < 3 and $canCraft; ++$x){ + for($y = 0; $y < 3; ++$y){ + $item = clone $packet->input[$y * 3 + $x]; + + foreach($needed as $k => $n){ + if($n->deepEquals($item, $n->getDamage() !== null, $n->getCompoundTag() !== null)){ + $remove = min($n->getCount(), $item->getCount()); + $n->setCount($n->getCount() - $remove); + $item->setCount($item->getCount() - $remove); + + if($n->getCount() === 0){ + unset($needed[$k]); + } + } + } + + if($item->getCount() > 0){ + $canCraft = false; + break; + } } } - } - - if(count($needed) > 0){ + if(count($needed) > 0){ + $canCraft = false; + } + }else{ $canCraft = false; } - }else{ - $canCraft = false; - } - /** @var Item[] $ingredients */ - $canCraft = true;//0.13.1大量物品本地配方出现问题,无法解决,使用极端(唯一)方法修复. - $ingredients = $packet->input; - $result = $packet->output[0]; + //Nasty hack. TODO: Get rid + $canCraft = true;//0.13.1 - if(!$canCraft or !$recipe->getResult()->deepEquals($result)){ - $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": expected " . $recipe->getResult() . ", got " . $result . ", using: " . implode(", ", $ingredients)); - $this->inventory->sendContents($this); - break; - } + /** @var Item[] $ingredients */ + $ingredients = $packet->input; + $result = $packet->output[0]; + + if(!$canCraft or !$recipe->getResult()->deepEquals($result)){ + $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": expected " . $recipe->getResult() . ", got " . $result . ", using: " . implode(", ", $ingredients)); + $this->inventory->sendContents($this); + break; + } - $used = array_fill(0, $this->inventory->getSize(), 0); + $used = array_fill(0, $this->inventory->getSize(), 0); - foreach($ingredients as $ingredient){ - $slot = -1; - foreach($this->inventory->getContents() as $index => $i){ - if($ingredient->getId() !== 0 and $ingredient->deepEquals($i, $ingredient->getDamage() !== null) and ($i->getCount() - $used[$index]) >= 1){ - $slot = $index; - $used[$index]++; + foreach($ingredients as $ingredient){ + $slot = -1; + foreach($this->inventory->getContents() as $index => $i){ + if($ingredient->getId() !== 0 and $ingredient->deepEquals($i, $ingredient->getDamage() !== null) and ($i->getCount() - $used[$index]) >= 1){ + $slot = $index; + $used[$index]++; + break; + } + } + + if($ingredient->getId() !== 0 and $slot === -1){ + $canCraft = false; break; } } - if($ingredient->getId() !== 0 and $slot === -1){ - $canCraft = false; + if(!$canCraft){ + $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": client does not have enough items, using: " . implode(", ", $ingredients)); + $this->inventory->sendContents($this); break; } - } - if(!$canCraft){ - $this->server->getLogger()->debug("Unmatched recipe " . $recipe->getId() . " from player " . $this->getName() . ": client does not have enough items, using: " . implode(", ", $ingredients)); - $this->inventory->sendContents($this); - break; - } + $this->server->getPluginManager()->callEvent($ev = new CraftItemEvent($this, $ingredients, $recipe)); - $this->server->getPluginManager()->callEvent($ev = new CraftItemEvent($this, $ingredients, $recipe)); + if($ev->isCancelled()){ + $this->inventory->sendContents($this); + break; + } - if($ev->isCancelled()){ - $this->inventory->sendContents($this); - break; - } + foreach($used as $slot => $count){ + if($count === 0){ + continue; + } - foreach($used as $slot => $count){ - if($count === 0){ - continue; - } + $item = $this->inventory->getItem($slot); - $item = $this->inventory->getItem($slot); + if($item->getCount() > $count){ + $newItem = clone $item; + $newItem->setCount($item->getCount() - $count); + }else{ + $newItem = Item::get(Item::AIR, 0, 0); + } - if($item->getCount() > $count){ - $newItem = clone $item; - $newItem->setCount($item->getCount() - $count); - }else{ - $newItem = Item::get(Item::AIR, 0, 0); + $this->inventory->setItem($slot, $newItem); } - $this->inventory->setItem($slot, $newItem); - } - - $extraItem = $this->inventory->addItem($recipe->getResult()); - if(count($extraItem) > 0){ - foreach($extraItem as $item){ - $this->level->dropItem($this, $item); + $extraItem = $this->inventory->addItem($recipe->getResult()); + if(count($extraItem) > 0 and !$this->isCreative()){ //Could not add all the items to our inventory (not enough space) + foreach($extraItem as $item){ + $this->level->dropItem($this, $item); + } } } @@ -3477,136 +3414,64 @@ public function handleDataPacket(DataPacket $packet){ if($packet->slot >= $this->inventory->getSize()){ break; } - if($this->isCreative()){ - if(Item::getCreativeItemIndex($packet->item) !== -1){ - $this->inventory->setItem($packet->slot, $packet->item); - $this->inventory->setHotbarSlotIndex($packet->slot, $packet->slot); //links $hotbar[$packet->slot] to $slots[$packet->slot] - } - } - $transaction = new BaseTransaction($this->inventory, $packet->slot, $this->inventory->getItem($packet->slot), $packet->item); + $transaction = new BaseTransaction($this->inventory, $packet->slot, $packet->item); }elseif($packet->windowid === ContainerSetContentPacket::SPECIAL_ARMOR){ //Our armor if($packet->slot >= 4){ break; } - $transaction = new BaseTransaction($this->inventory, $packet->slot + $this->inventory->getSize(), $this->inventory->getArmorItem($packet->slot), $packet->item); + $transaction = new BaseTransaction($this->inventory, $packet->slot + $this->inventory->getSize(), $packet->item); }elseif(isset($this->windowIndex[$packet->windowid])){ - $this->craftingType = 0; + //Transaction for non-player-inventory window, such as anvil, chest, etc. + $inv = $this->windowIndex[$packet->windowid]; + $achievements = []; - /** @var $packet \devmine\server\network\protocol\ContainerSetSlotPacket */ - if($inv instanceof EnchantInventory and $packet->item->hasEnchantments()){ - $inv->onEnchant($this, $inv->getItem($packet->slot), $packet->item); - } + if($inv instanceof FurnaceInventory and $inv->getItem($packet->slot)->getId() === Item::IRON_INGOT and $packet->slot === FurnaceInventory::RESULT){ + $achievements[] = "acquireIron"; - if($inv instanceof AnvilInventory){ - if($packet->slot == 2){ - if($packet->item->getId() != Item::AIR){ - $this->anvilItem = $packet->item; - }elseif($this->anvilItem != null){ - if(!$inv->onRename($this->anvilItem, $this)){ - break; //maybe cheating! - } - $this->anvilItem = null; - } - } + }elseif($inv instanceof EnchantInventory and $packet->item->hasEnchantments()){ + $inv->onEnchant($this, $inv->getItem($packet->slot), $packet->item); } - $transaction = new BaseTransaction($inv, $packet->slot, $inv->getItem($packet->slot), $packet->item); + $transaction = new BaseTransaction($inv, $packet->slot, $packet->item, $achievements); }else{ + //Client sent a transaction for a window which the server doesn't think they have open break; } - if($transaction->getSourceItem()->deepEquals($transaction->getTargetItem()) and $transaction->getTargetItem()->getCount() === $transaction->getSourceItem()->getCount()){ //No changes! - //No changes, just a local inventory update sent by the server - break; - } - + $this->getTransactionQueue()->addTransaction($transaction); - if($this->currentTransaction === null or $this->currentTransaction->getCreationTime() < (microtime(true) - 8)){ - if($this->currentTransaction !== null){ - foreach($this->currentTransaction->getInventories() as $inventory){ - if($inventory instanceof PlayerInventory){ - $inventory->sendArmorContents($this); - } - $inventory->sendContents($this); - } - } - $this->currentTransaction = new SimpleTransactionGroup($this); - } - - $this->currentTransaction->addTransaction($transaction); - - if($this->currentTransaction->canExecute()){ - $achievements = []; - foreach($this->currentTransaction->getTransactions() as $ts){ - $inv = $ts->getInventory(); - if($inv instanceof FurnaceInventory){ - if($ts->getSlot() === 2){ - switch($inv->getResult()->getId()){ - case Item::IRON_INGOT: - $achievements[] = "acquireIron"; - break; - } - } - } - } - - if($this->currentTransaction->execute()){ - foreach($achievements as $a){ - $this->awardAchievement($a); - } - } - - $this->currentTransaction = null; - } break; case ProtocolInfo::BLOCK_ENTITY_DATA_PACKET: if($this->spawned === false or $this->blocked === true or !$this->isAlive()){ break; } - $this->craftingType = 0; + $this->craftingType = self::CRAFTING_SMALL; $pos = new Vector3($packet->x, $packet->y, $packet->z); if($pos->distanceSquared($this) > 10000){ break; } - $t = $this->level->getsolidentity($pos); - if($t instanceof Sign){ + $t = $this->level->getTile($pos); + if($t instanceof Spawnable){ $nbt = new NBT(NBT::LITTLE_ENDIAN); - $nbt->read($packet->namedtag); + $nbt->read($packet->namedtag, false, true); $nbt = $nbt->getData(); - if($nbt["id"] !== solidentity::SIGN){ + if(!$t->updateCompoundTag($nbt, $this)){ $t->spawnTo($this); - }else{ - $ev = new SignChangeEvent($t->getBlock(), $this, [ - TextFormat::clean($nbt["Text1"], $this->removeFormat), - TextFormat::clean($nbt["Text2"], $this->removeFormat), - TextFormat::clean($nbt["Text3"], $this->removeFormat), - TextFormat::clean($nbt["Text4"], $this->removeFormat) - ]); - - if(!isset($t->namedtag->Creator) or $t->namedtag["Creator"] !== $this->getRawUniqueId()){ - $ev->setCancelled(); - }else{ - foreach($ev->getLines() as $line){ - if(mb_strlen($line, "UTF-8") > 16){ - $ev->setCancelled(); - } - } - } - - $this->server->getPluginManager()->callEvent($ev); - - if(!$ev->isCancelled()){ - $t->setText($ev->getLine(0), $ev->getLine(1), $ev->getLine(2), $ev->getLine(3)); - }else{ - $t->spawnTo($this); - } } } break; + case ProtocolInfo::SET_PLAYER_GAME_TYPE_PACKET: + if($packet->gamemode !== ($this->gamemode & 0x01)){ + $pk = new SetPlayerGameTypePacket(); + $pk->gamemode = $this->gamemode & 0x01; + $this->dataPacket($pk); + $this->sendSettings(); + } + break; default: break; } @@ -3642,6 +3507,41 @@ public function kick($reason = "", $isAdmin = true){ return false; } + /** + * @param Item $item + * + * Drops the specified item in front of the player. + */ + public function dropItem(Item $item){ + if($this->spawned === false or $this->blocked === true or !$this->isAlive()){ + return; + } + + if(($this->isCreative() and $this->server->limitedCreative) or $this->isSpectator()){ + //Ignore for limited creative + return; + } + + if($item->getId() === Item::AIR or $item->getCount() < 1){ + //Ignore dropping air or items with bad counts + return; + } + + $ev = new PlayerDropItemEvent($this, $item); + $this->server->getPluginManager()->callEvent($ev); + if($ev->isCancelled()){ + $this->getFloatingInventory()->removeItem($item); + $this->getInventory()->addItem($item); + return; + } + + $motion = $this->getDirectionVector()->multiply(0.4); + + $this->level->dropItem($this->add(0, 1.3, 0), $item, $motion, 40); + + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); + } + /** * Sends a direct chat message to a player * @@ -3682,9 +3582,9 @@ public function sendTranslation($message, array $parameters = []){ $pk = new TextPacket(); if(!$this->server->isLanguageForced()){ $pk->type = TextPacket::TYPE_TRANSLATION; - $pk->message = $this->server->getLanguage()->translateString($message, $parameters, "devmine."); + $pk->message = $this->server->getLanguage()->translateString($message, $parameters, "DevMine."); foreach($parameters as $i => $p){ - $parameters[$i] = $this->server->getLanguage()->translateString($p, $parameters, "devmine."); + $parameters[$i] = $this->server->getLanguage()->translateString($p, $parameters, "DevMine."); } $pk->parameters = $parameters; }else{ @@ -3707,7 +3607,7 @@ public function sendPopup($message, $subtitle = ""){ if(!$ev->isCancelled()){ $pk = new TextPacket(); $pk->type = TextPacket::TYPE_POPUP; - $pk->source = $message; + $pk->source = $ev->getMessage(); $pk->message = $subtitle; $this->dataPacket($pk); return true; @@ -3725,7 +3625,7 @@ public function sendTip($message){ if(!$ev->isCancelled()){ $pk = new TextPacket(); $pk->type = TextPacket::TYPE_TIP; - $pk->message = $message; + $pk->message = $ev->getMessage(); $this->dataPacket($pk); return true; } @@ -3741,7 +3641,6 @@ public function sendTip($message){ * @param bool $notify */ public final function close($message = "", $reason = "generic reason", $notify = true){ - if($this->connected and !$this->closed){ if($notify and strlen((string) $reason) > 0){ $pk = new DisconnectPacket; @@ -3801,7 +3700,7 @@ public final function close($message = "", $reason = "generic reason", $notify = $this->server->getPluginManager()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this); $this->spawned = false; - $this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("devmine.player.logOut", [ + $this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("DevMine.player.logOut", [ TextFormat::AQUA . $this->getName() . TextFormat::WHITE, $this->ip, $this->port, @@ -3823,10 +3722,8 @@ public final function close($message = "", $reason = "generic reason", $notify = $this->perm = null; } - if($this->inventory !== null){ - $this->inventory = null; - $this->currentTransaction = null; - } + $this->inventory = null; + $this->transactionQueue = null; $this->chunk = null; @@ -3847,9 +3744,9 @@ public function save($async = false){ parent::saveNBT(); if($this->level instanceof Level){ - $this->namedtag->Level = new StringTag("Level", $this->level->getName()); - if($this->spawnPosition instanceof Position and $this->spawnPosition->getLevel() instanceof Level and $this->spawnPosition->getLevel()->getProvider() !== NULL){ - $this->namedtag["SpawnLevel"] = $this->spawnPosition->getLevel()->getName(); + $this->namedtag->Level = new StringTag("Level", $this->level->getFolderName()); + if($this->hasValidSpawnPosition()){ + $this->namedtag["SpawnLevel"] = $this->spawnPosition->getLevel()->getFolderName(); $this->namedtag["SpawnX"] = (int) $this->spawnPosition->x; $this->namedtag["SpawnY"] = (int) $this->spawnPosition->y; $this->namedtag["SpawnZ"] = (int) $this->spawnPosition->z; @@ -3912,7 +3809,7 @@ public function kill(){ } } break; - case EntityDamageEvent::CAUSE_PROJECsolidentity: + case EntityDamageEvent::CAUSE_PROJECTILE: if($cause instanceof EntityDamageByEntityEvent){ $e = $cause->getDamager(); if($e instanceof Player){ @@ -4001,9 +3898,12 @@ public function kill(){ Entity::kill(); - $this->server->getPluginManager()->callEvent($ev = new PlayerDeathEvent($this, $this->getDrops(), new TranslationContainer($message, $params))); + $ev = new PlayerDeathEvent($this, $this->getDrops(), new TranslationContainer($message, $params)); + $ev->setKeepInventory($this->server->keepInventory); + $ev->setKeepExperience($this->server->keepExperience); + $this->server->getPluginManager()->callEvent($ev); - if(!$ev->getKeepInventory() and !$this->server->keepInventory){ + if(!$ev->getKeepInventory()){ foreach($ev->getDrops() as $item){ $this->level->dropItem($this, $item); } @@ -4013,11 +3913,10 @@ public function kill(){ } } - if($this->server->expEnabled and (!$ev->getKeepExperience() and !$this->server->keepInventory)){ - $exp = $this->getExp(); - if($exp > 100) $exp = 100; + if($this->server->expEnabled and !$ev->getKeepExperience()){ + $exp = min(91, $this->getTotalXp()); //Max 7 levels of exp dropped $this->getLevel()->spawnXPOrb($this->add(0, 0.2, 0), $exp); - $this->setExperienceAndLevel(0, 0); + $this->setTotalXp(0, true); } if($ev->getDeathMessage() != ""){ @@ -4025,7 +3924,7 @@ public function kill(){ } $pos = $this->getSpawn(); - + $this->setHealth(0); $pk = new RespawnPacket(); @@ -4043,94 +3942,16 @@ public function setHealth($amount){ } } - protected $movementSpeed = 0.1; - - /** - * Set movement speed to the player - * - * @param $amount - */ - public function setMovementSpeed($amount){ - $this->movementSpeed = $amount; - $this->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED)->setValue($amount); - } - - /** - * Get movement speed of the player - * - * @return float - */ - public function getMovementSpeed(){ - return $this->movementSpeed; - } - - protected $food = 20; - - protected $foodDepletion = 0; - - protected $foodEnabled = true; - - public function setFoodEnabled($enabled){ - $this->foodEnabled = $enabled; - } - - public function getFoodEnabled(){ - return $this->foodEnabled; - } - - public function setFood(float $amount){ - if(!$this->server->foodEnabled){ - $amount = 20; - } - $amount = min(20, max(0, $amount)); - $this->server->getPluginManager()->callEvent($ev = new PlayerHungerChangeEvent($this, $amount)); - - if($ev->isCancelled()) return false; - - $amount = $ev->getData(); - - if($amount <= 6 && !($this->getFood() <= 6)){ - $this->setDataProperty(self::DATA_FLAG_SPRINTING, self::DATA_TYPE_BYTE, false); - }elseif($amount > 6 && !($this->getFood() > 6)){ - $this->setDataProperty(self::DATA_FLAG_SPRINTING, self::DATA_TYPE_BYTE, true); - } - - $this->food = $amount; - if($this->getAttributeMap() instanceof AttributeMap){ - $this->getAttributeMap()->getAttribute(Attribute::HUNGER)->setValue($amount); - }else{ - //Sometimes this function is called before the attribute map is initialized, causing a crash. Not sure how that is even possible. Maybe a plugin? - } - - return true; - } - - public function getFood() : float{ - return $this->food; - } - - public function subtractFood($amount){ - if($this->getFood() - $amount <= 6 && !($this->getFood() <= 6)){ - $this->setDataProperty(self::DATA_FLAG_SPRINTING, self::DATA_TYPE_BYTE, false); - //$this->removeEffect(Effect::SLOWNESS); - }elseif($this->getFood() - $amount < 6 && !($this->getFood() > 6)){ - $this->setDataProperty(self::DATA_FLAG_SPRINTING, self::DATA_TYPE_BYTE, true); - /*$effect = Effect::getEffect(Effect::SLOWNESS); - $effect->setDuration(0x7fffffff); - $effect->setAmplifier(2); - $effect->setVisible(false); - $this->addEffect($effect);*/ - } - if($this->food - $amount < 0) return; - $this->setFood($this->getFood() - $amount); - } - public function attack($damage, EntityDamageEvent $source){ if(!$this->isAlive()){ - return false; + return; } - if($this->isCreative() and $source->getCause() !== EntityDamageEvent::CAUSE_SUICIDE and $source->getCause() !== EntityDamageEvent::CAUSE_VOID){ + if($this->isCreative() + and $source->getCause() !== EntityDamageEvent::CAUSE_MAGIC + and $source->getCause() !== EntityDamageEvent::CAUSE_SUICIDE + and $source->getCause() !== EntityDamageEvent::CAUSE_VOID + ){ $source->setCancelled(); }elseif($this->allowFlight and $source->getCause() === EntityDamageEvent::CAUSE_FALL){ $source->setCancelled(); @@ -4139,12 +3960,16 @@ public function attack($damage, EntityDamageEvent $source){ parent::attack($damage, $source); if($source->isCancelled()){ - return false; + return; }elseif($this->getLastDamageCause() === $source and $this->spawned){ $pk = new EntityEventPacket(); $pk->eid = 0; $pk->event = EntityEventPacket::HURT_ANIMATION; $this->dataPacket($pk); + + if($this->isSurvival()){ + $this->exhaust(0.3, PlayerExhaustEvent::CAUSE_DAMAGE); + } } return true; } @@ -4264,6 +4089,7 @@ public function teleport(Vector3 $pos, $yaw = null, $pitch = null){ $this->resetFallDistance(); $this->nextChunkOrderRun = 0; $this->newPosition = null; + $this->stopSleep(); return true; } return false; @@ -4320,7 +4146,7 @@ public function getWindowId(Inventory $inventory) : int{ * * @return int */ - public function addWindow(Inventory $inventory, int $forceId = null) : int{ + public function addWindow(Inventory $inventory, $forceId = null) : int{ if($this->windows->contains($inventory)){ return $this->windows[$inventory]; } @@ -4350,36 +4176,36 @@ public function removeWindow(Inventory $inventory){ } } - public function setepilogos($epilogosKey, epilogosValue $epilogosValue){ - $this->server->getPlayerepilogos()->setepilogos($this, $epilogosKey, $epilogosValue); + public function setMetadata($metadataKey, MetadataValue $metadataValue){ + $this->server->getPlayerMetadata()->setMetadata($this, $metadataKey, $metadataValue); } - public function getepilogos($epilogosKey){ - return $this->server->getPlayerepilogos()->getepilogos($this, $epilogosKey); + public function getMetadata($metadataKey){ + return $this->server->getPlayerMetadata()->getMetadata($this, $metadataKey); } - public function hasepilogos($epilogosKey){ - return $this->server->getPlayerepilogos()->hasepilogos($this, $epilogosKey); + public function hasMetadata($metadataKey){ + return $this->server->getPlayerMetadata()->hasMetadata($this, $metadataKey); } - public function removeepilogos($epilogosKey, Plugin $plugin){ - $this->server->getPlayerepilogos()->removeepilogos($this, $epilogosKey, $plugin); + public function removeMetadata($metadataKey, Plugin $plugin){ + $this->server->getPlayerMetadata()->removeMetadata($this, $metadataKey, $plugin); } - public function onChunkChanged(FullChunk $chunk){ + public function onChunkChanged(Chunk $chunk){ $this->loadQueue[Level::chunkHash($chunk->getX(), $chunk->getZ())] = abs(($this->x >> 4) - $chunk->getX()) + abs(($this->z >> 4) - $chunk->getZ()); } - public function onChunkLoaded(FullChunk $chunk){ + public function onChunkLoaded(Chunk $chunk){ } - public function onChunkPopulated(FullChunk $chunk){ + public function onChunkPopulated(Chunk $chunk){ } - public function onChunkUnloaded(FullChunk $chunk){ + public function onChunkUnloaded(Chunk $chunk){ } @@ -4399,19 +4225,17 @@ public function isLoaderActive(){ * @param $chunkX * @param $chunkZ * @param $payload - * @param int $ordering * @return BatchPacket|FullChunkDataPacket */ - public static function getChunkCacheFromData($chunkX, $chunkZ, $payload, $ordering = FullChunkDataPacket::ORDER_COLUMNS){ + public static function getChunkCacheFromData($chunkX, $chunkZ, $payload){ $pk = new FullChunkDataPacket(); $pk->chunkX = $chunkX; $pk->chunkZ = $chunkZ; - $pk->order = $ordering; $pk->data = $payload; if(Network::$BATCH_THRESHOLD >= 0){ $pk->encode(); $batch = new BatchPacket(); - $batch->payload = zlib_encode(Binary::writeInt(strlen($pk->getBuffer())) . $pk->getBuffer(), ZLIB_ENCODING_DEFLATE, Server::getInstance()->networkCompressionLevel); + $batch->payload = zlib_encode(Binary::writeUnsignedVarInt(strlen($pk->getBuffer())) . $pk->getBuffer(), ZLIB_ENCODING_DEFLATE, Server::getInstance()->networkCompressionLevel); $batch->encode(); $batch->isEncoded = true; return $batch; @@ -4419,5 +4243,14 @@ public static function getChunkCacheFromData($chunkX, $chunkZ, $payload, $orderi return $pk; } + /** + * @param Effect + */ + public function addEffect(Effect $effect){//Overwrite + if($effect->isBad() && $this->isCreative()){ + return; + } + parent::addEffect($effect); + } } diff --git a/src/devmine/creatures/player/tag/ByteArrayTag.php b/src/devmine/creatures/player/tag/ByteArrayTag.php index 13dae0d..b550d8f 100644 --- a/src/devmine/creatures/player/tag/ByteArrayTag.php +++ b/src/devmine/creatures/player/tag/ByteArrayTag.php @@ -14,12 +14,12 @@ public function getType(){ return NBT::TAG_ByteArray; } - public function read(NBT $nbt){ - $this->value = $nbt->get($nbt->getInt()); + public function read(NBT $nbt, bool $network = false){ + $this->value = $nbt->get($nbt->getInt($network)); } - public function write(NBT $nbt){ - $nbt->putInt(strlen($this->value)); + public function write(NBT $nbt, bool $network = false){ + $nbt->putInt(strlen($this->value), $network); $nbt->put($this->value); } } \ No newline at end of file diff --git a/src/devmine/creatures/player/tag/ByteTag.php b/src/devmine/creatures/player/tag/ByteTag.php index cecf207..0aafd46 100644 --- a/src/devmine/creatures/player/tag/ByteTag.php +++ b/src/devmine/creatures/player/tag/ByteTag.php @@ -14,11 +14,11 @@ public function getType(){ return NBT::TAG_Byte; } - public function read(NBT $nbt){ + public function read(NBT $nbt, bool $network = false){ $this->value = $nbt->getByte(); } - public function write(NBT $nbt){ + public function write(NBT $nbt, bool $network = false){ $nbt->putByte($this->value); } } \ No newline at end of file diff --git a/src/devmine/creatures/player/tag/CompoundTag.php b/src/devmine/creatures/player/tag/CompoundTag.php index 6f3a845..009fa2a 100644 --- a/src/devmine/creatures/player/tag/CompoundTag.php +++ b/src/devmine/creatures/player/tag/CompoundTag.php @@ -64,23 +64,24 @@ public function getType(){ return NBT::TAG_Compound; } - public function read(NBT $nbt){ + public function read(NBT $nbt, bool $network = false){ $this->value = []; do{ - $tag = $nbt->readTag(); + $tag = $nbt->readTag($network); if($tag instanceof NamedTag and $tag->getName() !== ""){ $this->{$tag->getName()} = $tag; } }while(!($tag instanceof EndTag) and !$nbt->feof()); } - public function write(NBT $nbt){ + public function write(NBT $nbt, bool $network = false){ foreach($this as $tag){ if($tag instanceof Tag and !($tag instanceof EndTag)){ - $nbt->writeTag($tag); + $nbt->writeTag($tag, $network); } } - $nbt->writeTag(new EndTag()); + + $nbt->writeTag(new EndTag, $network); } public function __toString(){ diff --git a/src/devmine/creatures/player/tag/DoubleTag.php b/src/devmine/creatures/player/tag/DoubleTag.php index f78d9c1..66a7b20 100644 --- a/src/devmine/creatures/player/tag/DoubleTag.php +++ b/src/devmine/creatures/player/tag/DoubleTag.php @@ -14,11 +14,11 @@ public function getType(){ return NBT::TAG_Double; } - public function read(NBT $nbt){ + public function read(NBT $nbt, bool $network = false){ $this->value = $nbt->getDouble(); } - public function write(NBT $nbt){ + public function write(NBT $nbt, bool $network = false){ $nbt->putDouble($this->value); } } \ No newline at end of file diff --git a/src/devmine/creatures/player/tag/EndTag.php b/src/devmine/creatures/player/tag/EndTag.php index d37ed81..f3b1eac 100644 --- a/src/devmine/creatures/player/tag/EndTag.php +++ b/src/devmine/creatures/player/tag/EndTag.php @@ -12,11 +12,11 @@ public function getType(){ return NBT::TAG_End; } - public function read(NBT $nbt){ + public function read(NBT $nbt, bool $network = false){ } - public function write(NBT $nbt){ + public function write(NBT $nbt, bool $network = false){ } } \ No newline at end of file diff --git a/src/devmine/creatures/player/tag/FloatTag.php b/src/devmine/creatures/player/tag/FloatTag.php index f0a64b9..50c890b 100644 --- a/src/devmine/creatures/player/tag/FloatTag.php +++ b/src/devmine/creatures/player/tag/FloatTag.php @@ -14,11 +14,11 @@ public function getType(){ return NBT::TAG_Float; } - public function read(NBT $nbt){ + public function read(NBT $nbt, bool $network = false){ $this->value = $nbt->getFloat(); } - public function write(NBT $nbt){ + public function write(NBT $nbt, bool $network = false){ $nbt->putFloat($this->value); } } \ No newline at end of file diff --git a/src/devmine/creatures/player/tag/IntArrayTag.php b/src/devmine/creatures/player/tag/IntArrayTag.php index 76e7dab..d4562da 100644 --- a/src/devmine/creatures/player/tag/IntArrayTag.php +++ b/src/devmine/creatures/player/tag/IntArrayTag.php @@ -14,13 +14,13 @@ public function getType(){ return NBT::TAG_IntArray; } - public function read(NBT $nbt){ - $size = $nbt->getInt(); + public function read(NBT $nbt, bool $network = false){ + $size = $nbt->getInt($network); $this->value = array_values(unpack($nbt->endianness === NBT::LITTLE_ENDIAN ? "V*" : "N*", $nbt->get($size * 4))); } - public function write(NBT $nbt){ - $nbt->putInt(count($this->value)); + public function write(NBT $nbt, bool $network = false){ + $nbt->putInt(count($this->value), $network); $nbt->put(pack($nbt->endianness === NBT::LITTLE_ENDIAN ? "V*" : "N*", ...$this->value)); } diff --git a/src/devmine/creatures/player/tag/IntTag.php b/src/devmine/creatures/player/tag/IntTag.php index f76badd..debacdc 100644 --- a/src/devmine/creatures/player/tag/IntTag.php +++ b/src/devmine/creatures/player/tag/IntTag.php @@ -14,11 +14,11 @@ public function getType(){ return NBT::TAG_Int; } - public function read(NBT $nbt){ - $this->value = $nbt->getInt(); + public function read(NBT $nbt, bool $network = false){ + $this->value = $nbt->getInt($network); } - public function write(NBT $nbt){ - $nbt->putInt($this->value); + public function write(NBT $nbt, bool $network = false){ + $nbt->putInt($this->value, $network); } } \ No newline at end of file diff --git a/src/devmine/creatures/player/tag/ListTag.php b/src/devmine/creatures/player/tag/ListTag.php index 1b65b1f..fbc7f82 100644 --- a/src/devmine/creatures/player/tag/ListTag.php +++ b/src/devmine/creatures/player/tag/ListTag.php @@ -97,72 +97,72 @@ public function getTagType(){ return $this->tagType; } - public function read(NBT $nbt){ + public function read(NBT $nbt, bool $network = false){ $this->value = []; $this->tagType = $nbt->getByte(); - $size = $nbt->getInt(); + $size = $nbt->getInt($network); for($i = 0; $i < $size and !$nbt->feof(); ++$i){ switch($this->tagType){ case NBT::TAG_Byte: $tag = new ByteTag(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; case NBT::TAG_Short: $tag = new ShortTag(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; case NBT::TAG_Int: $tag = new IntTag(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; case NBT::TAG_Long: $tag = new LongTag(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; case NBT::TAG_Float: $tag = new FloatTag(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; case NBT::TAG_Double: $tag = new DoubleTag(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; case NBT::TAG_ByteArray: $tag = new ByteArrayTag(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; case NBT::TAG_String: $tag = new StringTag(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; case NBT::TAG_List: $tag = new TagEnum(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; case NBT::TAG_Compound: $tag = new CompoundTag(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; case NBT::TAG_IntArray: $tag = new IntArrayTag(""); - $tag->read($nbt); + $tag->read($nbt, $network); $this->{$i} = $tag; break; } } } - public function write(NBT $nbt){ + public function write(NBT $nbt, bool $network = false){ if(!isset($this->tagType)){ $id = null; foreach($this as $tag){ @@ -188,7 +188,7 @@ public function write(NBT $nbt){ } $nbt->putInt(count($tags)); foreach($tags as $tag){ - $tag->write($nbt); + $tag->write($nbt, $network); } } diff --git a/src/devmine/creatures/player/tag/LongTag.php b/src/devmine/creatures/player/tag/LongTag.php index 2038178..9ce4f38 100644 --- a/src/devmine/creatures/player/tag/LongTag.php +++ b/src/devmine/creatures/player/tag/LongTag.php @@ -14,11 +14,13 @@ public function getType(){ return NBT::TAG_Long; } - public function read(NBT $nbt){ + //TODO: check if this also changed to varint + + public function read(NBT $nbt, bool $network = false){ $this->value = $nbt->getLong(); } - public function write(NBT $nbt){ + public function write(NBT $nbt, bool $network = false){ $nbt->putLong($this->value); } } \ No newline at end of file diff --git a/src/devmine/creatures/player/tag/ShortTag.php b/src/devmine/creatures/player/tag/ShortTag.php index 0054e6a..c8c8a6e 100644 --- a/src/devmine/creatures/player/tag/ShortTag.php +++ b/src/devmine/creatures/player/tag/ShortTag.php @@ -14,11 +14,11 @@ public function getType(){ return NBT::TAG_Short; } - public function read(NBT $nbt){ + public function read(NBT $nbt, bool $network = false){ $this->value = $nbt->getShort(); } - public function write(NBT $nbt){ + public function write(NBT $nbt, bool $network = false){ $nbt->putShort($this->value); } } \ No newline at end of file diff --git a/src/devmine/creatures/player/tag/StringTag.php b/src/devmine/creatures/player/tag/StringTag.php index 60c823a..0e5b7f8 100644 --- a/src/devmine/creatures/player/tag/StringTag.php +++ b/src/devmine/creatures/player/tag/StringTag.php @@ -14,12 +14,11 @@ public function getType(){ return NBT::TAG_String; } - public function read(NBT $nbt){ - $this->value = $nbt->get($nbt->getShort()); + public function read(NBT $nbt, bool $network = false){ + $this->value = $nbt->getString($network); } - public function write(NBT $nbt){ - $nbt->putShort(strlen($this->value)); - $nbt->put($this->value); + public function write(NBT $nbt, bool $network = false){ + $nbt->putString($this->value, $network); } } \ No newline at end of file diff --git a/src/devmine/creatures/player/tag/Tag.php b/src/devmine/creatures/player/tag/Tag.php index fa6344a..f2eee92 100644 --- a/src/devmine/creatures/player/tag/Tag.php +++ b/src/devmine/creatures/player/tag/Tag.php @@ -23,9 +23,9 @@ public function setValue($value){ $this->value = $value; } - abstract public function write(NBT $nbt); + abstract public function write(NBT $nbt, bool $network = false); - abstract public function read(NBT $nbt); + abstract public function read(NBT $nbt, bool $network = false); public function __toString(){ return (string) $this->value; diff --git a/src/devmine/events/Cancellable.php b/src/devmine/events/Cancellable.php index b6e4ec6..6b3bb26 100644 --- a/src/devmine/events/Cancellable.php +++ b/src/devmine/events/Cancellable.php @@ -2,7 +2,7 @@ -namespace devmine\server\events; +namespace devmine\events; /** diff --git a/src/devmine/events/Event.php b/src/devmine/events/Event.php index 1e88a76..6337295 100644 --- a/src/devmine/events/Event.php +++ b/src/devmine/events/Event.php @@ -5,7 +5,7 @@ /** * Event related classes */ -namespace devmine\server\events; +namespace devmine\events; abstract class Event{ diff --git a/src/devmine/events/EventPriority.php b/src/devmine/events/EventPriority.php index 7700b2d..03cae81 100644 --- a/src/devmine/events/EventPriority.php +++ b/src/devmine/events/EventPriority.php @@ -1,25 +1,8 @@ mobSpawn = new TimingsHandler("** " . $name . "mobSpawn"); $this->doChunkUnload = new TimingsHandler("** " . $name . "doChunkUnload"); $this->doTickPending = new TimingsHandler("** " . $name . "doTickPending"); - $this->doTicksolidentities = new TimingsHandler("** " . $name . "doTicksolidentities"); + $this->doTickTiles = new TimingsHandler("** " . $name . "doTickTiles"); $this->doVillages = new TimingsHandler("** " . $name . "doVillages"); $this->doChunkMap = new TimingsHandler("** " . $name . "doChunkMap"); $this->doSounds = new TimingsHandler("** " . $name . "doSounds"); $this->doChunkGC = new TimingsHandler("** " . $name . "doChunkGC"); $this->doPortalForcer = new TimingsHandler("** " . $name . "doPortalForcer"); $this->entityTick = new TimingsHandler("** " . $name . "entityTick"); - $this->solidentityEntityTick = new TimingsHandler("** " . $name . "solidentityEntityTick"); - $this->solidentityEntityPending = new TimingsHandler("** " . $name . "solidentityEntityPending"); + $this->tileEntityTick = new TimingsHandler("** " . $name . "tileEntityTick"); + $this->tileEntityPending = new TimingsHandler("** " . $name . "tileEntityPending"); $this->syncChunkSendTimer = new TimingsHandler("** " . $name . "syncChunkSend"); $this->syncChunkSendPrepareTimer = new TimingsHandler("** " . $name . "syncChunkSendPrepare"); @@ -82,8 +82,8 @@ public function __construct(Level $level){ $this->syncChunkLoadDataTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Data"); $this->syncChunkLoadStructuresTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Structures"); $this->syncChunkLoadEntitiesTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Entities"); - $this->syncChunkLoadsolidentityEntitiesTimer = new TimingsHandler("** " . $name . "syncChunkLoad - solidentityEntities"); - $this->syncChunkLoadsolidentityTicksTimer = new TimingsHandler("** " . $name . "syncChunkLoad - solidentityTicks"); + $this->syncChunkLoadTileEntitiesTimer = new TimingsHandler("** " . $name . "syncChunkLoad - TileEntities"); + $this->syncChunkLoadTileTicksTimer = new TimingsHandler("** " . $name . "syncChunkLoad - TileTicks"); $this->syncChunkLoadPostTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Post"); $this->tracker = new TimingsHandler($name . "tracker"); diff --git a/src/devmine/events/Listener.php b/src/devmine/events/Listener.php index 765c244..def2b93 100644 --- a/src/devmine/events/Listener.php +++ b/src/devmine/events/Listener.php @@ -2,7 +2,7 @@ -namespace devmine\server\events; +namespace devmine\events; interface Listener{ diff --git a/src/devmine/events/TextContainer.php b/src/devmine/events/TextContainer.php index a7bb98a..14f7460 100644 --- a/src/devmine/events/TextContainer.php +++ b/src/devmine/events/TextContainer.php @@ -2,7 +2,7 @@ -namespace devmine\server\events; +namespace devmine\events; class TextContainer{ diff --git a/src/devmine/events/Timings.php b/src/devmine/events/Timings.php index 6c0a484..de2d83d 100644 --- a/src/devmine/events/Timings.php +++ b/src/devmine/events/Timings.php @@ -2,16 +2,16 @@ -namespace devmine\server\events; +namespace devmine\events; use devmine\creatures\entities\Entity; use devmine\server\network\protocol\DataPacket; -use devmine\Player; -use devmine\pluginfeatures\PluginManager; +use devmine\creatures\player; +use devmine\consumer\plugin\PluginManager; use devmine\server\tasks\PluginTask; use devmine\server\tasks\TaskHandler; -use devmine\inventory\solidentity\solidentity; +use devmine\inventory\solidentity\Tile; abstract class Timings{ @@ -65,7 +65,7 @@ abstract class Timings{ /** @var TimingsHandler */ public static $activatedEntityTimer; /** @var TimingsHandler */ - public static $ticksolidentityEntityTimer; + public static $tickTileEntityTimer; /** @var TimingsHandler */ public static $timerEntityBaseTick; @@ -91,7 +91,7 @@ abstract class Timings{ /** @var TimingsHandler[] */ public static $entityTypeTimingMap = []; /** @var TimingsHandler[] */ - public static $solidentityEntityTypeTimingMap = []; + public static $tileEntityTypeTimingMap = []; /** @var TimingsHandler[] */ public static $packetReceiveTimingMap = []; /** @var TimingsHandler[] */ @@ -129,7 +129,7 @@ public static function init(){ self::$entityMoveTimer = new TimingsHandler("** entityMove"); self::$tickEntityTimer = new TimingsHandler("** tickEntity"); self::$activatedEntityTimer = new TimingsHandler("** activatedTickEntity"); - self::$ticksolidentityEntityTimer = new TimingsHandler("** ticksolidentityEntity"); + self::$tickTileEntityTimer = new TimingsHandler("** tickTileEntity"); self::$timerEntityBaseTick = new TimingsHandler("** entityBaseTick"); self::$timerLivingEntityBaseTick = new TimingsHandler("** livingEntityBaseTick"); @@ -197,17 +197,17 @@ public static function getEntityTimings(Entity $entity){ } /** - * @param solidentity $solidentity + * @param Tile $tile * * @return TimingsHandler */ - public static function getsolidentityEntityTimings(solidentity $solidentity){ - $solidentityType = (new \ReflectionClass($solidentity))->getShortName(); - if(!isset(self::$solidentityEntityTypeTimingMap[$solidentityType])){ - self::$solidentityEntityTypeTimingMap[$solidentityType] = new TimingsHandler("** ticksolidentityEntity - " . $solidentityType, self::$ticksolidentityEntityTimer); + public static function getTileEntityTimings(Tile $tile){ + $tileType = (new \ReflectionClass($tile))->getShortName(); + if(!isset(self::$tileEntityTypeTimingMap[$tileType])){ + self::$tileEntityTypeTimingMap[$tileType] = new TimingsHandler("** tickTileEntity - " . $tileType, self::$tickTileEntityTimer); } - return self::$solidentityEntityTypeTimingMap[$solidentityType]; + return self::$tileEntityTypeTimingMap[$tileType]; } /** diff --git a/src/devmine/events/TimingsHandler.php b/src/devmine/events/TimingsHandler.php index 634a358..c62a22d 100644 --- a/src/devmine/events/TimingsHandler.php +++ b/src/devmine/events/TimingsHandler.php @@ -2,12 +2,12 @@ -namespace devmine\server\events; +namespace devmine\events; use devmine\server\commands\defaults\TimingsCommand; use devmine\creatures\entities\Living; -use devmine\pluginfeatures\PluginManager; -use devmine\Server; +use devmine\consumer\plugin\PluginManager; +use devmine\server\server; class TimingsHandler{ @@ -55,7 +55,7 @@ public static function printTimings($fp){ } fwrite($fp, "# Version " . Server::getInstance()->getVersion() . PHP_EOL); - fwrite($fp, "# " . Server::getInstance()->getName() . " " . Server::getInstance()->getdevmineVersion() . PHP_EOL); + fwrite($fp, "# " . Server::getInstance()->getName() . " " . Server::getInstance()->getDevMineVersion() . PHP_EOL); $entities = 0; $livingEntities = 0; diff --git a/src/devmine/events/TranslationContainer.php b/src/devmine/events/TranslationContainer.php index eff2cf1..0cc735f 100644 --- a/src/devmine/events/TranslationContainer.php +++ b/src/devmine/events/TranslationContainer.php @@ -2,7 +2,7 @@ -namespace devmine\server\events; +namespace devmine\events; class TranslationContainer extends TextContainer{ diff --git a/src/devmine/events/block/BlockBreakEvent.php b/src/devmine/events/block/BlockBreakEvent.php index eef1755..9492939 100644 --- a/src/devmine/events/block/BlockBreakEvent.php +++ b/src/devmine/events/block/BlockBreakEvent.php @@ -1,35 +1,18 @@ getInventory()->getArmorContents() as $i){ + foreach($entity->getInventory()->getArmorContents() as $index => $i){ if($i->isArmor()){ $points += $i->getArmorValue(); + $this->usedArmors[$index] = 1; } } if($points !== 0){ $this->setRateDamage(1 - 0.04 * $points, self::MODIFIER_ARMOR); - $this->use_armors = $entity->getInventory()->getArmorContents(); } //For Protection $spe_Prote = null; - switch ($cause){ + switch($cause){ case self::CAUSE_ENTITY_EXPLOSION: case self::CAUSE_BLOCK_EXPLOSION: $spe_Prote = Enchantment::TYPE_ARMOR_EXPLOSION_PROTECTION; @@ -138,16 +123,20 @@ public function __construct(Entity $entity, $cause, $damage){ case self::CAUSE_LAVA: $spe_Prote = Enchantment::TYPE_ARMOR_FIRE_PROTECTION; break; - case self::CAUSE_PROJECsolidentity: - $spe_Prote = Enchantment::TYPE_ARMOR_PROJECsolidentity_PROTECTION; + case self::CAUSE_PROJECTILE: + $spe_Prote = Enchantment::TYPE_ARMOR_PROJECTILE_PROTECTION; break; default; break; } - foreach($this->use_armors as $i){ + foreach($this->usedArmors as $index => $cost){ + $i = $entity->getInventory()->getArmorItem($index); if($i->isArmor()){ $this->EPF += $i->getEnchantmentLevel(Enchantment::TYPE_ARMOR_PROTECTION); $this->fireProtectL = max($this->fireProtectL, $i->getEnchantmentLevel(Enchantment::TYPE_ARMOR_FIRE_PROTECTION)); + if($i->getEnchantmentLevel(Enchantment::TYPE_ARMOR_THORNS) > 0){ + $this->thornsLevel[$index] = $i->getEnchantmentLevel(Enchantment::TYPE_ARMOR_THORNS); + } if($spe_Prote !== null){ $this->EPF += 2 * $i->getEnchantmentLevel($spe_Prote); } @@ -229,8 +218,8 @@ public function setDamage($damage, $type = self::MODIFIER_BASE){ * @return float 1 - the percentage */ public function getRateDamage($type = self::MODIFIER_BASE){ - if(isset($this->ratemodifiers[$type])){ - return $this->ratemodifiers[$type]; + if(isset($this->rateModifiers[$type])){ + return $this->rateModifiers[$type]; } return 1; } @@ -244,7 +233,7 @@ public function getRateDamage($type = self::MODIFIER_BASE){ * Notice:If you want to add/reduce the damage by multiplying. Plz use this function. */ public function setRateDamage($damage, $type = self::MODIFIER_BASE){ - $this->ratemodifiers[$type] = $damage; + $this->rateModifiers[$type] = $damage; } /** @@ -261,7 +250,7 @@ public function isApplicable($type){ */ public function getFinalDamage(){ $damage = $this->modifiers[self::MODIFIER_BASE]; - foreach($this->ratemodifiers as $type => $d){ + foreach($this->rateModifiers as $type => $d){ $damage *= $d; } foreach($this->modifiers as $type => $d){ @@ -273,10 +262,13 @@ public function getFinalDamage(){ } /** - * @return Item $use_armors + * @return Item $usedArmors + * notice: $usedArmors $index->$cost + * $index: the $index of ArmorInventory + * $cost: the num of durability cost */ public function getUsedArmors(){ - return $this->use_armors; + return $this->usedArmors; } /** @@ -292,10 +284,10 @@ public function getFireProtectL(){ public function useArmors(){ if($this->entity instanceof Player){ if($this->entity->isSurvival() and $this->entity->isAlive()){ - foreach ($this->use_armors as $index=>$i){ + foreach($this->usedArmors as $index => $cost){ + $i = $this->entity->getInventory()->getArmorItem($index); if($i->isArmor()){ - $i->useOn($i); - $this->entity->getInventory()->setArmorItem($index, $i); + $this->entity->getInventory()->damageArmor($index, $cost); } } } @@ -303,4 +295,30 @@ public function useArmors(){ } return false; } + + public function createThornsDamage(){ + if($this->thornsLevel !== []){ + $this->thornsArmor = array_rand($this->thornsLevel); + $thornsL = $this->thornsLevel[$this->thornsArmor]; + if(mt_rand(1, 100) < $thornsL * 15){ + $this->thornsDamage = mt_rand(1, 4); + } + } + } + + public function getThornsDamage(){ + return $this->thornsDamage; + } + + /** + * @return bool should be used after getThornsDamage() + */ + public function setThornsArmorUse(){ + if($this->thornsArmor === null){ + return false; + }else{ + $this->usedArmors[$this->thornsArmor] = 3; + return true; + } + } } diff --git a/src/devmine/events/entity/EntityDeathEvent.php b/src/devmine/events/entity/EntityDeathEvent.php index 800af50..0d484bd 100644 --- a/src/devmine/events/entity/EntityDeathEvent.php +++ b/src/devmine/events/entity/EntityDeathEvent.php @@ -1,25 +1,8 @@ entity instanceof Projecsolidentity; + public function isProjectile(){ + return $this->entity instanceof Projectile; } /** diff --git a/src/devmine/events/entity/EntityDrinkPotionEvent.php b/src/devmine/events/entity/EntityDrinkPotionEvent.php index caaa498..6fbc0e7 100644 --- a/src/devmine/events/entity/EntityDrinkPotionEvent.php +++ b/src/devmine/events/entity/EntityDrinkPotionEvent.php @@ -1,12 +1,29 @@ entity = $entity; + $this->effect = $effect; + } + + /** + * @return Effect + */ + public function getEffect(){ + return $this->effect; + } +} diff --git a/src/devmine/events/entity/EntityEffectRemoveEvent.php b/src/devmine/events/entity/EntityEffectRemoveEvent.php new file mode 100644 index 0000000..0a80b1a --- /dev/null +++ b/src/devmine/events/entity/EntityEffectRemoveEvent.php @@ -0,0 +1,30 @@ +entity = $entity; + $this->effect = $effect; + } + + /** + * @return Effect + */ + public function getEffect(){ + return $this->effect; + } +} diff --git a/src/devmine/events/entity/EntityEvent.php b/src/devmine/events/entity/EntityEvent.php index bc5d28e..c0dde4e 100644 --- a/src/devmine/events/entity/EntityEvent.php +++ b/src/devmine/events/entity/EntityEvent.php @@ -1,30 +1,13 @@ entity = $entity; - $this->pos = $pos; - } - - public function getVector(){ - return $this->pos; - } - - -} \ No newline at end of file diff --git a/src/devmine/events/entity/EntityRegainHealthEvent.php b/src/devmine/events/entity/EntityRegainHealthEvent.php index 0b01348..404c7df 100644 --- a/src/devmine/events/entity/EntityRegainHealthEvent.php +++ b/src/devmine/events/entity/EntityRegainHealthEvent.php @@ -1,28 +1,11 @@ entity = $shooter; $this->bow = $bow; - $this->projecsolidentity = $projecsolidentity; + $this->projectile = $projectile; $this->force = $force; } @@ -65,22 +48,22 @@ public function getBow(){ } /** - * @return Entity|Projecsolidentity + * @return Entity|Projectile */ - public function getProjecsolidentity(){ - return $this->projecsolidentity; + public function getProjectile(){ + return $this->projectile; } /** - * @param Entity $projecsolidentity + * @param Entity $projectile */ - public function setProjecsolidentity(Entity $projecsolidentity){ - if($projecsolidentity !== $this->projecsolidentity){ - if(count($this->projecsolidentity->getViewers()) === 0){ - $this->projecsolidentity->kill(); - $this->projecsolidentity->close(); + public function setProjectile(Entity $projectile){ + if($projectile !== $this->projectile){ + if(count($this->projectile->getViewers()) === 0){ + $this->projectile->kill(); + $this->projectile->close(); } - $this->projecsolidentity = $projecsolidentity; + $this->projectile = $projectile; } } diff --git a/src/devmine/events/entity/EntitySpawnEvent.php b/src/devmine/events/entity/EntitySpawnEvent.php index a703ccd..c8d82c8 100644 --- a/src/devmine/events/entity/EntitySpawnEvent.php +++ b/src/devmine/events/entity/EntitySpawnEvent.php @@ -1,31 +1,14 @@ entity->getPosition(); @@ -75,8 +58,8 @@ public function isHuman(){ /** * @return bool */ - public function isProjecsolidentity(){ - return $this->entity instanceof Projecsolidentity; + public function isProjectile(){ + return $this->entity instanceof Projectile; } /** diff --git a/src/devmine/events/entity/EntityTeleportEvent.php b/src/devmine/events/entity/EntityTeleportEvent.php index 7078bd0..533581d 100644 --- a/src/devmine/events/entity/EntityTeleportEvent.php +++ b/src/devmine/events/entity/EntityTeleportEvent.php @@ -1,30 +1,13 @@ entity = $entity; } /** - * @return Projecsolidentity + * @return Projectile */ public function getEntity(){ return $this->entity; diff --git a/src/devmine/events/entity/ProjectileLaunchEvent.php b/src/devmine/events/entity/ProjectileLaunchEvent.php index 774a9bc..ceff83e 100644 --- a/src/devmine/events/entity/ProjectileLaunchEvent.php +++ b/src/devmine/events/entity/ProjectileLaunchEvent.php @@ -1,42 +1,25 @@ entity = $entity; } /** - * @return Projecsolidentity + * @return Projectile */ public function getEntity(){ return $this->entity; diff --git a/src/devmine/events/inventory/CraftItemEvent.php b/src/devmine/events/inventory/CraftItemEvent.php index c1d8cee..c13eaf5 100644 --- a/src/devmine/events/inventory/CraftItemEvent.php +++ b/src/devmine/events/inventory/CraftItemEvent.php @@ -1,29 +1,12 @@ $item){ + foreach($this->input as $i => $item){ $items[$i] = clone $item; } return $items; @@ -64,9 +47,9 @@ public function getRecipe(){ } /** - * @return \devmine\Player + * @return \devmine\creatures\player */ public function getPlayer(){ return $this->player; } -} \ No newline at end of file +} diff --git a/src/devmine/events/inventory/FurnaceBurnEvent.php b/src/devmine/events/inventory/FurnaceBurnEvent.php index 47830b8..bb1473d 100644 --- a/src/devmine/events/inventory/FurnaceBurnEvent.php +++ b/src/devmine/events/inventory/FurnaceBurnEvent.php @@ -1,28 +1,11 @@ ts = $ts; + public function __construct(TransactionQueue $transactionQueue){ + $this->transactionQueue = $transactionQueue; } /** - * @return TransactionGroup + * @deprecated + * @return TransactionQueue */ public function getTransaction(){ - return $this->ts; + return $this->transactionQueue; } -} + /** + * @return TransactionQueue + */ + public function getQueue(){ + return $this->transactionQueue; + } +} \ No newline at end of file diff --git a/src/devmine/events/level/ChunkEvent.php b/src/devmine/events/level/ChunkEvent.php index ff53ce6..29e2936 100644 --- a/src/devmine/events/level/ChunkEvent.php +++ b/src/devmine/events/level/ChunkEvent.php @@ -1,45 +1,28 @@ getProvider()->getLevel()); $this->chunk = $chunk; } /** - * @return FullChunk + * @return Chunk */ public function getChunk(){ return $this->chunk; diff --git a/src/devmine/events/level/ChunkLoadEvent.php b/src/devmine/events/level/ChunkLoadEvent.php index 96f99b4..9844880 100644 --- a/src/devmine/events/level/ChunkLoadEvent.php +++ b/src/devmine/events/level/ChunkLoadEvent.php @@ -1,27 +1,10 @@ newChunk = (bool) $newChunk; } diff --git a/src/devmine/events/level/ChunkPopulateEvent.php b/src/devmine/events/level/ChunkPopulateEvent.php index a0e17bc..91e6e29 100644 --- a/src/devmine/events/level/ChunkPopulateEvent.php +++ b/src/devmine/events/level/ChunkPopulateEvent.php @@ -1,25 +1,8 @@ level; diff --git a/src/devmine/events/level/LevelInitEvent.php b/src/devmine/events/level/LevelInitEvent.php index b5a77d3..11cab11 100644 --- a/src/devmine/events/level/LevelInitEvent.php +++ b/src/devmine/events/level/LevelInitEvent.php @@ -1,25 +1,8 @@ animationType; } -} \ No newline at end of file +} diff --git a/src/devmine/events/player/PlayerBedEnterEvent.php b/src/devmine/events/player/PlayerBedEnterEvent.php index 12631f4..e8c01e0 100644 --- a/src/devmine/events/player/PlayerBedEnterEvent.php +++ b/src/devmine/events/player/PlayerBedEnterEvent.php @@ -1,29 +1,12 @@ player = $player; $this->message = $message; - //TODO: @deprecated (backwards-compativility) - $i = 0; - while(($pos = strpos($format, "%s")) !== false){ - $format = substr($format, 0, $pos) . "{%$i}" . substr($format, $pos + 2); - ++$i; - } - $this->format = $format; if($recipients === null){ @@ -84,13 +60,6 @@ public function getFormat(){ } public function setFormat($format){ - //TODO: @deprecated (backwards-compativility) - $i = 0; - while(($pos = strpos($format, "%s")) !== false){ - $format = substr($format, 0, $pos) . "{%$i}" . substr($format, $pos + 2); - ++$i; - } - $this->format = $format; } diff --git a/src/devmine/events/player/PlayerCommandPreprocessEvent.php b/src/devmine/events/player/PlayerCommandPreprocessEvent.php index da955d6..d908fc2 100644 --- a/src/devmine/events/player/PlayerCommandPreprocessEvent.php +++ b/src/devmine/events/player/PlayerCommandPreprocessEvent.php @@ -1,28 +1,11 @@ exp = $exp; + public function __construct(Human $player, int $expLevel, float $progress){ + $this->progress = $progress; $this->expLevel = $expLevel; - $this->action = $action; $this->player = $player; } + /** + * @deprecated This is redundant, and will be removed in the future. + */ public function getAction(){ - return $this->action; - } - - public function getExp(){ - return $this->exp; + return self::SET_EXPERIENCE; } - + public function getExpLevel(){ return $this->expLevel; } - - public function setExp($exp){ - $this->exp = $exp; - } - + public function setExpLevel($level){ $this->expLevel = $level; } + public function getProgress(): float{ + return $this->progress; + } + + public function setProgress(float $progress){ + $this->progress = $progress; //errors will be handled internally anyway + } + + public function getExp(){ + return Human::getLevelXpRequirement($this->level) * $this->progress; + } + + public function setExp($exp){ + $this->progress = $exp / Human::getLevelXpRequirement($this->level); + } } diff --git a/src/devmine/events/player/PlayerFishEvent.php b/src/devmine/events/player/PlayerFishEvent.php index abb4e52..1f33376 100644 --- a/src/devmine/events/player/PlayerFishEvent.php +++ b/src/devmine/events/player/PlayerFishEvent.php @@ -1,30 +1,13 @@ type; } -} \ No newline at end of file +} diff --git a/src/devmine/events/player/PlayerToggleFlightEvent.php b/src/devmine/events/player/PlayerToggleFlightEvent.php new file mode 100644 index 0000000..1168a33 --- /dev/null +++ b/src/devmine/events/player/PlayerToggleFlightEvent.php @@ -0,0 +1,25 @@ +player = $player; + $this->isFlying = (bool) $isFlying; + } + + public function isFlying(){ + return $this->isFlying; + } + +} \ No newline at end of file diff --git a/src/devmine/events/player/PlayerToggleGlideEvent.php b/src/devmine/events/player/PlayerToggleGlideEvent.php new file mode 100644 index 0000000..9597e4f --- /dev/null +++ b/src/devmine/events/player/PlayerToggleGlideEvent.php @@ -0,0 +1,17 @@ +player = $player; + $this->isGliding = (bool) $isGliding; + } + public function isGliding(){ + return $this->isGliding; + } +} diff --git a/src/devmine/events/player/PlayerToggleSneakEvent.php b/src/devmine/events/player/PlayerToggleSneakEvent.php index 53892a4..023bede 100644 --- a/src/devmine/events/player/PlayerToggleSneakEvent.php +++ b/src/devmine/events/player/PlayerToggleSneakEvent.php @@ -1,28 +1,11 @@ gametype = ($server->getGamemode() & 0x01) === 0 ? "SMP" : "CMP"; $this->version = $server->getVersion(); - $this->server_engine = $server->getName() . " " . $server->getdevmineVersion(); + $this->server_engine = $server->getName() . " " . $server->getDevMineVersion(); $this->map = $server->getDefaultLevel() === null ? "unknown" : $server->getDefaultLevel()->getName(); $this->numPlayers = $poc; $this->maxPlayers = $pc; @@ -112,28 +95,28 @@ public function setListPlugins($value){ } /** - * @return \devmine\pluginfeatures\Plugin[] + * @return \devmine\consumer\plugin\Plugin[] */ public function getPlugins(){ return $this->plugins; } /** - * @param \devmine\pluginfeatures\Plugin[] $plugins + * @param \devmine\consumer\plugin\Plugin[] $plugins */ public function setPlugins(array $plugins){ $this->plugins = $plugins; } /** - * @return \devmine\Player[] + * @return \devmine\creatures\player[] */ public function getPlayerList(){ return $this->players; } /** - * @param \devmine\Player[] $players + * @param \devmine\creatures\player[] $players */ public function setPlayerList(array $players){ $this->players = $players; diff --git a/src/devmine/events/server/RemoteServerCommandEvent.php b/src/devmine/events/server/RemoteServerCommandEvent.php index 826110a..e2e5a3e 100644 --- a/src/devmine/events/server/RemoteServerCommandEvent.php +++ b/src/devmine/events/server/RemoteServerCommandEvent.php @@ -1,25 +1,8 @@ meta = $meta; - } - public function getName() : string{ return "Acacia Wood Stairs"; } - - public function getDrops(Item $item) : array { - return [ - [$this->id, 0, 1], - ]; - } - - public function getHardness() { - return 2; - } - - public function getResistance(){ - return 15; - } - - public function getToolType(){ - return Tool::TYPE_AXE; - } } \ No newline at end of file diff --git a/src/devmine/inventory/blocks/ActiveRedstoneLamp.php b/src/devmine/inventory/blocks/ActiveRedstoneLamp.php index 4d576a8..3a7da49 100644 --- a/src/devmine/inventory/blocks/ActiveRedstoneLamp.php +++ b/src/devmine/inventory/blocks/ActiveRedstoneLamp.php @@ -1,6 +1,23 @@ getLevel()->setBlock($this, new InactiveRedstoneLamp(), true, false); + $this->getLevel()->setBlock($this, new InactiveRedstoneLamp(), true, true); //$this->turnAroundOff(); return true; } diff --git a/src/devmine/inventory/blocks/Anvil.php b/src/devmine/inventory/blocks/Anvil.php index 79351d8..e49a722 100644 --- a/src/devmine/inventory/blocks/Anvil.php +++ b/src/devmine/inventory/blocks/Anvil.php @@ -7,8 +7,8 @@ use devmine\inventory\layout\AnvilInventory; use devmine\inventory\items\Item; use devmine\inventory\items\Tool; -use devmine\levels\sound\AnvilFallSound; -use devmine\Player; +use devmine\worlds\sound\AnvilFallSound; +use devmine\creatures\player; class Anvil extends Fallable{ @@ -39,7 +39,13 @@ public function getResistance(){ } public function getName() : string{ - return "Anvil"; + $names = [ + self::NORMAL => "Anvil", + self::SLIGHTLY_DAMAGED => "Slightly Damaged Anvil", + self::VERY_DAMAGED => "Very Damaged Anvil", + 12 => "Anvil" //just in case somebody uses /give to get an anvil with damage 12 or higher, to prevent crash + ]; + return $names[$this->meta & 0x0c]; } public function getToolType(){ @@ -56,23 +62,26 @@ public function onActivate(Item $item, Player $player = null){ } $player->addWindow(new AnvilInventory($this)); + $player->craftingType = Player::CRAFTING_ANVIL; } return true; } public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ - parent::place($item, $block, $target, $face, $fx, $fy, $fz, $player); - $this->getLevel()->addSound(new AnvilFallSound($this)); + $direction = ($player !== null? $player->getDirection(): 0) & 0x03; + $this->meta = ($this->meta & 0x0c) | $direction; + $this->getLevel()->setBlock($block, $this, true, true); + $this->level->addSound(new AnvilFallSound($this)); } public function getDrops(Item $item) : array { if($item->isPickaxe() >= 1){ return [ - [$this->id, 0, 1], //TODO break level + [$this->id, $this->meta & 0x0c, 1], ]; }else{ return []; } } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/blocks/BeaconBlock.php b/src/devmine/inventory/blocks/BeaconBlock.php new file mode 100644 index 0000000..53b2991 --- /dev/null +++ b/src/devmine/inventory/blocks/BeaconBlock.php @@ -0,0 +1,45 @@ +meta = $meta; + } + + public function canBeActivated() : bool{ + return false; + } + + public function getName(){ + return "Beacon"; + } + + public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ + $this->getLevel()->setBlock($this, $this, true, true); + $nbt = new CompoundTag("", [ + new StringTag("id", Tile::BEACON), + new IntTag("x", $block->x), + new IntTag("y", $block->y), + new IntTag("z", $block->z) + ]); + $pot = Tile::createTile(Tile::BEACON, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + return true; + } + } diff --git a/src/devmine/inventory/blocks/Bed.php b/src/devmine/inventory/blocks/Bed.php index 6b75c04..e7b03bf 100644 --- a/src/devmine/inventory/blocks/Bed.php +++ b/src/devmine/inventory/blocks/Bed.php @@ -4,11 +4,12 @@ namespace devmine\inventory\blocks; +use devmine\events\TranslationContainter; use devmine\inventory\items\Item; -use devmine\levels\Explosion; -use devmine\levels\Level; +use devmine\worlds\Explosion; +use devmine\worlds\Level; use devmine\server\calculations\AxisAlignedBB; -use devmine\Player; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class Bed extends Transparent{ @@ -54,7 +55,7 @@ public function onActivate(Item $item, Player $player = null){ $isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE); if($player instanceof Player and !$isNight){ - $player->sendMessage(TextFormat::GRAY . "You can only sleep at night"); + $player->sendMessage(new TranslationContainter(TextFormat::GRAY . "%tile.bed.noSleep")); return true; } @@ -83,7 +84,7 @@ public function onActivate(Item $item, Player $player = null){ } if($player instanceof Player and $player->sleepOn($b) === false){ - $player->sendMessage(TextFormat::GRAY . "This bed is occupied"); + $player->sendMessage(new TranslationContainter(TextFormat::GRAY . "%tile.bed.occupied")); } return true; diff --git a/src/devmine/inventory/blocks/BirchWoodStairs.php b/src/devmine/inventory/blocks/BirchWoodStairs.php index b841434..4df1205 100644 --- a/src/devmine/inventory/blocks/BirchWoodStairs.php +++ b/src/devmine/inventory/blocks/BirchWoodStairs.php @@ -4,36 +4,11 @@ namespace devmine\inventory\blocks; -use devmine\inventory\items\Item; -use devmine\inventory\items\Tool; - -class BirchWoodStairs extends Stair{ +class BirchWoodStairs extends WoodStairs{ protected $id = self::BIRCH_WOOD_STAIRS; - public function __construct($meta = 0){ - $this->meta = $meta; - } - public function getName() : string{ return "Birch Wood Stairs"; } - - public function getDrops(Item $item) : array { - return [ - [$this->id, 0, 1], - ]; - } - - public function getHardness() { - return 2; - } - - public function getResistance(){ - return 15; - } - - public function getToolType(){ - return Tool::TYPE_AXE; - } } \ No newline at end of file diff --git a/src/devmine/inventory/blocks/Block.php b/src/devmine/inventory/blocks/Block.php index 66a07b8..f4e400b 100644 --- a/src/devmine/inventory/blocks/Block.php +++ b/src/devmine/inventory/blocks/Block.php @@ -8,23 +8,20 @@ namespace devmine\inventory\blocks; use devmine\creatures\entities\Entity; - - -use devmine\server\events\block\BlockBurnEvent; +use devmine\events\block\BlockBurnEvent; use devmine\inventory\items\Item; use devmine\inventory\items\Tool; -use devmine\levels\Level; -use devmine\levels\MovingObjectPosition; -use devmine\levels\Position; +use devmine\worlds\Level; +use devmine\worlds\MovingObjectPosition; +use devmine\worlds\Position; use devmine\server\calculations\AxisAlignedBB; use devmine\server\calculations\Vector3; -use devmine\server\epilogos\epilogosble; -use devmine\server\epilogos\epilogosValue; -use devmine\Player; -use devmine\pluginfeatures\Plugin; +use devmine\server\meta\Metadatable; +use devmine\server\meta\MetadataValue; +use devmine\creatures\player; +use devmine\consumer\plugin\Plugin; - -class Block extends Position implements BlockIds, epilogosble{ +class Block extends Position implements BlockIds, Metadatable{ /** @var \SplFixedArray */ public static $list = null; @@ -48,32 +45,6 @@ class Block extends Position implements BlockIds, epilogosble{ /** @var AxisAlignedBB */ public $boundingBox = null; - /** - * Backwards-compatibility with old way to define block properties - * - * @deprecated - * - * @param string $key - * - * @return mixed - */ - public function __get($key){ - static $map = [ - "hardness" => "getHardness", - "lightLevel" => "getLightLevel", - "frictionFactor" => "getFrictionFactor", - "name" => "getName", - "isPlaceable" => "canBePlaced", - "isReplaceable" => "canBeReplaced", - "isTransparent" => "isTransparent", - "isSolid" => "isSolid", - "isFlowable" => "canBeFlowedInto", - "isActivable" => "canBeActivated", - "hasEntityCollision" => "hasEntityCollision" - ]; - return isset($map[$key]) ? $this->{$map[$key]}() : null; - } - public static function init(){ if(self::$list === null){ self::$list = new \SplFixedArray(256); @@ -204,6 +175,16 @@ public static function init(){ self::$list[self::BREWING_STAND_BLOCK] = BrewingStand::class; self::$list[self::END_PORTAL_FRAME] = EndPortalFrame::class; self::$list[self::END_STONE] = EndStone::class; + + self::$list[self::END_STONE_BRICKS] = EndStoneBricks::class; + self::$list[self::END_ROD] = EndRod::class; + + self::$list[self::PURPUR_BLOCK] = PurpurBlock::class; + self::$list[self::PURPUR_STAIRS] = PurpurStairs::class; + + self::$list[self::CHORUS_FLOWER] = ChorusFlower::class; + self::$list[self::CHORUS_PLANT] = ChorusPlant::class; + self::$list[self::SANDSTONE_STAIRS] = SandstoneStairs::class; self::$list[self::EMERALD_ORE] = EmeraldOre::class; @@ -211,6 +192,7 @@ public static function init(){ self::$list[self::SPRUCE_WOOD_STAIRS] = SpruceWoodStairs::class; self::$list[self::BIRCH_WOOD_STAIRS] = BirchWoodStairs::class; self::$list[self::JUNGLE_WOOD_STAIRS] = JungleWoodStairs::class; + self::$list[self::BEACON_BLOCK] = BeaconBlock::class; self::$list[self::STONE_WALL] = StoneWall::class; self::$list[self::FLOWER_POT_BLOCK] = FlowerPot::class; @@ -233,6 +215,8 @@ public static function init(){ self::$list[self::DARK_OAK_WOOD_STAIRS] = DarkOakWoodStairs::class; self::$list[self::SLIME_BLOCK] = SlimeBlock::class; + self::$list[self::PRISMARINE_BLOCK] = PrismarineBlock::class; + self::$list[self::SEA_LANTERN_BLOCK] = SeaLanternBlock::class; self::$list[self::HAY_BALE] = HayBale::class; self::$list[self::CARPET] = Carpet::class; self::$list[self::HARDENED_CLAY] = HardenedClay::class; @@ -287,6 +271,8 @@ public static function init(){ self::$list[self::POWERED_REPEATER_BLOCK] = PoweredRepeater::class; self::$list[self::UNPOWERED_REPEATER_BLOCK] = UnpoweredRepeater::class; self::$list[self::CAULDRON_BLOCK] = Cauldron::class; + self::$list[self::INVISIBLE_BEDROCK] = InvisibleBedrock::class; + self::$list[self::HOPPER_BLOCK] = Hopper::class; foreach(self::$list as $id => $class){ if($class !== null){ @@ -304,14 +290,12 @@ public static function init(){ if($block->isSolid()){ if($block->isTransparent()){ - if($block instanceof Lava){ - self::$lightFilter[$id] = 15; - }elseif($block instanceof Liquid or $block instanceof Ice){ + if($block instanceof Liquid or $block instanceof Ice){ self::$lightFilter[$id] = 2; }else{ self::$lightFilter[$id] = 1; } - }elseif($block->getId() == Block::GLOWSTONE){ + }elseif($block instanceof SolidLight){ self::$lightFilter[$id] = 1; }else{ self::$lightFilter[$id] = 15; @@ -337,6 +321,10 @@ public static function init(){ * @return Block */ public static function get($id, $meta = 0, Position $pos = null){ + if($id > 0xff){ + trigger_error("BlockID cannot be higher than 255, defaulting to 0", E_USER_NOTICE); + $id = 0; + } try{ $block = self::$list[$id]; if($block !== null){ @@ -581,7 +569,7 @@ public function canPassThrough(){ /** * @return string */ - public function getName() : string{ + public function getName(){ return "Unknown"; } @@ -845,29 +833,29 @@ public function calculateIntercept(Vector3 $pos1, Vector3 $pos2){ return MovingObjectPosition::fromBlock($this->x, $this->y, $this->z, $f, $vector->add($this->x, $this->y, $this->z)); } - public function setepilogos($epilogosKey, epilogosValue $epilogosValue){ + public function setMetadata($metadataKey, MetadataValue $metadataValue){ if($this->getLevel() instanceof Level){ - $this->getLevel()->getBlockepilogos()->setepilogos($this, $epilogosKey, $epilogosValue); + $this->getLevel()->getBlockMetadata()->setMetadata($this, $metadataKey, $metadataValue); } } - public function getepilogos($epilogosKey){ + public function getMetadata($metadataKey){ if($this->getLevel() instanceof Level){ - return $this->getLevel()->getBlockepilogos()->getepilogos($this, $epilogosKey); + return $this->getLevel()->getBlockMetadata()->getMetadata($this, $metadataKey); } return null; } - public function hasepilogos($epilogosKey){ + public function hasMetadata($metadataKey){ if($this->getLevel() instanceof Level){ - $this->getLevel()->getBlockepilogos()->hasepilogos($this, $epilogosKey); + $this->getLevel()->getBlockMetadata()->hasMetadata($this, $metadataKey); } } - public function removeepilogos($epilogosKey, Plugin $plugin){ + public function removeMetadata($metadataKey, Plugin $plugin){ if($this->getLevel() instanceof Level){ - $this->getLevel()->getBlockepilogos()->removeepilogos($this, $epilogosKey, $plugin); + $this->getLevel()->getBlockMetadata()->removeMetadata($this, $metadataKey, $plugin); } } } diff --git a/src/devmine/inventory/blocks/BlockIds.php b/src/devmine/inventory/blocks/BlockIds.php index c3cd7dc..77163bd 100644 --- a/src/devmine/inventory/blocks/BlockIds.php +++ b/src/devmine/inventory/blocks/BlockIds.php @@ -1,9 +1,28 @@ getLevel()->setBlock($block, $this, true, true); $nbt = new CompoundTag("", [ new ListTag("Items", []), - new StringTag("id", solidentity::BREWING_STAND), + new StringTag("id", Tile::BREWING_STAND), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) @@ -45,7 +62,7 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } } - solidentity::createsolidentity(solidentity::BREWING_STAND, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + Tile::createTile(Tile::BREWING_STAND, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); return true; } @@ -78,20 +95,20 @@ public function onActivate(Item $item, Player $player = null){ if($player->isCreative() and $player->getServer()->limitedCreative){ return true; } - $t = $this->getLevel()->getsolidentity($this); + $t = $this->getLevel()->getTile($this); //$brewingStand = false; - if($t instanceof solidentityBrewingStand){ + if($t instanceof TileBrewingStand){ $brewingStand = $t; }else{ $nbt = new CompoundTag("", [ new ListTag("Items", []), - new StringTag("id", solidentity::BREWING_STAND), + new StringTag("id", Tile::BREWING_STAND), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) ]); $nbt->Items->setTagType(NBT::TAG_Compound); - $brewingStand = solidentity::createsolidentity(solidentity::BREWING_STAND, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + $brewingStand = Tile::createTile(Tile::BREWING_STAND, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); } $player->addWindow($brewingStand->getInventory()); } diff --git a/src/devmine/inventory/blocks/BrownMushroom.php b/src/devmine/inventory/blocks/BrownMushroom.php index 8b6d361..9bdcdae 100644 --- a/src/devmine/inventory/blocks/BrownMushroom.php +++ b/src/devmine/inventory/blocks/BrownMushroom.php @@ -5,8 +5,8 @@ namespace devmine\inventory\blocks; use devmine\inventory\items\Item; -use devmine\levels\Level; -use devmine\Player; +use devmine\worlds\Level; +use devmine\creatures\player; class BrownMushroom extends Flowable{ diff --git a/src/devmine/inventory/blocks/BrownMushroomBlock.php b/src/devmine/inventory/blocks/BrownMushroomBlock.php index d731991..df283f6 100644 --- a/src/devmine/inventory/blocks/BrownMushroomBlock.php +++ b/src/devmine/inventory/blocks/BrownMushroomBlock.php @@ -1,5 +1,23 @@ meta = $meta; - } - public function getName() : string{ return "Burning Furnace"; } - public function canBeActivated() : bool { - return true; - } - - public function getHardness() { - return 3.5; - } - - public function getToolType(){ - return Tool::TYPE_PICKAXE; - } - public function getLightLevel(){ return 13; } - - public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ - $faces = [ - 0 => 4, - 1 => 2, - 2 => 5, - 3 => 3, - ]; - $this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0]; - $this->getLevel()->setBlock($block, $this, true, true); - $nbt = new CompoundTag("", [ - new ListTag("Items", []), - new StringTag("id", solidentity::FURNACE), - new IntTag("x", $this->x), - new IntTag("y", $this->y), - new IntTag("z", $this->z) - ]); - $nbt->Items->setTagType(NBT::TAG_Compound); - - if($item->hasCustomName()){ - $nbt->CustomName = new StringTag("CustomName", $item->getCustomName()); - } - - if($item->hasCustomBlockData()){ - foreach($item->getCustomBlockData() as $key => $v){ - $nbt->{$key} = $v; - } - } - - solidentity::createsolidentity("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); - - return true; - } - - public function onBreak(Item $item){ - $this->getLevel()->setBlock($this, new Air(), true, true); - - return true; - } - - public function onActivate(Item $item, Player $player = null){ - if($player instanceof Player){ - $t = $this->getLevel()->getsolidentity($this); - $furnace = false; - if($t instanceof Furnace){ - $furnace = $t; - }else{ - $nbt = new CompoundTag("", [ - new ListTag("Items", []), - new StringTag("id", solidentity::FURNACE), - new IntTag("x", $this->x), - new IntTag("y", $this->y), - new IntTag("z", $this->z) - ]); - $nbt->Items->setTagType(NBT::TAG_Compound); - $furnace = solidentity::createsolidentity("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); - } - - if(isset($furnace->namedtag->Lock) and $furnace->namedtag->Lock instanceof StringTag){ - if($furnace->namedtag->Lock->getValue() !== $item->getCustomName()){ - return true; - } - } - - if($player->isCreative() and $player->getServer()->limitedCreative){ - return true; - } - - $player->addWindow($furnace->getInventory()); - } - - return true; - } - - public function getDrops(Item $item) : array { - $drops = []; - if($item->isPickaxe() >= 1){ - $drops[] = [Item::FURNACE, 0, 1]; - } - - return $drops; - } } \ No newline at end of file diff --git a/src/devmine/inventory/blocks/Cactus.php b/src/devmine/inventory/blocks/Cactus.php index d2e17be..d91e885 100644 --- a/src/devmine/inventory/blocks/Cactus.php +++ b/src/devmine/inventory/blocks/Cactus.php @@ -5,15 +5,15 @@ namespace devmine\inventory\blocks; use devmine\creatures\entities\Entity; -use devmine\server\events\block\BlockGrowEvent; -use devmine\server\events\entity\EntityDamageByBlockEvent; -use devmine\server\events\entity\EntityDamageEvent; +use devmine\events\block\BlockGrowEvent; +use devmine\events\entity\EntityDamageByBlockEvent; +use devmine\events\entity\EntityDamageEvent; use devmine\inventory\items\Item; -use devmine\levels\Level; +use devmine\worlds\Level; use devmine\server\calculations\AxisAlignedBB; use devmine\server\calculations\Vector3; -use devmine\Player; -use devmine\Server; +use devmine\creatures\player; +use devmine\server\server; class Cactus extends Transparent{ diff --git a/src/devmine/inventory/blocks/Cake.php b/src/devmine/inventory/blocks/Cake.php index 0fd8d41..87f7b68 100644 --- a/src/devmine/inventory/blocks/Cake.php +++ b/src/devmine/inventory/blocks/Cake.php @@ -4,14 +4,13 @@ namespace devmine\inventory\blocks; -use devmine\creatures\entities\Entity; -use devmine\server\events\entity\EntityEatBlockEvent; +use devmine\creatures\entities\Effect; +use devmine\events\entity\EntityEatBlockEvent; use devmine\inventory\items\FoodSource; use devmine\inventory\items\Item; -use devmine\levels\Level; +use devmine\worlds\Level; use devmine\server\calculations\AxisAlignedBB; -use devmine\Player; - +use devmine\creatures\player; class Cake extends Transparent implements FoodSource{ @@ -21,11 +20,11 @@ public function __construct($meta = 0){ $this->meta = $meta; } - public function canBeActivated() : bool { + public function canBeActivated() : bool{ return true; } - public function getHardness() { + public function getHardness(){ return 0.5; } @@ -33,7 +32,7 @@ public function getName() : string{ return "Cake Block"; } - protected function recalculateBoundingBox() { + protected function recalculateBoundingBox(){ $f = (1 + $this->getDamage() * 2) / 16; @@ -70,25 +69,21 @@ public function onUpdate($type){ return false; } - public function getDrops(Item $item) : array { + public function getDrops(Item $item) : array{ return []; } - public function canBeConsumed() : bool{ - return true; - } - - public function canBeConsumedBy(Entity $entity) : bool{ - return $entity instanceof Player and ($entity->getFood() < $entity->getMaxFood()) and $this->canBeConsumed(); - } + public function onActivate(Item $item, Player $player = null){ + if($player instanceof Player and $player->getHealth() < $player->getMaxHealth()){ + $ev = new EntityEatBlockEvent($player, $this); - public function getResidue(){ - $new = clone $this; - return $new; - } + if(!$ev->isCancelled()){ + $this->getLevel()->setBlock($this, $ev->getResidue()); + return true; + } + } - public function getAdditionalEffects() : array{ - return []; + return false; } public function getFoodRestore() : int{ @@ -99,24 +94,19 @@ public function getSaturationRestore() : float{ return 0.4; } - public function onActivate(Item $item, Player $player = null){ - if($player instanceof Player and $player->getFood() < 20){ - $player->getServer()->getPluginManager()->callEvent($ev = new EntityEatBlockEvent($player, $this)); - if(!$ev->isCancelled()){ - $player->setFood($player->getFood() + 2); - ++$this->meta; - - if($this->meta >= 0x06){ - $this->getLevel()->setBlock($this, new Air(), true); - }else{ - $this->getLevel()->setBlock($this, $this, true); - } - - return true; - } + public function getResidue(){ + $clone = clone $this; + $clone->meta++; + if($clone->meta >= 0x06){ + $clone = new Air(); } - - return false; + return $clone; } -} \ No newline at end of file + /** + * @return Effect[] + */ + public function getAdditionalEffects() : array{ + return []; + } +} diff --git a/src/devmine/inventory/blocks/Camera.php b/src/devmine/inventory/blocks/Camera.php deleted file mode 100644 index ac11095..0000000 --- a/src/devmine/inventory/blocks/Camera.php +++ /dev/null @@ -1,80 +0,0 @@ -meta = $meta; - } - - public function canBeReplaced(){ - return true; - } - - public function getName() : string{ - static $names = [ - 0 => "Camera", - ]; - return $names[$this->meta & 0x07]; - } - - public function onUpdate($type){ - if($type === Level::BLOCK_UPDATE_NORMAL){ - if($this->getSide(0)->isTransparent() === true && !$this->getSide(0) instanceof Camera){ //Replace with common break method - $this->getLevel()->setBlock($this, new Air(), false, false, true); - - return Level::BLOCK_UPDATE_NORMAL; - } - } - - return false; - } - - public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ - $down = $this->getSide(0); - $up = $this->getSide(1); - if($down->getId() === self::GRASS or $down->getId() === self::DIRT){ - $this->getLevel()->setBlock($block, $this, true); - $this->getLevel()->setBlock($up, Block::get($this->id, $this->meta ^ 0x08), true); - return true; - } - return false; - } - - public function onBreak(Item $item) : array{ - $up = $this->getSide(1); - $down = $this->getSide(0); - if(($this->meta & 0x08) === 0x08){ - if($up->getId() === $this->id and $up->meta !== 0x08){ - $this->getLevel()->setBlock($up, new Air(), true, true); - } - elseif($down->getId() === $this->id and $down->meta !== 0x08){ - $this->getLevel()->setBlock($down, new Air(), true, true); - } - } - else{ - if($up->getId() === $this->id and ($up->meta & 0x08) === 0x08){ - $this->getLevel()->setBlock($up, new Air(), true, true); - } - elseif($down->getId() === $this->id and ($down->meta & 0x08) === 0x08){ - $this->getLevel()->setBlock($down, new Air(), true, true); - } - } - } - - public function getDrops(Item $item) : array{ - if(($this->meta & 0x08) !== 0x08){ - return [[Item::CAMERA,$this->meta,1]]; - } - else - return []; - } -} diff --git a/src/devmine/inventory/blocks/Carpet.php b/src/devmine/inventory/blocks/Carpet.php index b833176..a054bbb 100644 --- a/src/devmine/inventory/blocks/Carpet.php +++ b/src/devmine/inventory/blocks/Carpet.php @@ -5,9 +5,9 @@ namespace devmine\inventory\blocks; use devmine\inventory\items\Item; -use devmine\levels\Level; +use devmine\worlds\Level; use devmine\server\calculations\AxisAlignedBB; -use devmine\Player; +use devmine\creatures\player; class Carpet extends Flowable{ diff --git a/src/devmine/inventory/blocks/Cauldron.php b/src/devmine/inventory/blocks/Cauldron.php index bf75c0b..50b1f40 100644 --- a/src/devmine/inventory/blocks/Cauldron.php +++ b/src/devmine/inventory/blocks/Cauldron.php @@ -1,30 +1,47 @@ x), new IntTag("y", $block->y), new IntTag("z", $block->z), @@ -69,7 +86,7 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } $chunk = $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4); - $solidentity = solidentity::createsolidentity("Cauldron", $chunk, $nbt);// + $tile = Tile::createTile("Cauldron", $chunk, $nbt);// $this->getLevel()->setBlock($block, $this, true, true); return true; } @@ -102,14 +119,14 @@ public function isFull(){ } public function onActivate(Item $item, Player $player = null){//@author iTX. rewrite @Dog194 - $solidentity = $this->getLevel()->getsolidentity($this); - if(!($solidentity instanceof solidentityCauldron)){ + $tile = $this->getLevel()->getTile($this); + if(!($tile instanceof TileCauldron)){ return false; } switch($item->getId()){ case Item::BUCKET: if($item->getDamage() === 0){//empty bucket - if(!$this->isFull() or $solidentity->isCustomColor() or $solidentity->hasPotion()){ + if(!$this->isFull() or $tile->isCustomColor() or $tile->hasPotion()){ break; } $bucket = clone $item; @@ -121,11 +138,11 @@ public function onActivate(Item $item, Player $player = null){//@author iTX. rew } $this->meta = 0;//empty $this->getLevel()->setBlock($this, $this, true); - $solidentity->clearCustomColor(); + $tile->clearCustomColor(); $this->getLevel()->addSound(new SplashSound($this->add(0.5, 1, 0.5))); } }elseif($item->getDamage() === 8){//water bucket - if($this->isFull() and !$solidentity->isCustomColor() and !$solidentity->hasPotion()){ + if($this->isFull() and !$tile->isCustomColor() and !$tile->hasPotion()){ break; } $bucket = clone $item; @@ -135,16 +152,16 @@ public function onActivate(Item $item, Player $player = null){//@author iTX. rew if($player->isSurvival()){ $player->getInventory()->setItemInHand($ev->getItem()); } - if($solidentity->hasPotion()){//if has potion + if($tile->hasPotion()){//if has potion $this->meta = 0;//empty - $solidentity->setPotionId(0xffff);//reset potion - $solidentity->setSplashPotion(false); - $solidentity->clearCustomColor(); + $tile->setPotionId(0xffff);//reset potion + $tile->setSplashPotion(false); + $tile->clearCustomColor(); $this->getLevel()->setBlock($this, $this, true); $this->getLevel()->addSound(new ExplodeSound($this->add(0.5, 0, 0.5))); }else{ $this->meta = 6;//fill - $solidentity->clearCustomColor(); + $tile->clearCustomColor(); $this->getLevel()->setBlock($this, $this, true); $this->getLevel()->addSound(new SplashSound($this->add(0.5, 1, 0.5))); } @@ -153,10 +170,10 @@ public function onActivate(Item $item, Player $player = null){//@author iTX. rew } break; case Item::DYE: - if($solidentity->hasPotion()) break; + if($tile->hasPotion()) break; $color = Color::getDyeColor($item->getDamage()); - if($solidentity->isCustomColor()){ - $color = Color::averageColor($color, $solidentity->getCustomColor()); + if($tile->isCustomColor()){ + $color = Color::averageColor($color, $tile->getCustomColor()); } if($player->isSurvival()){ $item->setCount($item->getCount() - 1); @@ -164,7 +181,7 @@ public function onActivate(Item $item, Player $player = null){//@author iTX. rew $player->getInventory()->setItemInHand(Item::get(Item::AIR)); }*/ } - $solidentity->setCustomColor($color); + $tile->setCustomColor($color); $this->getLevel()->addSound(new SplashSound($this->add(0.5, 1, 0.5))); $this->update(); break; @@ -173,16 +190,16 @@ public function onActivate(Item $item, Player $player = null){//@author iTX. rew case Item::LEATHER_PANTS: case Item::LEATHER_BOOTS: if($this->isEmpty()) break; - if($solidentity->isCustomColor()){ + if($tile->isCustomColor()){ --$this->meta; $this->getLevel()->setBlock($this, $this, true); $newItem = clone $item; /** @var Armor $newItem */ - $newItem->setCustomColor($solidentity->getCustomColor()); + $newItem->setCustomColor($tile->getCustomColor()); $player->getInventory()->setItemInHand($newItem); $this->getLevel()->addSound(new SplashSound($this->add(0.5, 1, 0.5))); if($this->isEmpty()){ - $solidentity->clearCustomColor(); + $tile->clearCustomColor(); } }else{ --$this->meta; @@ -196,16 +213,16 @@ public function onActivate(Item $item, Player $player = null){//@author iTX. rew break; case Item::POTION: case Item::SPLASH_POTION: - if(!$this->isEmpty() and (($solidentity->getPotionId() !== $item->getDamage() and $item->getDamage() !== Potion::WATER_BOTTLE) or - ($item->getId() === Item::POTION and $solidentity->getSplashPotion()) or - ($item->getId() === Item::SPLASH_POTION and !$solidentity->getSplashPotion()) and $item->getDamage() !== 0 or - ($item->getDamage() === Potion::WATER_BOTTLE and $solidentity->hasPotion())) + if(!$this->isEmpty() and (($tile->getPotionId() !== $item->getDamage() and $item->getDamage() !== Potion::WATER_BOTTLE) or + ($item->getId() === Item::POTION and $tile->getSplashPotion()) or + ($item->getId() === Item::SPLASH_POTION and !$tile->getSplashPotion()) and $item->getDamage() !== 0 or + ($item->getDamage() === Potion::WATER_BOTTLE and $tile->hasPotion())) ){//long... $this->meta = 0x00; $this->getLevel()->setBlock($this, $this, true); - $solidentity->setPotionId(0xffff);//reset - $solidentity->setSplashPotion(false); - $solidentity->clearCustomColor(); + $tile->setPotionId(0xffff);//reset + $tile->setSplashPotion(false); + $tile->clearCustomColor(); if($player->isSurvival()){ $player->getInventory()->setItemInHand(Item::get(Item::GLASS_BOTTLE)); } @@ -217,16 +234,16 @@ public function onActivate(Item $item, Player $player = null){//@author iTX. rew if($player->isSurvival()){ $player->getInventory()->setItemInHand(Item::get(Item::GLASS_BOTTLE)); } - $solidentity->setPotionId(0xffff); - $solidentity->setSplashPotion(false); - $solidentity->clearCustomColor(); + $tile->setPotionId(0xffff); + $tile->setSplashPotion(false); + $tile->clearCustomColor(); $this->getLevel()->addSound(new SplashSound($this->add(0.5, 1, 0.5))); }elseif(!$this->isFull()){ $this->meta += 2; if($this->meta > 0x06) $this->meta = 0x06; - $solidentity->setPotionId($item->getDamage()); - $solidentity->setSplashPotion($item->getId() === Item::SPLASH_POTION); - $solidentity->clearCustomColor(); + $tile->setPotionId($item->getDamage()); + $tile->setSplashPotion($item->getId() === Item::SPLASH_POTION); + $tile->clearCustomColor(); $this->getLevel()->setBlock($this, $this, true); if($player->isSurvival()){ $player->getInventory()->setItemInHand(Item::get(Item::GLASS_BOTTLE)); @@ -243,17 +260,17 @@ public function onActivate(Item $item, Player $player = null){//@author iTX. rew if($this->meta < 2) { break; } - if($solidentity->hasPotion()){ + if($tile->hasPotion()){ $this->meta -= 2; - if($solidentity->getSplashPotion() === true){ - $result = Item::get(Item::SPLASH_POTION, $solidentity->getPotionId()); + if($tile->getSplashPotion() === true){ + $result = Item::get(Item::SPLASH_POTION, $tile->getPotionId()); }else{ - $result = Item::get(Item::POTION, $solidentity->getPotionId()); + $result = Item::get(Item::POTION, $tile->getPotionId()); } if($this->isEmpty()){ - $solidentity->setPotionId(0xffff);//reset - $solidentity->setSplashPotion(false); - $solidentity->clearCustomColor(); + $tile->setPotionId(0xffff);//reset + $tile->setSplashPotion(false); + $tile->clearCustomColor(); } $this->getLevel()->setBlock($this, $this, true); $this->addItem($item, $player, $result); diff --git a/src/devmine/inventory/blocks/Chest.php b/src/devmine/inventory/blocks/Chest.php index 4fb17ef..837fc43 100644 --- a/src/devmine/inventory/blocks/Chest.php +++ b/src/devmine/inventory/blocks/Chest.php @@ -12,9 +12,9 @@ use devmine\creatures\player\tag\ListTag; use devmine\creatures\player\tag\IntTag; use devmine\creatures\player\tag\StringTag; -use devmine\Player; -use devmine\inventory\solidentity\Chest as solidentityChest; -use devmine\inventory\solidentity\solidentity; +use devmine\creatures\player; +use devmine\inventory\solidentity\Chest as TileChest; +use devmine\inventory\solidentity\Tile; class Chest extends Transparent{ @@ -70,9 +70,9 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } $c = $this->getSide($side); if($c instanceof Chest and $c->getDamage() === $this->meta){ - $solidentity = $this->getLevel()->getsolidentity($c); - if($solidentity instanceof solidentityChest and !$solidentity->isPaired()){ - $chest = $solidentity; + $tile = $this->getLevel()->getTile($c); + if($tile instanceof TileChest and !$tile->isPaired()){ + $chest = $tile; break; } } @@ -81,7 +81,7 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $this->getLevel()->setBlock($block, $this, true, true); $nbt = new CompoundTag("", [ new ListTag("Items", []), - new StringTag("id", solidentity::CHEST), + new StringTag("id", Tile::CHEST), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) @@ -98,19 +98,19 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } } - $solidentity = solidentity::createsolidentity("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + $tile = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); - if($chest instanceof solidentityChest and $solidentity instanceof solidentityChest){ - $chest->pairWith($solidentity); - $solidentity->pairWith($chest); + if($chest instanceof TileChest and $tile instanceof TileChest){ + $chest->pairWith($tile); + $tile->pairWith($chest); } return true; } public function onBreak(Item $item){ - $t = $this->getLevel()->getsolidentity($this); - if($t instanceof solidentityChest){ + $t = $this->getLevel()->getTile($this); + if($t instanceof TileChest){ $t->unpair(); } $this->getLevel()->setBlock($this, new Air(), true, true); @@ -125,20 +125,20 @@ public function onActivate(Item $item, Player $player = null){ return true; } - $t = $this->getLevel()->getsolidentity($this); + $t = $this->getLevel()->getTile($this); $chest = null; - if($t instanceof solidentityChest){ + if($t instanceof TileChest){ $chest = $t; }else{ $nbt = new CompoundTag("", [ new ListTag("Items", []), - new StringTag("id", solidentity::CHEST), + new StringTag("id", Tile::CHEST), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) ]); $nbt->Items->setTagType(NBT::TAG_Compound); - $chest = solidentity::createsolidentity("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + $chest = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); } if(isset($chest->namedtag->Lock) and $chest->namedtag->Lock instanceof StringTag){ diff --git a/src/devmine/inventory/blocks/ChorusFlower.php b/src/devmine/inventory/blocks/ChorusFlower.php new file mode 100644 index 0000000..5f3e747 --- /dev/null +++ b/src/devmine/inventory/blocks/ChorusFlower.php @@ -0,0 +1,57 @@ +meta = $meta; + } + + public function getHardness(){ + return 0.4; + } + + public function getToolType(){ + return Tool::TYPE_AXE; + } + + public function getName() : string{ + return "Chorus Flower"; + } + + public function getDrops(Item $item) : array { + $drops = []; + if($this->meta >= 0x07){ + $drops[] = [Item::CHORUS_FRUIT, 0, 1]; + } + return $drops; + } + +} \ No newline at end of file diff --git a/src/devmine/inventory/blocks/ChorusPlant.php b/src/devmine/inventory/blocks/ChorusPlant.php new file mode 100644 index 0000000..b95eff1 --- /dev/null +++ b/src/devmine/inventory/blocks/ChorusPlant.php @@ -0,0 +1,57 @@ +meta = $meta; + } + + public function getHardness(){ + return 0.4; + } + + public function getToolType(){ + return Tool::TYPE_AXE; + } + + public function getName() : string{ + return "Chorus Plant"; + } + + public function getDrops(Item $item) : array { + $drops = []; + if($this->meta >= 0x07){ + $drops[] = [Item::CHORUS_FRUIT, 0, 1]; + } + return $drops; + } + +} \ No newline at end of file diff --git a/src/devmine/inventory/blocks/CocoaBlock.php b/src/devmine/inventory/blocks/CocoaBlock.php index ad86066..18545d3 100644 --- a/src/devmine/inventory/blocks/CocoaBlock.php +++ b/src/devmine/inventory/blocks/CocoaBlock.php @@ -1,14 +1,31 @@ meta = $meta; - } - public function getName() : string{ return "Dark Oak Wood Stairs"; } - - public function getToolType(){ - return Tool::TYPE_AXE; - } - - public function getDrops(Item $item) : array { - return [ - [$this->id, 0, 1], - ]; - } } \ No newline at end of file diff --git a/src/devmine/inventory/blocks/DaylightDetector.php b/src/devmine/inventory/blocks/DaylightDetector.php index aaf0a5b..bcedc49 100644 --- a/src/devmine/inventory/blocks/DaylightDetector.php +++ b/src/devmine/inventory/blocks/DaylightDetector.php @@ -1,15 +1,32 @@ getLevel()->getsolidentity($this); + protected function getTile(){ + $t = $this->getLevel()->getTile($this); if($t instanceof DLDetector){ return $t; }else{ $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::DAY_LIGHT_DETECTOR), + new StringTag("id", Tile::DAY_LIGHT_DETECTOR), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) ]); - return solidentity::createsolidentity(solidentity::DAY_LIGHT_DETECTOR, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + return Tile::createTile(Tile::DAY_LIGHT_DETECTOR, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); } } public function onActivate(Item $item, Player $player = null){ $this->getLevel()->setBlock($this, new DaylightDetectorInverted(), true, true); - $this->getsolidentity()->onUpdate(); + $this->getTile()->onUpdate(); return true; } public function isActivated(Block $from = null){ - return $this->getsolidentity()->isActivated(); + return $this->getTile()->isActivated(); } public function onBreak(Item $item){ diff --git a/src/devmine/inventory/blocks/DaylightDetectorInverted.php b/src/devmine/inventory/blocks/DaylightDetectorInverted.php index 471fb41..f80b36a 100644 --- a/src/devmine/inventory/blocks/DaylightDetectorInverted.php +++ b/src/devmine/inventory/blocks/DaylightDetectorInverted.php @@ -1,18 +1,35 @@ getLevel()->setBlock($this, new DaylightDetector(), true, true); - $this->getsolidentity()->onUpdate(); + $this->getTile()->onUpdate(); return true; } } \ No newline at end of file diff --git a/src/devmine/inventory/blocks/DeadBush.php b/src/devmine/inventory/blocks/DeadBush.php index 447b4ea..8525d76 100644 --- a/src/devmine/inventory/blocks/DeadBush.php +++ b/src/devmine/inventory/blocks/DeadBush.php @@ -4,9 +4,9 @@ namespace devmine\inventory\blocks; -use devmine\levels\Level; +use devmine\worlds\Level; use devmine\inventory\items\Item; -use devmine\Player; +use devmine\creatures\player; class DeadBush extends Flowable{ diff --git a/src/devmine/inventory/blocks/Dirt.php b/src/devmine/inventory/blocks/Dirt.php index 0266eba..00a5182 100644 --- a/src/devmine/inventory/blocks/Dirt.php +++ b/src/devmine/inventory/blocks/Dirt.php @@ -6,7 +6,7 @@ use devmine\inventory\items\Item; use devmine\inventory\items\Tool; -use devmine\Player; +use devmine\creatures\player; class Dirt extends Solid{ diff --git a/src/devmine/inventory/blocks/Dispenser.php b/src/devmine/inventory/blocks/Dispenser.php index 051623c..0f03a57 100644 --- a/src/devmine/inventory/blocks/Dispenser.php +++ b/src/devmine/inventory/blocks/Dispenser.php @@ -1,6 +1,23 @@ getLevel()->setBlock($block, $this, true, true); $nbt = new CompoundTag("", [ new ListTag("Items", []), - new StringTag("id", solidentity::DISPENSER), + new StringTag("id", Tile::DISPENSER), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) @@ -78,34 +95,34 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } } - solidentity::createsolidentity(solidentity::DISPENSER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + Tile::createTile(Tile::DISPENSER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); return true; } public function activate(){ - $solidentity = $this->getLevel()->getsolidentity($this); - if($solidentity instanceof solidentityDispenser){ - $solidentity->activate(); + $tile = $this->getLevel()->getTile($this); + if($tile instanceof TileDispenser){ + $tile->activate(); } } public function onActivate(Item $item, Player $player = null){ if($player instanceof Player){ - $t = $this->getLevel()->getsolidentity($this); + $t = $this->getLevel()->getTile($this); $dispenser = null; - if($t instanceof solidentityDispenser){ + if($t instanceof TileDispenser){ $dispenser = $t; }else{ $nbt = new CompoundTag("", [ new ListTag("Items", []), - new StringTag("id", solidentity::DISPENSER), + new StringTag("id", Tile::DISPENSER), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) ]); $nbt->Items->setTagType(NBT::TAG_Compound); - $dispenser = solidentity::createsolidentity(solidentity::DISPENSER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + $dispenser = Tile::createTile(Tile::DISPENSER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); } if($player->isCreative() and $player->getServer()->limitedCreative){ diff --git a/src/devmine/inventory/blocks/Door.php b/src/devmine/inventory/blocks/Door.php index 10bc572..0b9baf4 100644 --- a/src/devmine/inventory/blocks/Door.php +++ b/src/devmine/inventory/blocks/Door.php @@ -5,11 +5,11 @@ namespace devmine\inventory\blocks; use devmine\inventory\items\Item; -use devmine\levels\Level; -use devmine\levels\sound\DoorSound; +use devmine\worlds\Level; +use devmine\worlds\sound\DoorSound; use devmine\server\calculations\AxisAlignedBB; use devmine\server\calculations\Vector3; -use devmine\Player; +use devmine\creatures\player; abstract class Door extends Transparent implements ElectricalAppliance{ @@ -192,10 +192,13 @@ protected function recalculateBoundingBox() { public function onUpdate($type){ if($type === Level::BLOCK_UPDATE_NORMAL){ - if($this->getSide(0)->getId() === self::AIR){ //Replace with common break method - $this->getLevel()->setBlock($this, new Air(), false); - if($this->getSide(1) instanceof Door){ - $this->getLevel()->setBlock($this->getSide(1), new Air(), false); + if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR and $this->getSide(Vector3::SIDE_UP) instanceof Door){ //Block underneath the door was broken + + $this->getLevel()->setBlock($this, new Air(), false, false); + $this->getLevel()->setBlock($this->getSide(Vector3::SIDE_UP), new Air(), false); + + foreach($this->getDrops(Item::get(Item::DIAMOND_PICKAXE)) as $drop){ + $this->getLevel()->dropItem($this, Item::get($drop[0], $drop[1], $drop[2])); } return Level::BLOCK_UPDATE_NORMAL; @@ -207,8 +210,8 @@ public function onUpdate($type){ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ if($face === 1){ - $blockUp = $this->getSide(1); - $blockDown = $this->getSide(0); + $blockUp = $this->getSide(Vector3::SIDE_UP); + $blockDown = $this->getSide(Vector3::SIDE_DOWN); if($blockUp->canBeReplaced() === false or $blockDown->isTransparent() === true){ return false; } @@ -237,12 +240,12 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, public function onBreak(Item $item){ if(($this->getDamage() & 0x08) === 0x08){ - $down = $this->getSide(0); + $down = $this->getSide(Vector3::SIDE_DOWN); if($down->getId() === $this->getId()){ $this->getLevel()->setBlock($down, new Air(), true); } }else{ - $up = $this->getSide(1); + $up = $this->getSide(Vector3::SIDE_UP); if($up->getId() === $this->getId()){ $this->getLevel()->setBlock($up, new Air(), true); } @@ -258,7 +261,7 @@ public function isOpened(){ public function onActivate(Item $item, Player $player = null){ if(($this->getDamage() & 0x08) === 0x08){ //Top - $down = $this->getSide(0); + $down = $this->getSide(Vector3::SIDE_DOWN); if($down->getId() === $this->getId()){ $meta = $down->getDamage() ^ 0x04; $this->getLevel()->setBlock($down, Block::get($this->getId(), $meta), true); @@ -284,4 +287,4 @@ public function onActivate(Item $item, Player $player = null){ return true; } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/blocks/DoublePlant.php b/src/devmine/inventory/blocks/DoublePlant.php index 1dae10f..7b4ed51 100644 --- a/src/devmine/inventory/blocks/DoublePlant.php +++ b/src/devmine/inventory/blocks/DoublePlant.php @@ -5,8 +5,8 @@ namespace devmine\inventory\blocks; use devmine\inventory\items\Item; -use devmine\levels\Level; -use devmine\Player; +use devmine\worlds\Level; +use devmine\creatures\player; class DoublePlant extends Flowable{ @@ -42,7 +42,7 @@ public function getName() : string{ public function onUpdate($type){ if($type === Level::BLOCK_UPDATE_NORMAL){ if($this->getSide(0)->isTransparent() === true && !$this->getSide(0) instanceof DoublePlant){ //Replace with common break method - $this->getLevel()->setBlock($this, new Air(), false, false); + $this->getLevel()->setBlock($this, new Air(), true, true); return Level::BLOCK_UPDATE_NORMAL; } diff --git a/src/devmine/inventory/blocks/DoubleRedSandstoneSlab.php b/src/devmine/inventory/blocks/DoubleRedSandstoneSlab.php index b1d9f5d..e8f049f 100644 --- a/src/devmine/inventory/blocks/DoubleRedSandstoneSlab.php +++ b/src/devmine/inventory/blocks/DoubleRedSandstoneSlab.php @@ -1,6 +1,23 @@ "Stone Brick", 6 => "Quartz", 7 => "Nether Brick", + 7 => "Purpur", ]; return "Double " . $names[$this->meta & 0x07] . " Slab"; } diff --git a/src/devmine/inventory/blocks/Dropper.php b/src/devmine/inventory/blocks/Dropper.php index 86d8c25..d0f8606 100644 --- a/src/devmine/inventory/blocks/Dropper.php +++ b/src/devmine/inventory/blocks/Dropper.php @@ -1,6 +1,23 @@ getLevel()->setBlock($block, $this, true, true); $nbt = new CompoundTag("", [ new ListTag("Items", []), - new StringTag("id", solidentity::DROPPER), + new StringTag("id", Tile::DROPPER), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) @@ -78,34 +95,34 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } } - solidentity::createsolidentity(solidentity::DROPPER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + Tile::createTile(Tile::DROPPER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); return true; } public function activate(){ - $solidentity = $this->getLevel()->getsolidentity($this); - if($solidentity instanceof solidentityDropper){ - $solidentity->activate(); + $tile = $this->getLevel()->getTile($this); + if($tile instanceof TileDropper){ + $tile->activate(); } } public function onActivate(Item $item, Player $player = null){ if($player instanceof Player){ - $t = $this->getLevel()->getsolidentity($this); + $t = $this->getLevel()->getTile($this); $dropper = null; - if($t instanceof solidentityDropper){ + if($t instanceof TileDropper){ $dropper = $t; }else{ $nbt = new CompoundTag("", [ new ListTag("Items", []), - new StringTag("id", solidentity::DROPPER), + new StringTag("id", Tile::DROPPER), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) ]); $nbt->Items->setTagType(NBT::TAG_Compound); - $dropper = solidentity::createsolidentity(solidentity::DROPPER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + $dropper = Tile::createTile(Tile::DROPPER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); } if($player->isCreative() and $player->getServer()->limitedCreative){ diff --git a/src/devmine/inventory/blocks/ElectricalAppliance.php b/src/devmine/inventory/blocks/ElectricalAppliance.php index af5f926..5aba74b 100644 --- a/src/devmine/inventory/blocks/ElectricalAppliance.php +++ b/src/devmine/inventory/blocks/ElectricalAppliance.php @@ -1,6 +1,23 @@ getLevel()->setBlock($block, $this, true, true); $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::ENCHANT_TABLE), + new StringTag("id", Tile::ENCHANT_TABLE), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) @@ -58,7 +58,7 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } } - solidentity::createsolidentity(solidentity::ENCHANT_TABLE, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); return true; } @@ -91,14 +91,14 @@ public function onActivate(Item $item, Player $player = null){ if($player->isCreative() and $player->getServer()->limitedCreative){ return true; } - $solidentity = $this->getLevel()->getsolidentity($this); + $tile = $this->getLevel()->getTile($this); $enchantTable = null; - if($solidentity instanceof EnchantTable){ - $enchantTable = $solidentity; + if($tile instanceof EnchantTable){ + $enchantTable = $tile; }else{ $this->getLevel()->setBlock($this, $this, true, true); $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::ENCHANT_TABLE), + new StringTag("id", Tile::ENCHANT_TABLE), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) @@ -115,9 +115,10 @@ public function onActivate(Item $item, Player $player = null){ } /** @var EnchantTable $enchantTable */ - $enchantTable = solidentity::createsolidentity(solidentity::ENCHANT_TABLE, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + $enchantTable = Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); } - $player->addWindow($enchantTable->getInventory()); + $player->addWindow(new EnchantInventory($this)); + $player->craftingType = Player::CRAFTING_ENCHANT; } diff --git a/src/devmine/inventory/blocks/EndPortalFrame.php b/src/devmine/inventory/blocks/EndPortalFrame.php index 5a543c5..88b74cc 100644 --- a/src/devmine/inventory/blocks/EndPortalFrame.php +++ b/src/devmine/inventory/blocks/EndPortalFrame.php @@ -7,7 +7,7 @@ use devmine\inventory\items\Item; use devmine\server\calculations\AxisAlignedBB; -class EndPortalFrame extends Solid{ +class EndPortalFrame extends Solid implements SolidLight{ protected $id = self::END_PORTAL_FRAME; diff --git a/src/devmine/inventory/blocks/EndRod.php b/src/devmine/inventory/blocks/EndRod.php new file mode 100644 index 0000000..545772c --- /dev/null +++ b/src/devmine/inventory/blocks/EndRod.php @@ -0,0 +1,87 @@ +meta = $meta; + } + + public function getLightLevel(){ + return 14; + } + + public function getName() : string{ + return "End Rod"; + } + + public function onUpdate($type){ + if($type === Level::BLOCK_UPDATE_NORMAL){ + $below = $this->getSide(0); + $side = $this->getDamage(); + $faces = [ + 1 => 1, + 2 => 2, + 3 => 3, + 4 => 4, + 5 => 5, + 6 => 6, + 0 => 0, + ]; + } + return false; + } + + public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ + $below = $this->getSide(0); + + if($target->isTransparent() === false and $face !== 0){ + $faces = [ + 1 => 1, + 2 => 3, + 3 => 2, + 4 => 5, + 5 => 4, + ]; + $this->meta = $faces[$face]; + $this->getLevel()->setBlock($block, $this, true, true); + return true; + } + return false; + } + + public function getDrops(Item $item) : array { + return [ + [$this->id, 0, 1], + ]; + } + +} \ No newline at end of file diff --git a/src/devmine/inventory/blocks/EndStoneBricks.php b/src/devmine/inventory/blocks/EndStoneBricks.php new file mode 100644 index 0000000..c991a7b --- /dev/null +++ b/src/devmine/inventory/blocks/EndStoneBricks.php @@ -0,0 +1,59 @@ +meta = $meta; + } + + public function getHardness() { + return 0.8; + } + + public function getToolType(){ + return Tool::TYPE_PICKAXE; + } + + public function getName() : string{ + return "End Stone Bricks"; + } + + public function getDrops(Item $item) : array { + if($item->isPickaxe() >= 1){ + return [ + [Item::ENDSTONE_BRICKS, $this->meta & 0x03, 1], + ]; + }else{ + return []; + } + } + +} \ No newline at end of file diff --git a/src/devmine/inventory/blocks/Fallable.php b/src/devmine/inventory/blocks/Fallable.php index da85389..ce20318 100644 --- a/src/devmine/inventory/blocks/Fallable.php +++ b/src/devmine/inventory/blocks/Fallable.php @@ -5,8 +5,7 @@ namespace devmine\inventory\blocks; use devmine\creatures\entities\Entity; -use devmine\inventory\items\Item; -use devmine\levels\Level; +use devmine\worlds\Level; use devmine\server\calculations\Vector3; use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\CompoundTag; @@ -14,16 +13,9 @@ use devmine\creatures\player\tag\ListTag; use devmine\creatures\player\tag\FloatTag; use devmine\creatures\player\tag\IntTag; -use devmine\Player; abstract class Fallable extends Solid{ - public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ - $ret = $this->getLevel()->setBlock($this, $this, true, true); - - return $ret; - } - public function onUpdate($type){ if($type === Level::BLOCK_UPDATE_NORMAL){ $down = $this->getSide(Vector3::SIDE_DOWN); @@ -43,7 +35,7 @@ public function onUpdate($type){ new FloatTag("", 0), new FloatTag("", 0) ]), - "solidentityID" => new IntTag("solidentityID", $this->getId()), + "TileID" => new IntTag("TileID", $this->getId()), "Data" => new ByteTag("Data", $this->getDamage()), ])); diff --git a/src/devmine/inventory/blocks/FenceGate.php b/src/devmine/inventory/blocks/FenceGate.php index b67dead..eec5e81 100644 --- a/src/devmine/inventory/blocks/FenceGate.php +++ b/src/devmine/inventory/blocks/FenceGate.php @@ -7,8 +7,8 @@ use devmine\inventory\items\Item; use devmine\inventory\items\Tool; use devmine\server\calculations\AxisAlignedBB; -use devmine\Player; -use devmine\levels\sound\DoorSound; +use devmine\creatures\player; +use devmine\worlds\sound\DoorSound; class FenceGate extends Transparent implements ElectricalAppliance{ diff --git a/src/devmine/inventory/blocks/Fire.php b/src/devmine/inventory/blocks/Fire.php index a8efe8a..ec09060 100644 --- a/src/devmine/inventory/blocks/Fire.php +++ b/src/devmine/inventory/blocks/Fire.php @@ -7,14 +7,14 @@ use devmine\creatures\entities\Arrow; use devmine\creatures\entities\Effect; use devmine\creatures\entities\Entity; -use devmine\server\events\block\BlockBurnEvent; -use devmine\server\events\entity\EntityCombustByBlockEvent; -use devmine\server\events\entity\EntityDamageByBlockEvent; -use devmine\server\events\entity\EntityDamageEvent; +use devmine\events\block\BlockBurnEvent; +use devmine\events\entity\EntityCombustByBlockEvent; +use devmine\events\entity\EntityDamageByBlockEvent; +use devmine\events\entity\EntityDamageEvent; use devmine\inventory\items\Item; -use devmine\levels\Level; +use devmine\worlds\Level; use devmine\server\calculations\Vector3; -use devmine\Server; +use devmine\server\server; class Fire extends Flowable{ diff --git a/src/devmine/inventory/blocks/Flower.php b/src/devmine/inventory/blocks/Flower.php index a952d24..e75cd8b 100644 --- a/src/devmine/inventory/blocks/Flower.php +++ b/src/devmine/inventory/blocks/Flower.php @@ -5,9 +5,9 @@ namespace devmine\inventory\blocks; use devmine\inventory\items\Item; -use devmine\levels\Level; +use devmine\worlds\Level; use devmine\server\calculations\Vector3; -use devmine\Player; +use devmine\creatures\player; class Flower extends Flowable{ const TYPE_POPPY = 0; diff --git a/src/devmine/inventory/blocks/FlowerPot.php b/src/devmine/inventory/blocks/FlowerPot.php index 7348b0f..055d7b5 100644 --- a/src/devmine/inventory/blocks/FlowerPot.php +++ b/src/devmine/inventory/blocks/FlowerPot.php @@ -1,42 +1,41 @@ meta = $meta; } - public function canBeActivated() : bool { - return true; - } - public function getName() : string{ return "Flower Pot Block"; } - public function getBoundingBox(){ + public function canBeActivated(): bool{ + return true; + } + + protected function recalculateBoundingBox(){ return new AxisAlignedBB( $this->x + 0.3125, $this->y, @@ -48,78 +47,74 @@ public function getBoundingBox(){ } public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ - if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() === false){ - $this->getLevel()->setBlock($block, $this, true, true); - $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::FLOWER_POT), - new IntTag("x", $block->x), - new IntTag("y", $block->y), - new IntTag("z", $block->z), - new ShortTag("item", 0), - new IntTag("data", 0), - ]); - - if($item->hasCustomBlockData()){ - foreach($item->getCustomBlockData() as $key => $v){ - $nbt->{$key} = $v; - } - } - - $pot = solidentity::createsolidentity("FlowerPot", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); - return true; + if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ + return false; } - return false; - } - public function onActivate(Item $item, Player $player = null){ - $solidentity = $this->getLevel()->getsolidentity($this); - if($solidentity instanceof FlowerPotsolidentity){ - if($solidentity->getFlowerPotItem() === Item::AIR){ - switch($item->getId()){ - case Item::TALL_GRASS: - if($item->getDamage() === 1){ - break; - } - case Item::SAPLING: - case Item::DEAD_BUSH: - case Item::DANDELION: - case Item::RED_FLOWER: - case Item::BROWN_MUSHROOM: - case Item::RED_MUSHROOM: - case Item::CACTUS: - $solidentity->setFlowerPotData($item->getId(), $item->getDamage()); - $this->setDamage($item->getId()); - $this->getLevel()->setBlock($this, $this, true, false); - if($player->isSurvival()){ - $item->setCount($item->getCount() - 1); - $player->getInventory()->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR)); - } - return true; - break; - } + $this->getLevel()->setBlock($block, $this, true, true); + + $nbt = new CompoundTag("", [ + new StringTag("id", Tile::FLOWER_POT), + new IntTag("x", $block->x), + new IntTag("y", $block->y), + new IntTag("z", $block->z), + new ShortTag("item", 0), + new IntTag("mData", 0), + ]); + + if($item->hasCustomBlockData()){ + foreach($item->getCustomBlockData() as $key => $v){ + $nbt->{$key} = $v; } } - return false; + + Tile::createTile(Tile::FLOWER_POT, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + return true; } public function onUpdate($type){ if($type === Level::BLOCK_UPDATE_NORMAL){ - if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){ + if($this->getSide(0)->isTransparent() === true){ $this->getLevel()->useBreakOn($this); + return Level::BLOCK_UPDATE_NORMAL; } } + return false; } - public function getDrops(Item $item) : array { - $items = array([Item::FLOWER_POT, 0, 1]); - /** @var FlowerPotsolidentity $solidentity */ - if($this->getLevel()!=null && (($solidentity = $this->getLevel()->getsolidentity($this)) instanceof FlowerPotsolidentity)){ - if($solidentity->getFlowerPotItem() !== Item::AIR){ - $items[] = array($solidentity->getFlowerPotItem(), $solidentity->getFlowerPotData(), 1); + public function onActivate(Item $item, Player $player = null){ + $pot = $this->getLevel()->getTile($this); + if(!($pot instanceof TileFlowerPot)){ + return false; + } + if(!$pot->canAddItem($item)){ + return true; + } + + $this->setDamage(self::STATE_FULL); //specific damage value is unnecessary, it just needs to be non-zero to show an item. + $this->getLevel()->setBlock($this, $this, true, false); + $pot->setItem($item); + + if($player instanceof Player){ + if($player->isSurvival()){ + $item->setCount($item->getCount() - 1); + $player->getInventory()->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR)); + } + } + return true; + } + + public function getDrops(Item $item) : array{ + $items = [[Item::FLOWER_POT, 0, 1]]; + $tile = $this->getLevel()->getTile($this); + if($tile instanceof TileFlowerPot){ + if(($item = $tile->getItem())->getId() !== Item::AIR){ + $items[] = [$item->getId(), $item->getDamage(), 1]; } } return $items; } + } diff --git a/src/devmine/inventory/blocks/Furnace.php b/src/devmine/inventory/blocks/Furnace.php index 762d930..44d922a 100644 --- a/src/devmine/inventory/blocks/Furnace.php +++ b/src/devmine/inventory/blocks/Furnace.php @@ -4,12 +4,114 @@ namespace devmine\inventory\blocks; +use devmine\inventory\items\Item; +use devmine\creatures\player\NBT; +use devmine\creatures\player\tag\CompoundTag; +use devmine\creatures\player\tag\ListTag; +use devmine\creatures\player\tag\IntTag; +use devmine\creatures\player\tag\StringTag; +use devmine\creatures\player; +use devmine\inventory\solidentity\Furnace as FurnaceTile; +use devmine\inventory\solidentity\Tile; -class Furnace extends BurningFurnace{ +class Furnace extends Solid{ protected $id = self::FURNACE; + public function __construct($meta = 0){ + $this->meta = $meta; + } + public function getName() : string{ return "Furnace"; } + + public function canBeActivated() : bool { + return true; + } + + public function getHardness() { + return 3.5; + } + + public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ + $faces = [ + 0 => 4, + 1 => 2, + 2 => 5, + 3 => 3, + ]; + $this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0]; + $this->getLevel()->setBlock($block, $this, true, true); + $nbt = new CompoundTag("", [ + new ListTag("Items", []), + new StringTag("id", Tile::FURNACE), + new IntTag("x", $this->x), + new IntTag("y", $this->y), + new IntTag("z", $this->z) + ]); + $nbt->Items->setTagType(NBT::TAG_Compound); + + if($item->hasCustomName()){ + $nbt->CustomName = new StringTag("CustomName", $item->getCustomName()); + } + + if($item->hasCustomBlockData()){ + foreach($item->getCustomBlockData() as $key => $v){ + $nbt->{$key} = $v; + } + } + + Tile::createTile("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + + return true; + } + + public function onBreak(Item $item){ + $this->getLevel()->setBlock($this, new Air(), true, true); + + return true; + } + + public function onActivate(Item $item, Player $player = null){ + if($player instanceof Player){ + $t = $this->getLevel()->getTile($this); + if($t instanceof FurnaceTile){ + $furnace = $t; + }else{ + $nbt = new CompoundTag("", [ + new ListTag("Items", []), + new StringTag("id", Tile::FURNACE), + new IntTag("x", $this->x), + new IntTag("y", $this->y), + new IntTag("z", $this->z) + ]); + $nbt->Items->setTagType(NBT::TAG_Compound); + $furnace = Tile::createTile("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + } + + if(isset($furnace->namedtag->Lock) and $furnace->namedtag->Lock instanceof StringTag){ + if($furnace->namedtag->Lock->getValue() !== $item->getCustomName()){ + return true; + } + } + + if($player->isCreative() and $player->getServer()->limitedCreative){ + return true; + } + + $player->addWindow($furnace->getInventory()); + } + + return true; + } + + public function getDrops(Item $item) : array { + $drops = []; + if($item->isPickaxe() >= 1){ + $drops[] = [Item::FURNACE, 0, 1]; + } + + return $drops; + } } \ No newline at end of file diff --git a/src/devmine/inventory/blocks/GlowingObsidian.php b/src/devmine/inventory/blocks/GlowingObsidian.php index 47884fa..f2de55d 100644 --- a/src/devmine/inventory/blocks/GlowingObsidian.php +++ b/src/devmine/inventory/blocks/GlowingObsidian.php @@ -5,7 +5,7 @@ namespace devmine\inventory\blocks; -class GlowingObsidian extends Transparent{ +class GlowingObsidian extends Solid implements SolidLight{ protected $id = self::GLOWING_OBSIDIAN; diff --git a/src/devmine/inventory/blocks/GlowingRedstoneOre.php b/src/devmine/inventory/blocks/GlowingRedstoneOre.php index b6b7f83..9b552f9 100644 --- a/src/devmine/inventory/blocks/GlowingRedstoneOre.php +++ b/src/devmine/inventory/blocks/GlowingRedstoneOre.php @@ -5,9 +5,9 @@ namespace devmine\inventory\blocks; use devmine\inventory\items\Item; -use devmine\levels\Level; +use devmine\worlds\Level; -class GlowingRedstoneOre extends RedstoneOre{ +class GlowingRedstoneOre extends RedstoneOre implements SolidLight{ protected $id = self::GLOWING_REDSTONE_ORE; diff --git a/src/devmine/inventory/blocks/Glowstone.php b/src/devmine/inventory/blocks/Glowstone.php index 2fcf92b..bc6dd8c 100644 --- a/src/devmine/inventory/blocks/Glowstone.php +++ b/src/devmine/inventory/blocks/Glowstone.php @@ -8,7 +8,7 @@ use devmine\inventory\items\Tool; use devmine\inventory\items\enchantment\enchantment; -class Glowstone extends Transparent{ +class Glowstone extends Transparent implements SolidLight{ protected $id = self::GLOWSTONE_BLOCK; @@ -38,10 +38,10 @@ public function getDrops(Item $item) : array { [Item::GLOWSTONE_BLOCK, 0, 1], ]; }else{ - $fortunel = $item->getEnchantmentLevel(Enchantment::TYPE_MINING_FORTUNE); - $fortunel = $fortunel > 3 ? 3 : $fortunel; + $fortuneL = $item->getEnchantmentLevel(Enchantment::TYPE_MINING_FORTUNE); + $fortuneL = $fortuneL > 3 ? 3 : $fortuneL; $times = [1,1,2,3,4]; - $time = $times[mt_rand(0, $fortunel + 1)]; + $time = $times[mt_rand(0, $fortuneL + 1)]; $num = mt_rand(2, 4) * $time; $num = $num > 4 ? 4 : $num; return [ diff --git a/src/devmine/inventory/blocks/Grass.php b/src/devmine/inventory/blocks/Grass.php index 3edd795..bbc5b3b 100644 --- a/src/devmine/inventory/blocks/Grass.php +++ b/src/devmine/inventory/blocks/Grass.php @@ -4,15 +4,15 @@ namespace devmine\inventory\blocks; -use devmine\server\events\block\BlockSpreadEvent; +use devmine\events\block\BlockSpreadEvent; use devmine\inventory\items\Item; use devmine\inventory\items\Tool; use devmine\inventory\items\enchantment\enchantment; -use devmine\levels\generator\object\TallGrass as TallGrassObject; -use devmine\levels\Level; +use devmine\worlds\generator\object\TallGrass as TallGrassObject; +use devmine\worlds\Level; use devmine\server\calculations\Vector3; -use devmine\Player; -use devmine\Server; +use devmine\creatures\player; +use devmine\server\server; use devmine\utilities\main\Random; class Grass extends Solid{ diff --git a/src/devmine/inventory/blocks/GrassPath.php b/src/devmine/inventory/blocks/GrassPath.php index 7702cc4..1585534 100644 --- a/src/devmine/inventory/blocks/GrassPath.php +++ b/src/devmine/inventory/blocks/GrassPath.php @@ -10,7 +10,7 @@ use devmine\inventory\items\enchantment\enchantment; -use devmine\levels\Level; +use devmine\worlds\Level; use devmine\server\calculations\AxisAlignedBB; diff --git a/src/devmine/inventory/blocks/HayBale.php b/src/devmine/inventory/blocks/HayBale.php index 7ee0bd6..259f822 100644 --- a/src/devmine/inventory/blocks/HayBale.php +++ b/src/devmine/inventory/blocks/HayBale.php @@ -5,7 +5,7 @@ namespace devmine\inventory\blocks; use devmine\inventory\items\Item; -use devmine\Player; +use devmine\creatures\player; class HayBale extends Solid{ diff --git a/src/devmine/inventory/blocks/HeavyWeightedPressurePlate.php b/src/devmine/inventory/blocks/HeavyWeightedPressurePlate.php index 20970b3..4abd133 100644 --- a/src/devmine/inventory/blocks/HeavyWeightedPressurePlate.php +++ b/src/devmine/inventory/blocks/HeavyWeightedPressurePlate.php @@ -1,6 +1,23 @@ meta = $meta; + } + + public function canBeActivated(): bool{ + return true; + } + + public function getToolType(){ + return Tool::TYPE_PICKAXE; + } + + public function getName() : string{ + return "Hopper"; + } + + public function getHardness(){ + return 3; + } + + public function onActivate(Item $item, Player $player = null){ + if($player instanceof Player){ + $t = $this->getLevel()->getTile($this); + if($t instanceof TileHopper){ + if($t->hasLock() and !$t->checkLock($item->getCustomName())){ + $player->getServer()->getLogger()->debug($player->getName() . " attempted to open a locked hopper"); + return true; + } + $player->addWindow($t->getInventory()); + } + } + return true; + } + + public function activate(){ + //TODO: Hopper content freezing (requires basic redstone system upgrade) + } + + public function getTarget(){ + return $this->target; + } + + public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ + $faces = [ + 0 => 0, + 1 => 0, + 2 => 3, + 3 => 2, + 4 => 5, + 5 => 4 + ]; + $this->meta = $faces[$face]; + $this->getLevel()->setBlock($block, $this, true, true); + + $nbt = new CompoundTag("", [ + new ListTag("Items", []), + new StringTag("id", Tile::HOPPER), + new IntTag("x", $this->x), + new IntTag("y", $this->y), + new IntTag("z", $this->z) + ]); + $nbt->Items->setTagType(NBT::TAG_Compound); + + if($item->hasCustomName()){ + $nbt->CustomName = new StringTag("CustomName", $item->getCustomName()); + } + + if($item->hasCustomBlockData()){ + foreach($item->getCustomBlockData() as $key => $v){ + $nbt->{$key} = $v; + } + } + + $t = Tile::createTile(Tile::HOPPER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + + return true; + } + + public function getDrops(Item $item) : array { + if($item->isPickaxe() >= 1){ + return [ + [Item::HOPPER, 0, 1], + ]; + }else{ + return []; + } + } +} \ No newline at end of file diff --git a/src/devmine/inventory/blocks/InactiveRedstoneLamp.php b/src/devmine/inventory/blocks/InactiveRedstoneLamp.php index 982ac37..33ad9b4 100644 --- a/src/devmine/inventory/blocks/InactiveRedstoneLamp.php +++ b/src/devmine/inventory/blocks/InactiveRedstoneLamp.php @@ -1,6 +1,23 @@ getLevel()->setBlock($this, new ActiveRedstoneLamp(), true, false); + $this->getLevel()->setBlock($this, new ActiveRedstoneLamp(), true, true); /*}else{ $this->getLevel()->setBlock($this, new ActiveRedstoneLamp(), true, false); //$this->lightAround(); @@ -32,4 +49,4 @@ public function turnOn(){ public function turnOff(){ return true; } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/blocks/InvisibleBedrock.php b/src/devmine/inventory/blocks/InvisibleBedrock.php new file mode 100644 index 0000000..bf851a2 --- /dev/null +++ b/src/devmine/inventory/blocks/InvisibleBedrock.php @@ -0,0 +1,33 @@ +getLevel()->getsolidentity($this); - if(!$solidentity instanceof ItemFramesolidentity){ + $tile = $this->getLevel()->getTile($this); + if(!($tile instanceof ItemFrameTile)){ $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::ITEM_FRAME), + new StringTag("id", Tile::ITEM_FRAME), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z), new ByteTag("ItemRotation", 0), new FloatTag("ItemDropChance", 1.0) ]); - solidentity::createsolidentity(solidentity::ITEM_FRAME, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + $tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); } - if($solidentity->getItem()->getId() === 0){ - $solidentity->setItem(Item::get($item->getId(), $item->getDamage(), 1)); + if($tile->getItem()->getId() === 0){ + $item = clone $item; + $item->setCount(1); + $tile->setItem($item); if($player instanceof Player){ if($player->isSurvival()) { $count = $item->getCount(); @@ -58,10 +77,10 @@ public function onActivate(Item $item, Player $player = null){ } } }else{ - $itemRot = $solidentity->getItemRotation(); + $itemRot = $tile->getItemRotation(); if($itemRot === 7) $itemRot = 0; else $itemRot++; - $solidentity->setItemRotation($itemRot); + $tile->setItemRotation($itemRot); } return true; @@ -75,17 +94,17 @@ public function getDrops(Item $item) : array{ if($this->getLevel()==null){ return []; } - $solidentity = $this->getLevel()->getsolidentity($this); - if(!$solidentity instanceof ItemFramesolidentity){ + $tile = $this->getLevel()->getTile($this); + if(!$tile instanceof ItemFrameTile){ return [ [Item::ITEM_FRAME, 0, 1] ]; } $chance = mt_rand(0, 100); - if($chance <= ($solidentity->getItemDropChance() * 100)){ + if($chance <= ($tile->getItemDropChance() * 100)){ return [ [Item::ITEM_FRAME, 0 ,1], - [$solidentity->getItem()->getId(), $solidentity->getItem()->getDamage(), 1] + [$tile->getItem()->getId(), $tile->getItem()->getDamage(), 1] ]; } return [ @@ -104,7 +123,7 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $this->meta = $faces[$face]; $this->getLevel()->setBlock($block, $this, true, true); $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::ITEM_FRAME), + new StringTag("id", Tile::ITEM_FRAME), new IntTag("x", $block->x), new IntTag("y", $block->y), new IntTag("z", $block->z), @@ -118,9 +137,9 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } } - solidentity::createsolidentity(solidentity::ITEM_FRAME, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + Tile::createTile(Tile::ITEM_FRAME, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); return true; } return false; } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/blocks/JungleWoodStairs.php b/src/devmine/inventory/blocks/JungleWoodStairs.php index ad9801f..ac555ae 100644 --- a/src/devmine/inventory/blocks/JungleWoodStairs.php +++ b/src/devmine/inventory/blocks/JungleWoodStairs.php @@ -4,28 +4,11 @@ namespace devmine\inventory\blocks; -use devmine\inventory\items\Item; -use devmine\inventory\items\Tool; - -class JungleWoodStairs extends Stair{ +class JungleWoodStairs extends WoodStairs{ protected $id = self::JUNGLE_WOOD_STAIRS; - public function __construct($meta = 0){ - $this->meta = $meta; - } - public function getName() : string{ return "Jungle Wood Stairs"; } - - public function getToolType(){ - return Tool::TYPE_AXE; - } - - public function getDrops(Item $item) : array { - return [ - [$this->id, 0, 1], - ]; - } } \ No newline at end of file diff --git a/src/devmine/inventory/blocks/Ladder.php b/src/devmine/inventory/blocks/Ladder.php index 7d807fa..d3c3847 100644 --- a/src/devmine/inventory/blocks/Ladder.php +++ b/src/devmine/inventory/blocks/Ladder.php @@ -7,9 +7,9 @@ use devmine\creatures\entities\Entity; use devmine\inventory\items\Item; use devmine\inventory\items\Tool; -use devmine\levels\Level; +use devmine\worlds\Level; use devmine\server\calculations\AxisAlignedBB; -use devmine\Player; +use devmine\creatures\player; class Ladder extends Transparent{ @@ -42,7 +42,7 @@ public function onEntityCollide(Entity $entity){ protected function recalculateBoundingBox() { - $f = 0.125; + $f = 0.1875; if($this->meta === 2){ return new AxisAlignedBB( @@ -106,25 +106,18 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } public function onUpdate($type){ + if($type === Level::BLOCK_UPDATE_NORMAL){ $faces = [ 2 => 3, 3 => 2, 4 => 5, 5 => 4, ]; - /*if($this->getSide(0)->getId() === self::AIR){ //Replace with common break method - Server::getInstance()->api->entity->drop($this, Item::get(LADDER, 0, 1)); - $this->getLevel()->setBlock($this, new Air(), true, true, true); - return Level::BLOCK_UPDATE_NORMAL; - }*/ - if($type === Level::BLOCK_UPDATE_NORMAL){ - if(isset($faces[$this->meta])) { - if ($this->getSide($faces[$this->meta])->getId() === self::AIR) { + if (!$this->getSide($faces[$this->meta])->isSolid()){//replace with common break method $this->getLevel()->useBreakOn($this); - } return Level::BLOCK_UPDATE_NORMAL; + } } - } return false; } diff --git a/src/devmine/inventory/blocks/Lava.php b/src/devmine/inventory/blocks/Lava.php index 8b97561..0ddf0d1 100644 --- a/src/devmine/inventory/blocks/Lava.php +++ b/src/devmine/inventory/blocks/Lava.php @@ -6,12 +6,12 @@ use devmine\creatures\entities\Effect; use devmine\creatures\entities\Entity; -use devmine\server\events\entity\EntityCombustByBlockEvent; -use devmine\server\events\entity\EntityDamageByBlockEvent; -use devmine\server\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityCombustByBlockEvent; +use devmine\events\entity\EntityDamageByBlockEvent; +use devmine\events\entity\EntityDamageEvent; use devmine\inventory\items\Item; -use devmine\Player; -use devmine\Server; +use devmine\creatures\player; +use devmine\server\server; class Lava extends Liquid{ diff --git a/src/devmine/inventory/blocks/Leaves.php b/src/devmine/inventory/blocks/Leaves.php index 1a84cb5..643e870 100644 --- a/src/devmine/inventory/blocks/Leaves.php +++ b/src/devmine/inventory/blocks/Leaves.php @@ -4,14 +4,14 @@ namespace devmine\inventory\blocks; -use devmine\server\events\block\LeavesDecayEvent; +use devmine\events\block\LeavesDecayEvent; use devmine\inventory\items\Item; use devmine\inventory\items\Tool; use devmine\inventory\items\Dye; use devmine\inventory\items\enchantment\enchantment; -use devmine\levels\Level; -use devmine\Player; -use devmine\Server; +use devmine\worlds\Level; +use devmine\creatures\player; +use devmine\server\server; class Leaves extends Transparent{ const OAK = 0; @@ -20,6 +20,8 @@ class Leaves extends Transparent{ const JUNGLE = 3; const ACACIA = 0; const DARK_OAK = 1; + + const WOOD_TYPE = self::WOOD; protected $id = self::LEAVES; @@ -59,12 +61,12 @@ private function findLog(Block $pos, array $visited, $distance, &$check, $fromSi if(isset($visited[$index])){ return false; } - if($pos->getId() === self::WOOD){ + if($pos->getId() === static::WOOD_TYPE){ return true; - }elseif($pos->getId() === self::LEAVES and $distance < 3){ + }elseif($pos->getId() === $this->id and $distance < 3){ $visited[$index] = true; $down = $pos->getSide(0)->getId(); - if($down === Item::WOOD){ + if($down === static::WOOD_TYPE){ return true; } if($fromSide === null){ @@ -122,7 +124,7 @@ public function onUpdate($type){ if($type === Level::BLOCK_UPDATE_NORMAL){ if(($this->meta & 0b00001100) === 0){ $this->meta |= 0x08; - $this->getLevel()->setBlock($this, $this, false, false, true); + $this->getLevel()->setBlock($this, $this, true, false); } }elseif($type === Level::BLOCK_UPDATE_RANDOM){ if(($this->meta & 0b00001100) === 0x08){ @@ -153,10 +155,10 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, public function getDrops(Item $item) : array { $drops = []; if($item->isShears() or $item->getEnchantmentLevel(Enchantment::TYPE_MINING_SILK_TOUCH) > 0){ - $drops[] = [Item::LEAVES, $this->meta & 0x03, 1]; + $drops[] = [$this->id, $this->meta & 0x03, 1]; }else{ $fortunel = $item->getEnchantmentLevel(Enchantment::TYPE_MINING_FORTUNE); - $fortunel = $fortunel > 3 ? 3 : $fortunel; + $fortunel = min(3, $fortunel); $rates = [20,16,12,10]; if(mt_rand(1, $rates[$fortunel]) === 1){ //Saplings $drops[] = [Item::SAPLING, $this->meta & 0x03, 1]; diff --git a/src/devmine/inventory/blocks/Leaves2.php b/src/devmine/inventory/blocks/Leaves2.php index d24b18f..94720b6 100644 --- a/src/devmine/inventory/blocks/Leaves2.php +++ b/src/devmine/inventory/blocks/Leaves2.php @@ -4,15 +4,17 @@ namespace devmine\inventory\blocks; -use devmine\server\events\block\LeavesDecayEvent; +use devmine\events\block\LeavesDecayEvent; use devmine\inventory\items\Item; use devmine\inventory\items\enchantment\enchantment; -use devmine\levels\Level; -use devmine\Player; -use devmine\Server; +use devmine\worlds\Level; +use devmine\creatures\player; +use devmine\server\server; class Leaves2 extends Leaves{ + const WOOD_TYPE = self::WOOD2; + protected $id = self::LEAVES2; public function __construct($meta = 0){ @@ -27,113 +29,16 @@ public function getName() : string{ return $names[$this->meta & 0x01]; } - private function findLog(Block $pos, array $visited, $distance, &$check, $fromSide = null){ - ++$check; - $index = $pos->x . "." . $pos->y . "." . $pos->z; - if(isset($visited[$index])){ - return false; - } - if($pos->getId() === self::WOOD2){ - return true; - }elseif($pos->getId() === self::LEAVES2 and $distance < 3){ - $visited[$index] = true; - $down = $pos->getSide(0)->getId(); - if($down === Item::WOOD2){ - return true; - } - if($fromSide === null){ - for($side = 2; $side <= 5; ++$side){ - if($this->findLog($pos->getSide($side), $visited, $distance + 1, $check, $side) === true){ - return true; - } - } - }else{ //No more loops - switch($fromSide){ - case 2: - if($this->findLog($pos->getSide(2), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - }elseif($this->findLog($pos->getSide(4), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - }elseif($this->findLog($pos->getSide(5), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - } - break; - case 3: - if($this->findLog($pos->getSide(3), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - }elseif($this->findLog($pos->getSide(4), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - }elseif($this->findLog($pos->getSide(5), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - } - break; - case 4: - if($this->findLog($pos->getSide(2), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - }elseif($this->findLog($pos->getSide(3), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - }elseif($this->findLog($pos->getSide(4), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - } - break; - case 5: - if($this->findLog($pos->getSide(2), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - }elseif($this->findLog($pos->getSide(3), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - }elseif($this->findLog($pos->getSide(5), $visited, $distance + 1, $check, $fromSide) === true){ - return true; - } - break; - } - } - } - - return false; - } - - public function onUpdate($type){ - if($type === Level::BLOCK_UPDATE_NORMAL){ - if(($this->meta & 0b00001100) === 0){ - $this->meta |= 0x08; - $this->getLevel()->setBlock($this, $this, false, false, true); - } - }elseif($type === Level::BLOCK_UPDATE_RANDOM){ - if(($this->meta & 0b00001100) === 0x08){ - $this->meta &= 0x03; - $visited = []; - $check = 0; - - Server::getInstance()->getPluginManager()->callEvent($ev = new LeavesDecayEvent($this)); - - if($ev->isCancelled() or $this->findLog($this, $visited, 0, $check) === true){ - $this->getLevel()->setBlock($this, $this, false, false); - }else{ - $this->getLevel()->useBreakOn($this); - - return Level::BLOCK_UPDATE_NORMAL; - } - } - } - - return false; - } - - public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ - $this->meta |= 0x04; - $this->getLevel()->setBlock($this, $this, true); - } - public function getDrops(Item $item) : array { $drops = []; if($item->isShears() or $item->getEnchantmentLevel(Enchantment::TYPE_MINING_SILK_TOUCH) > 0){ - $drops[] = [Item::LEAVES2, $this->meta & 0x03, 1]; + $drops[] = [$this->id, $this->meta & 0x01, 1]; }else{ $fortunel = $item->getEnchantmentLevel(Enchantment::TYPE_MINING_FORTUNE); - $fortunel = $fortunel > 3 ? 3 : $fortunel; + $fortunel = min(3, $fortunel); $rates = [20,16,12,10]; if(mt_rand(1, $rates[$fortunel]) === 1){ //Saplings - $drops[] = [Item::SAPLING, $this->meta & 0x03, 1]; + $drops[] = [Item::SAPLING, ($this->meta & 0x01) | 0x04, 1]; } } diff --git a/src/devmine/inventory/blocks/Lever.php b/src/devmine/inventory/blocks/Lever.php index e870b1e..a80174e 100644 --- a/src/devmine/inventory/blocks/Lever.php +++ b/src/devmine/inventory/blocks/Lever.php @@ -1,13 +1,30 @@ getDamage() == 0){ if($item->getId() == Item::SPAWN_EGG){ - $solidentity = $this->getLevel()->getsolidentity($this); - if($solidentity instanceof MobSpawner){ + $tile = $this->getLevel()->getTile($this); + if($tile instanceof MobSpawner){ $this->meta = $item->getDamage(); //$this->getLevel()->setBlock($this, $this, true, false); - $solidentity->setEntityId($this->meta); + $tile->setEntityId($this->meta); } return true; } @@ -73,7 +56,7 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $this->getLevel()->setBlock($block, $this, true, true); $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::MOB_SPAWNER), + new StringTag("id", Tile::MOB_SPAWNER), new IntTag("x", $block->x), new IntTag("y", $block->y), new IntTag("z", $block->z), @@ -86,7 +69,7 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } } - solidentity::createsolidentity(solidentity::MOB_SPAWNER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + Tile::createTile(Tile::MOB_SPAWNER, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); return true; } diff --git a/src/devmine/inventory/blocks/Mycelium.php b/src/devmine/inventory/blocks/Mycelium.php index 2daff49..483c32e 100644 --- a/src/devmine/inventory/blocks/Mycelium.php +++ b/src/devmine/inventory/blocks/Mycelium.php @@ -1,14 +1,16 @@ meta = $meta; } - + public function getBreakTime(Item $item){ - if ($item instanceof Air){ + if($item instanceof Air){ //Breaking by hand return 10; - } - else{ + }else{ // Other breaktimes are equal to woodfences. return parent::getBreakTime($item); } } - - public function getHardness() { + + public function getHardness(){ return 2; } - + public function getToolType(){ //Different then the woodfences return Tool::TYPE_PICKAXE; } - + public function getName() : string{ return "Nether Brick Fence"; } - + public function canConnect(Block $block){ - //TODO: activate comments when the NetherBrickFenceGate class has been created. - return ($block instanceof NetherBrickFence /* or $block instanceof NetherBrickFenceGate */) ? true : $block->isSolid() and !$block->isTransparent(); + return ($block instanceof NetherBrickFence) or ($block->isSolid() and !$block->isTransparent()); } - + public function getDrops(Item $item) : array { if($item->isPickaxe() >= Tool::TIER_WOODEN){ return [ @@ -51,4 +51,4 @@ public function getDrops(Item $item) : array { return []; } } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/blocks/NetherQuartzOre.php b/src/devmine/inventory/blocks/NetherQuartzOre.php index d022dcf..591a3bc 100644 --- a/src/devmine/inventory/blocks/NetherQuartzOre.php +++ b/src/devmine/inventory/blocks/NetherQuartzOre.php @@ -1,6 +1,23 @@ "Birch Wood Planks", self::JUNGLE => "Jungle Wood Planks", self::ACACIA => "Acacia Wood Planks", - self::DARK_OAK => "Jungle Wood Planks", - "", - "" + self::DARK_OAK => "Dark Oak Wood Planks", + 6 => "Unknown Planks", + 7 => "Unknown Planks" ]; return $names[$this->meta & 0x07]; } diff --git a/src/devmine/inventory/blocks/Portal.php b/src/devmine/inventory/blocks/Portal.php index 3f2857e..fa7a235 100644 --- a/src/devmine/inventory/blocks/Portal.php +++ b/src/devmine/inventory/blocks/Portal.php @@ -1,14 +1,29 @@ getLevel()->addSound($sound); - } - - for($num = 0;$num <= 10;$num++){ - $particle = new PortalParticle($this); - $this->getLevel()->addParticle($particle); - } - } - - return true; - } - - public function onBreak(Item $item) { - $sound = new EndermanTeleportSound($this); - $this->getLevel()->addSound($sound); - $particle = new PortalParticle($this); - $this->getLevel()->addParticle($particle); + public function onBreak(Item $item){ $block = $this; - //$this->getLevel()->setBlock($block, new Block(Block::PORTAL, 0));//在破坏处放置一个方块防止计算出错 if($this->getLevel()->getBlock($this->temporalVector->setComponents($block->x - 1, $block->y, $block->z))->getId() == Block::PORTAL or $this->getLevel()->getBlock($this->temporalVector->setComponents($block->x + 1, $block->y, $block->z))->getId() == Block::PORTAL){//x方向 for($x = $block->x;$this->getLevel()->getBlock($this->temporalVector->setComponents($x, $block->y, $block->z))->getId() == Block::PORTAL;$x++){ @@ -116,7 +106,7 @@ public function onBreak(Item $item) { public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ if($player instanceof Player){ - $this->meta = ((int) $player->getDirection() + 5) % 2; + $this->meta = $player->getDirection() & 0x01; } $this->getLevel()->setBlock($block, $this, true, true); @@ -124,12 +114,6 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } public function getDrops(Item $item) : array { - if($item->isPickaxe() >= 1){ - return [ - [Item::PORTAL, 0, 1], - ]; - }else{ - return []; - } + return []; } } \ No newline at end of file diff --git a/src/devmine/inventory/blocks/PoweredRail.php b/src/devmine/inventory/blocks/PoweredRail.php index 0cef24d..cb7cf8a 100644 --- a/src/devmine/inventory/blocks/PoweredRail.php +++ b/src/devmine/inventory/blocks/PoweredRail.php @@ -1,18 +1,29 @@ getLevel()->getServer()->redstoneEnabled and $this->canActivate){ if(!$this->isActivated()){ $this->meta = 1; $this->getLevel()->setBlock($this, $this, true, false); $this->getLevel()->addSound(new GenericSound($this, 1000)); } if(!$this->isActivated() or ($this->isActivated() and ($this->getLevel()->getServer()->getTick() % 30) == 0)){ - $this->activate(); - } + $this->activate(); } } diff --git a/src/devmine/inventory/blocks/PrismarineBlock.php b/src/devmine/inventory/blocks/PrismarineBlock.php new file mode 100644 index 0000000..c636e52 --- /dev/null +++ b/src/devmine/inventory/blocks/PrismarineBlock.php @@ -0,0 +1,44 @@ +meta = $meta; + } + + public function getName() : string{ + static $names = [ + 0 => "Prismarine Block", + 1 => "Dark Prismarine Block", + 2 => "Prismarine Bricks Block", + ]; + return $names[$this->meta & 0x0f]; + } + + public function getHardness(){ + return 1.5; + } + + public function getToolType(){ + return Tool::TYPE_PICKAXE; + } + + public function getDrops(Item $item) : array { + if($item->isPickaxe() >= Tool::TIER_WOODEN){ + return [ + [$this->id, $this->meta & 0x0f, 1], + ]; + }else{ + return []; + } + } +} \ No newline at end of file diff --git a/src/devmine/inventory/blocks/Pumpkin.php b/src/devmine/inventory/blocks/Pumpkin.php index eaf1c01..3d43759 100644 --- a/src/devmine/inventory/blocks/Pumpkin.php +++ b/src/devmine/inventory/blocks/Pumpkin.php @@ -1,24 +1,18 @@ meta = $meta; + } + + public function getHardness(){ + return 1.5; + } + + public function getToolType(){ + return Tool::TYPE_PICKAXE; + } + + public function getName() : string{ + static $names = [ + 0 => "Purpur Block", + 2 => "Purpur Pillar", + ]; + + return $names[$this->meta & 0x0f]; + } + + public function getDrops(Item $item) : array { + if($item->isPickaxe() >= Tool::TIER_WOODEN){ + + return [ + [$this->id, $this->meta & 0x0f, 1], + ]; + + }else{ + + return []; + + } + } + +} \ No newline at end of file diff --git a/src/devmine/inventory/blocks/PurpurStairs.php b/src/devmine/inventory/blocks/PurpurStairs.php new file mode 100644 index 0000000..7d60170 --- /dev/null +++ b/src/devmine/inventory/blocks/PurpurStairs.php @@ -0,0 +1,49 @@ +meta = $meta; + } + + public function getHardness(){ + return 1.5; + } + + public function getToolType(){ + return Tool::TYPE_PICKAXE; + } + + public function getName() : string{ + return "Purpur Stairs"; + } + +} \ No newline at end of file diff --git a/src/devmine/inventory/blocks/Quartz.php b/src/devmine/inventory/blocks/Quartz.php index f923480..70fc381 100644 --- a/src/devmine/inventory/blocks/Quartz.php +++ b/src/devmine/inventory/blocks/Quartz.php @@ -6,7 +6,7 @@ use devmine\inventory\items\Item; use devmine\inventory\items\Tool; -use devmine\Player; +use devmine\creatures\player; class Quartz extends Solid{ diff --git a/src/devmine/inventory/blocks/Rail.php b/src/devmine/inventory/blocks/Rail.php index ed137a3..ab4aed6 100644 --- a/src/devmine/inventory/blocks/Rail.php +++ b/src/devmine/inventory/blocks/Rail.php @@ -1,18 +1,44 @@ getEnchantmentLevel(Enchantment::TYPE_MINING_FORTUNE); - $fortunel = $fortunel > 3 ? 3 : $fortunel; + $fortuneL = $item->getEnchantmentLevel(Enchantment::TYPE_MINING_FORTUNE); + $fortuneL = $fortuneL > 3 ? 3 : $fortuneL; return [ - [Item::REDSTONE_DUST, 0, mt_rand(4, 5 + $fortunel)], + [Item::REDSTONE_DUST, 0, mt_rand(4, 5 + $fortuneL)], ]; } }else{ diff --git a/src/devmine/inventory/blocks/RedstoneSource.php b/src/devmine/inventory/blocks/RedstoneSource.php index 43822de..ba81d67 100644 --- a/src/devmine/inventory/blocks/RedstoneSource.php +++ b/src/devmine/inventory/blocks/RedstoneSource.php @@ -1,13 +1,30 @@ getLevel()->getServer()->redstoneEnabled; } public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ @@ -98,7 +114,6 @@ public function deactivateBlockWithoutWire(Block $block){ } public function activate(array $ignore = []){ - if($this->canCalc()){ $this->activated = true; /** @var Door $block */ @@ -111,10 +126,8 @@ public function activate(array $ignore = []){ } } } - } public function deactivate(array $ignore = []){ - if($this->canCalc()){ $this->activated = false; /** @var Door $block */ @@ -137,7 +150,7 @@ public function deactivate(array $ignore = []){ $block = $this->getSide(Vector3::SIDE_DOWN, 2); $this->deactivateBlock($block); } - } + } public function checkPower(Block $block, array $ignore = [], $ignoreWire = false){ diff --git a/src/devmine/inventory/blocks/RedstoneTorch.php b/src/devmine/inventory/blocks/RedstoneTorch.php index 86ad0be..505606b 100644 --- a/src/devmine/inventory/blocks/RedstoneTorch.php +++ b/src/devmine/inventory/blocks/RedstoneTorch.php @@ -1,12 +1,29 @@ meta = $meta; + } + + public function getLightLevel(){ + return 15; + } + + public function getName() : string{ + return "Sea Lantern Block"; + } + + public function getHardness(){ + return 0.3; + } + + public function getDrops(Item $item) : array { + return [ + [Item::PRISMARINE_CRYSTALS, 0, 3], + ]; + } + +} \ No newline at end of file diff --git a/src/devmine/inventory/blocks/SignPost.php b/src/devmine/inventory/blocks/SignPost.php index 72e341e..e40f8f1 100644 --- a/src/devmine/inventory/blocks/SignPost.php +++ b/src/devmine/inventory/blocks/SignPost.php @@ -6,8 +6,8 @@ use devmine\inventory\items\Item; use devmine\inventory\items\Tool; -use devmine\levels\Level; -use devmine\Player; +use devmine\worlds\Level; +use devmine\creatures\player; use devmine\server\calculations\Vector3; class SignPost extends Transparent{ diff --git a/src/devmine/inventory/blocks/SkullBlock.php b/src/devmine/inventory/blocks/SkullBlock.php index 6ae7fde..109448b 100644 --- a/src/devmine/inventory/blocks/SkullBlock.php +++ b/src/devmine/inventory/blocks/SkullBlock.php @@ -1,10 +1,27 @@ x), new IntTag("y", $block->y), new IntTag("z", $block->z), @@ -82,7 +99,7 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } $chunk = $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4); - $pot = solidentity::createsolidentity(solidentity::SKULL, $chunk, $nbt); + $pot = Tile::createTile(Tile::SKULL, $chunk, $nbt); $this->getLevel()->setBlock($block, Block::get(Block::SKULL_BLOCK, $face), true, true); return true; } @@ -114,9 +131,9 @@ public function onBreak(Item $item){ } public function getDrops(Item $item) : array { - /** @var Skull $solidentity */ - if($this->getLevel()!=null && (($solidentity = $this->getLevel()->getsolidentity($this)) instanceof Skull)){ - return [[Item::SKULL, $solidentity->getSkullType(), 1]]; + /** @var Skull $tile */ + if($this->getLevel()!=null && (($tile = $this->getLevel()->getTile($this)) instanceof Skull)){ + return [[Item::SKULL, $tile->getSkullType(), 1]]; }else return [[Item::SKULL, 0, 1]]; } diff --git a/src/devmine/inventory/blocks/Slab.php b/src/devmine/inventory/blocks/Slab.php index b0f9d17..9eb616a 100644 --- a/src/devmine/inventory/blocks/Slab.php +++ b/src/devmine/inventory/blocks/Slab.php @@ -7,7 +7,7 @@ use devmine\inventory\items\Item; use devmine\inventory\items\Tool; use devmine\server\calculations\AxisAlignedBB; -use devmine\Player; +use devmine\creatures\player; class Slab extends Transparent{ @@ -19,6 +19,7 @@ class Slab extends Transparent{ const STONE_BRICK = 5; const QUARTZ = 6; const NETHER_BRICK = 7; + const PURPUR_BLOCK = 8; protected $id = self::SLAB; @@ -39,7 +40,7 @@ public function getName() : string{ 4 => "Brick", 5 => "Stone Brick", 6 => "Quartz", - 7 => "", + 7 => "Purpur", ]; return (($this->meta & 0x08) > 0 ? "Upper " : "") . $names[$this->meta & 0x07] . " Slab"; } diff --git a/src/devmine/inventory/blocks/SlimeBlock.php b/src/devmine/inventory/blocks/SlimeBlock.php index d76351d..577c820 100644 --- a/src/devmine/inventory/blocks/SlimeBlock.php +++ b/src/devmine/inventory/blocks/SlimeBlock.php @@ -1,10 +1,28 @@ meta = $meta; } public function getHardness() { return 0.6; } + public function absorbWater($block = null){ + if ($block == null) $block = $this; + $range = $this->absorbRange / 2; + for ($xx = -$range; $xx <= $range; $xx++){ + for ($yy = -$range; $yy <= $range; $yy++){ + for ($zz = -$range; $zz <= $range; $zz++){ + $block = $this->getLevel()->getBlock(new Vector3($this->x + $xx, $this->y + $yy, $this->z + $zz)); + if ($block->getId() === Block::WATER) $this->getLevel()->setBlock($block, Block::get(Block::AIR), true, true); + if ($block->getId() === Block::STILL_WATER) $this->getLevel()->setBlock($block, Block::get(Block::AIR), true, true); + } + } + } + } + + public function onUpdate($type){ + if ($this->meta == 0) { + if($type === Level::BLOCK_UPDATE_NORMAL){ + $blockAbove = $this->getSide(Vector3::SIDE_UP)->getId(); + $blockBeneath = $this->getSide(Vector3::SIDE_DOWN)->getId(); + $blockNorth = $this->getSide(Vector3::SIDE_NORTH)->getId(); + $blockSouth = $this->getSide(Vector3::SIDE_SOUTH)->getId(); + $blockEast = $this->getSide(Vector3::SIDE_EAST)->getId(); + $blockWest = $this->getSide(Vector3::SIDE_WEST)->getId(); + + if($blockAbove === Block::WATER || + $blockBeneath === Block::WATER || + $blockNorth === Block::WATER || + $blockSouth === Block::WATER || + $blockEast === Block::WATER || + $blockWest === Block::WATER){ + $this->absorbWater($this); + $this->getLevel()->setBlock($this, Block::get(Block::SPONGE, 1), true, true); + return Level::BLOCK_UPDATE_NORMAL; + } + if($blockAbove === Block::STILL_WATER || + $blockBeneath === Block::STILL_WATER || + $blockNorth === Block::STILL_WATER || + $blockSouth === Block::STILL_WATER || + $blockEast === Block::STILL_WATER || + $blockWest === Block::STILL_WATER){ + $this->absorbWater($this); + $this->getLevel()->setBlock($this, Block::get(Block::SPONGE, 1), true, true); + return Level::BLOCK_UPDATE_NORMAL; + } + } + return false; + } + } + public function getName() : string{ - return "Sponge"; + static $names = [ + 0 => "Sponge", + 1 => "Wet Sponge", + ]; + return $names[$this->meta & 0x0f]; } -} \ No newline at end of file + public function getDrops(Item $item) : array { + return [ + [$this->id, $this->meta & 0x0f, 1], + ]; + } +} diff --git a/src/devmine/inventory/blocks/SpruceWoodStairs.php b/src/devmine/inventory/blocks/SpruceWoodStairs.php index 2cc6c70..078d772 100644 --- a/src/devmine/inventory/blocks/SpruceWoodStairs.php +++ b/src/devmine/inventory/blocks/SpruceWoodStairs.php @@ -4,28 +4,11 @@ namespace devmine\inventory\blocks; -use devmine\inventory\items\Item; -use devmine\inventory\items\Tool; - -class SpruceWoodStairs extends Stair{ +class SpruceWoodStairs extends WoodStairs{ protected $id = self::SPRUCE_WOOD_STAIRS; - public function __construct($meta = 0){ - $this->meta = $meta; - } - public function getName() : string{ return "Spruce Wood Stairs"; } - - public function getToolType(){ - return Tool::TYPE_AXE; - } - - public function getDrops(Item $item) : array { - return [ - [$this->id, 0, 1], - ]; - } } \ No newline at end of file diff --git a/src/devmine/inventory/blocks/Stair.php b/src/devmine/inventory/blocks/Stair.php index da11152..999f8b1 100644 --- a/src/devmine/inventory/blocks/Stair.php +++ b/src/devmine/inventory/blocks/Stair.php @@ -7,7 +7,7 @@ use devmine\inventory\items\Item; use devmine\inventory\items\Tool; use devmine\server\calculations\AxisAlignedBB; -use devmine\Player; +use devmine\creatures\player; abstract class Stair extends Transparent{ @@ -110,14 +110,6 @@ protected function recalculateBoundingBox() { } } - public function getBurnChance() : int{ - return 5; - } - - public function getBurnAbility() : int{ - return 20; - } - public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ $faces = [ 0 => 0, diff --git a/src/devmine/inventory/blocks/StillLava.php b/src/devmine/inventory/blocks/StillLava.php index 2c98bb2..dafe561 100644 --- a/src/devmine/inventory/blocks/StillLava.php +++ b/src/devmine/inventory/blocks/StillLava.php @@ -4,20 +4,21 @@ namespace devmine\inventory\blocks; -use devmine\levels\Level; +use devmine\worlds\Level; class StillLava extends Lava{ protected $id = self::STILL_LAVA; public function onUpdate($type){ - if($type == Level::BLOCK_UPDATE_NORMAL){ - parent::onUpdate($type); + if($type !== Level::BLOCK_UPDATE_SCHEDULED){ + return parent::onUpdate($type); } + return false; } public function getName() : string{ return "Still Lava"; } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/blocks/StillWater.php b/src/devmine/inventory/blocks/StillWater.php index ad4e5ef..961dbe8 100644 --- a/src/devmine/inventory/blocks/StillWater.php +++ b/src/devmine/inventory/blocks/StillWater.php @@ -4,19 +4,20 @@ namespace devmine\inventory\blocks; -use devmine\levels\Level; +use devmine\worlds\Level; class StillWater extends Water{ protected $id = self::STILL_WATER; public function onUpdate($type){ - if($type == Level::BLOCK_UPDATE_NORMAL){ - parent::onUpdate($type); + if($type !== Level::BLOCK_UPDATE_SCHEDULED){ + return parent::onUpdate($type); } + return false; } public function getName() : string{ return "Still Water"; } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/blocks/StoneButton.php b/src/devmine/inventory/blocks/StoneButton.php index d5a0dd8..8a2f408 100644 --- a/src/devmine/inventory/blocks/StoneButton.php +++ b/src/devmine/inventory/blocks/StoneButton.php @@ -1,12 +1,29 @@ getSide(0)->isTransparent() === true){ //Replace with common break method - $this->getLevel()->setBlock($this, new Air(), false, false); + $this->getLevel()->setBlock($this, new Air(), true, true); return Level::BLOCK_UPDATE_NORMAL; } diff --git a/src/devmine/inventory/blocks/Torch.php b/src/devmine/inventory/blocks/Torch.php index 9d4630d..38a3555 100644 --- a/src/devmine/inventory/blocks/Torch.php +++ b/src/devmine/inventory/blocks/Torch.php @@ -5,8 +5,8 @@ namespace devmine\inventory\blocks; use devmine\inventory\items\Item; -use devmine\levels\Level; -use devmine\Player; +use devmine\worlds\Level; +use devmine\creatures\player; class Torch extends Flowable{ diff --git a/src/devmine/inventory/blocks/Trapdoor.php b/src/devmine/inventory/blocks/Trapdoor.php index 8b1924c..361070b 100644 --- a/src/devmine/inventory/blocks/Trapdoor.php +++ b/src/devmine/inventory/blocks/Trapdoor.php @@ -7,8 +7,8 @@ use devmine\inventory\items\Item; use devmine\inventory\items\Tool; use devmine\server\calculations\AxisAlignedBB; -use devmine\Player; -use devmine\levels\sound\DoorSound; +use devmine\creatures\player; +use devmine\worlds\sound\DoorSound; class Trapdoor extends Transparent{ @@ -106,27 +106,20 @@ protected function recalculateBoundingBox() { } public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ - if(($target->isTransparent() === false or $target->getId() === self::SLAB) and $face !== 0 and $face !== 1){ - switch($face){ - case 2: - $this->meta |= 0b00000011; - break; - case 3: - $this->meta |= 0b00000010; - break; - case 4: - $this->meta |= 0b00000001; - break; - case 5: - break; - } - if($fy > 0.5){ - $this->meta |= 0b00000100; - } - $this->getLevel()->setBlock($block, $this, true, true); - return true; + $directions = [ + 0 => 1, + 1 => 3, + 2 => 0, + 3 => 2 + ]; + if($player !== null){ + $this->meta = $directions[$player->getDirection() & 0x03]; } - return false; + if(($fy > 0.5 and $face !== self::SIDE_UP) or $face === self::SIDE_DOWN){ + $this->meta |= 0b00000100; //top half of block + } + $this->getLevel()->setBlock($block, $this, true, true); + return true; } public function getDrops(Item $item) : array { diff --git a/src/devmine/inventory/blocks/TrappedChest.php b/src/devmine/inventory/blocks/TrappedChest.php index 2a48f62..def5a1f 100644 --- a/src/devmine/inventory/blocks/TrappedChest.php +++ b/src/devmine/inventory/blocks/TrappedChest.php @@ -1,6 +1,23 @@ getSide($side); if($c instanceof Chest and $c->getDamage() === $this->meta){ - $solidentity = $this->getLevel()->getsolidentity($c); - if($solidentity instanceof solidentityChest and !$solidentity->isPaired()){ - $chest = $solidentity; + $tile = $this->getLevel()->getTile($c); + if($tile instanceof TileChest and !$tile->isPaired()){ + $chest = $tile; break; } } @@ -99,7 +116,7 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $this->getLevel()->setBlock($block, $this, true, true); $nbt = new CompoundTag("", [ new ListTag("Items", []), - new StringTag("id", solidentity::CHEST), + new StringTag("id", Tile::CHEST), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) @@ -116,19 +133,19 @@ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, } } - $solidentity = solidentity::createsolidentity("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + $tile = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); - if($chest instanceof solidentityChest and $solidentity instanceof solidentityChest){ - $chest->pairWith($solidentity); - $solidentity->pairWith($chest); + if($chest instanceof TileChest and $tile instanceof TileChest){ + $chest->pairWith($tile); + $tile->pairWith($chest); } return true; } public function onBreak(Item $item){ - $t = $this->getLevel()->getsolidentity($this); - if($t instanceof solidentityChest){ + $t = $this->getLevel()->getTile($this); + if($t instanceof TileChest){ $t->unpair(); } $this->getLevel()->setBlock($this, new Air(), true, true); @@ -143,20 +160,20 @@ public function onActivate(Item $item, Player $player = null){ return true; } - $t = $this->getLevel()->getsolidentity($this); + $t = $this->getLevel()->getTile($this); $chest = null; - if($t instanceof solidentityChest){ + if($t instanceof TileChest){ $chest = $t; }else{ $nbt = new CompoundTag("", [ new ListTag("Items", []), - new StringTag("id", solidentity::CHEST), + new StringTag("id", Tile::CHEST), new IntTag("x", $this->x), new IntTag("y", $this->y), new IntTag("z", $this->z) ]); $nbt->Items->setTagType(NBT::TAG_Compound); - $chest = solidentity::createsolidentity("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); + $chest = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); } if(isset($chest->namedtag->Lock) and $chest->namedtag->Lock instanceof StringTag){ diff --git a/src/devmine/inventory/blocks/UnlitRedstoneTorch.php b/src/devmine/inventory/blocks/UnlitRedstoneTorch.php index 455db37..aae5c1e 100644 --- a/src/devmine/inventory/blocks/UnlitRedstoneTorch.php +++ b/src/devmine/inventory/blocks/UnlitRedstoneTorch.php @@ -1,6 +1,23 @@ getServer()->limitedCreative and $player->isCreative()) return true; - $player->craftingType = 1; + $player->craftingType = Player::CRAFTING_BIG; } return true; diff --git a/src/devmine/inventory/items/Armor.php b/src/devmine/inventory/items/Armor.php index 775aaca..dc32075 100644 --- a/src/devmine/inventory/items/Armor.php +++ b/src/devmine/inventory/items/Armor.php @@ -17,10 +17,10 @@ abstract class Armor extends Item{ const TIER_IRON = 4; const TIER_DIAMOND = 5; - const TYPE_HELMET = 1; - const TYPE_CHESTPLATE = 2; - const TYPE_LEGGINGS = 3; - const TYPE_BOOTS = 4; + const TYPE_HELMET = 0; + const TYPE_CHESTPLATE = 1; + const TYPE_LEGGINGS = 2; + const TYPE_BOOTS = 3; public function getMaxStackSize() : int { return 1; @@ -33,11 +33,11 @@ public function isArmor(){ /** * * @param Item $object + * @param int $cost * * @return bool */ - public function useOn($object) - { + public function useOn($object, int $cost = 1){ if($this->isUnbreakable()){ return true; } @@ -51,7 +51,7 @@ public function useOn($object) if(mt_rand(1, 100) > $unbreakings[$unbreakingl]){ return true; } - $this->setDamage($this->getDamage() + 1); + $this->setDamage($this->getDamage() + $cost); if($this->getDamage() >= $this->getMaxDurability()){ $this->setCount(0); } diff --git a/src/devmine/inventory/items/Arrow.php b/src/devmine/inventory/items/Arrow.php index d4771ae..84ec6d9 100644 --- a/src/devmine/inventory/items/Arrow.php +++ b/src/devmine/inventory/items/Arrow.php @@ -1,6 +1,23 @@ block = Block::get(Item::CAMERA); parent::__construct(self::CAMERA, 0, $count, "Camera"); } diff --git a/src/devmine/inventory/items/Cauldron.php b/src/devmine/inventory/items/Cauldron.php index 62a4efc..b78aee9 100644 --- a/src/devmine/inventory/items/Cauldron.php +++ b/src/devmine/inventory/items/Cauldron.php @@ -1,6 +1,23 @@ getViewers(), $pk); Server::getInstance()->getPluginManager()->callEvent($ev = new EntityEatItemEvent($human, $this)); - if(!$ev->isCancelled()){ - $human->addSaturation($ev->getSaturationRestore()); - $human->addFood($ev->getFoodRestore()); - foreach($ev->getAdditionalEffects() as $effect){ - $human->addEffect($effect); - } - $human->getInventory()->setItemInHand($ev->getResidue()); + + $human->addSaturation($ev->getSaturationRestore()); + $human->addFood($ev->getFoodRestore()); + foreach($ev->getAdditionalEffects() as $effect){ + $human->addEffect($effect); } - + + $human->getInventory()->setItemInHand($ev->getResidue()); } } diff --git a/src/devmine/inventory/items/GhastTear.php b/src/devmine/inventory/items/GhastTear.php new file mode 100644 index 0000000..fdfd0f7 --- /dev/null +++ b/src/devmine/inventory/items/GhastTear.php @@ -0,0 +1,11 @@ +block = Block::get(Block::HOPPER_BLOCK); + parent::__construct(self::HOPPER, 0, $count, "Hopper"); + } +} \ No newline at end of file diff --git a/src/devmine/inventory/items/IronBoots.php b/src/devmine/inventory/items/IronBoots.php index 1b5c86b..d72c75c 100644 --- a/src/devmine/inventory/items/IronBoots.php +++ b/src/devmine/inventory/items/IronBoots.php @@ -1,6 +1,23 @@ addEnchantment(Enchantment::getEnchantment($ench["id"])->setLevel($ench["lvl"])); - } - } - self::addCreativeItem($item); - } - } - }else{ - $creativeItems = new Config(Server::getInstance()->getFilePath() . "src/devmine/resources/creativeitems.json", Config::JSON, []); - foreach($creativeItems->getAll() as $item){ - self::addCreativeItem(Item::get($item["ID"], $item["Damage"])); + + $creativeItems = new Config(Server::getInstance()->getFilePath() . "src/devmine/server/resources/creativeitems.json", Config::JSON, []); + + foreach($creativeItems->getAll() as $data){ + $item = Item::get($data["id"], $data["damage"], $data["count"], $data["nbt"]); + if($item->getName() === "Unknown"){ + continue; } + self::addCreativeItem($item); } - } public static function clearCreativeItems(){ @@ -281,8 +268,7 @@ public static function getCreativeItems() : array{ } public static function addCreativeItem(Item $item){ - //Doing it this way allows adding enchanted items to inventory, like enchanted books - Item::$creative[] = $item; + Item::$creative[] = clone $item; } public static function removeCreativeItem(Item $item){ @@ -810,6 +796,17 @@ final public function isPlaceable() : bool{ return $this->canBePlaced(); } + public function canBeConsumed() : bool{ + return false; + } + + public function canBeConsumedBy(Entity $entity) : bool{ + return $this->canBeConsumed(); + } + + public function onConsume(Entity $entity){ + } + public function getBlock() : Block{ if($this->block instanceof Block){ return clone $this->block; @@ -908,7 +905,7 @@ public function isHelmet(){ return false; } - public function isLegging(){ + public function isLeggings(){ return false; } @@ -941,10 +938,6 @@ public function getModifyAttackDamage(Entity $target){ return $rec; } - final public function __toString(){ //Get error here.. - return "Item " . $this->name . " (" . $this->id . ":" . ($this->meta === null ? "?" : $this->meta) . ")x" . $this->count . ($this->hasCompoundTag() ? " tags:0x" . bin2hex($this->getCompoundTag()) : ""); - } - public function getDestroySpeed(Block $block, Player $player){ return 1; } @@ -966,4 +959,72 @@ public final function deepEquals(Item $item, bool $checkDamage = true, bool $che return false; } + + final public function __toString() : string{ + return "Item " . $this->name . " (" . $this->id . ":" . ($this->meta === null ? "?" : $this->meta) . ")x" . $this->count . ($this->hasCompoundTag() ? " tags:0x" . bin2hex($this->getCompoundTag()) : ""); + } + + final public function jsonSerialize(){ + return [ + "id" => $this->id, + "damage" => $this->meta, + "count" => $this->count, //TODO: separate items and stacks + "nbt" => $this->tags + ]; + } + + /** + * Serializes the item to an NBT CompoundTag + * + * @param int $slot optional, the inventory slot of the item + * + * @return CompoundTag + */ + public function nbtSerialize(int $slot = -1, string $tagName = "") : CompoundTag{ + $tag = new CompoundTag($tagName, [ + "id" => new ShortTag("id", $this->id), + "Count" => new ByteTag("Count", $this->count ?? -1), + "Damage" => new ShortTag("Damage", $this->meta), + ]); + + if($this->hasCompoundTag()){ + $tag->tag = clone $this->getNamedTag(); + $tag->tag->setName("tag"); + } + + if($slot !== -1){ + $tag->Slot = new ByteTag("Slot", $slot); + } + + return $tag; + } + + /** + * Deserializes an Item from an NBT CompoundTag + * + * @param CompoundTag $tag + * + * @return Item + */ + public static function nbtDeserialize(CompoundTag $tag) : Item{ + if(!isset($tag->id) or !isset($tag->Count)){ + return Item::get(0); + } + + if($tag->id instanceof ShortTag){ + $item = Item::get($tag->id->getValue(), !isset($tag->Damage) ? 0 : $tag->Damage->getValue(), $tag->Count->getValue()); + }elseif($tag->id instanceof StringTag){ //PC item save format + $item = Item::fromString($tag->id->getValue()); + $item->setDamage(!isset($tag->Damage) ? 0 : $tag->Damage->getValue()); + $item->setCount($tag->Count->getValue()); + }else{ + throw new \InvalidArgumentException("Item CompoundTag ID must be an instance of StringTag or ShortTag, " . get_class($tag->id) . " given"); + } + + if(isset($tag->tag) and $tag->tag instanceof CompoundTag){ + $item->setNamedTag($tag->tag); + } + + return $item; + } } diff --git a/src/devmine/inventory/items/ItemFrame.php b/src/devmine/inventory/items/ItemFrame.php index 7893703..e3828ed 100644 --- a/src/devmine/inventory/items/ItemFrame.php +++ b/src/devmine/inventory/items/ItemFrame.php @@ -1,6 +1,23 @@ [matching effect, duration in ticks, amplifier] //Use false if no effects. @@ -105,7 +123,9 @@ class Potion extends Item{ self::STRENGTH_TWO => [Effect::STRENGTH, (90 * 20), 1], self::WEAKNESS => [Effect::WEAKNESS, (90 * 20), 0], - self::WEAKNESS_T => [Effect::WEAKNESS, (240 * 20), 0] + self::WEAKNESS_T => [Effect::WEAKNESS, (240 * 20), 0], + + self::DECAY => [Effect::WITHER, (40 * 20), 0] ]; public function __construct($meta = 0, $count = 1){ @@ -113,7 +133,11 @@ public function __construct($meta = 0, $count = 1){ } public static function getColor(int $meta){ - return Effect::getEffect(self::getEffectId($meta))->getColor(); + $effect = Effect::getEffect(self::getEffectId($meta)); + if($effect !== null){ + return $effect->getColor(); + } + return [0, 0, 0]; } public function getMaxStackSize() : int{ @@ -124,7 +148,7 @@ public function canBeConsumed() : bool{ return $this->meta > 0; } - public function canBeConsumedBy($entity) : bool{ + public function canBeConsumedBy(Entity $entity) : bool{ return $entity instanceof Human; } @@ -137,7 +161,7 @@ public function getEffects(): array{ * @return Effect[] */ public static function getEffectsById(int $id) : array{ - if(count(self::POTIONS[$id]) === 3){ + if(count(self::POTIONS[$id] ?? []) === 3){ return [Effect::getEffect(self::POTIONS[$id][0])->setDuration(self::POTIONS[$id][1])->setAmplifier(self::POTIONS[$id][2])]; } return []; @@ -211,7 +235,7 @@ public static function getEffectId(int $meta) : int{ case self::REGENERATION_TWO: return Effect::REGENERATION; default: - return Effect::WATER_BREATHING; + return 0; } } @@ -277,6 +301,8 @@ public static function getNameByMeta(int $meta) : string{ case self::WEAKNESS: case self::WEAKNESS_T: return "Potion of Weakness"; + case self::DECAY: + return "Potion of WHTHER II"; default: return "Potion"; } diff --git a/src/devmine/inventory/items/PrismarineCrystals.php b/src/devmine/inventory/items/PrismarineCrystals.php new file mode 100644 index 0000000..91ab0b7 --- /dev/null +++ b/src/devmine/inventory/items/PrismarineCrystals.php @@ -0,0 +1,12 @@ +getChunk($block->getX() >> 4, $block->getZ() >> 4); - if(!($chunk instanceof FullChunk)){ + if(!($chunk instanceof Chunk)){ return false; } diff --git a/src/devmine/inventory/items/SplashPotion.php b/src/devmine/inventory/items/SplashPotion.php index eb9b6e6..43f1eac 100644 --- a/src/devmine/inventory/items/SplashPotion.php +++ b/src/devmine/inventory/items/SplashPotion.php @@ -1,6 +1,23 @@ isUnbreakable()){ return true; } diff --git a/src/devmine/inventory/items/enchantment/Enchantment.php b/src/devmine/inventory/items/enchantment/Enchantment.php index 8461b95..4e82e2e 100644 --- a/src/devmine/inventory/items/enchantment/Enchantment.php +++ b/src/devmine/inventory/items/enchantment/Enchantment.php @@ -59,7 +59,7 @@ class Enchantment{ const TYPE_ARMOR_FIRE_PROTECTION = 1; const TYPE_ARMOR_FALL_PROTECTION = 2; const TYPE_ARMOR_EXPLOSION_PROTECTION = 3; - const TYPE_ARMOR_PROJECsolidentity_PROTECTION = 4; + const TYPE_ARMOR_PROJECTILE_PROTECTION = 4; const TYPE_ARMOR_THORNS = 5; const TYPE_WATER_BREATHING = 6; const TYPE_WATER_SPEED = 7; @@ -127,7 +127,7 @@ public static function init(){ self::$enchantments[self::TYPE_ARMOR_FALL_PROTECTION] = new Enchantment(self::TYPE_ARMOR_FALL_PROTECTION, "%enchantment.protect.fall", self::RARITY_UNCOMMON, self::ACTIVATION_EQUIP, self::SLOT_FEET); self::$enchantments[self::TYPE_ARMOR_EXPLOSION_PROTECTION] = new Enchantment(self::TYPE_ARMOR_EXPLOSION_PROTECTION, "%enchantment.protect.explosion", self::RARITY_UNCOMMON, self::ACTIVATION_EQUIP, self::SLOT_ARMOR); - self::$enchantments[self::TYPE_ARMOR_PROJECsolidentity_PROTECTION] = new Enchantment(self::TYPE_ARMOR_PROJECsolidentity_PROTECTION, "%enchantment.protect.projecsolidentity", self::RARITY_UNCOMMON, self::ACTIVATION_EQUIP, self::SLOT_ARMOR); + self::$enchantments[self::TYPE_ARMOR_PROJECTILE_PROTECTION] = new Enchantment(self::TYPE_ARMOR_PROJECTILE_PROTECTION, "%enchantment.protect.projectile", self::RARITY_UNCOMMON, self::ACTIVATION_EQUIP, self::SLOT_ARMOR); self::$enchantments[self::TYPE_ARMOR_THORNS] = new Enchantment(self::TYPE_ARMOR_THORNS, "%enchantment.protect.thorns", self::RARITY_UNCOMMON, self::ACTIVATION_EQUIP, self::SLOT_SWORD); self::$enchantments[self::TYPE_WATER_BREATHING] = new Enchantment(self::TYPE_WATER_BREATHING, "%enchantment.protect.waterbrething", self::RARITY_UNCOMMON, self::ACTIVATION_EQUIP, self::SLOT_FEET); self::$enchantments[self::TYPE_WATER_SPEED] = new Enchantment(self::TYPE_WATER_SPEED, "%enchantment.waterspeed", self::RARITY_UNCOMMON, self::ACTIVATION_EQUIP, self::SLOT_FEET); @@ -163,11 +163,22 @@ public static function getEnchantment($id){ return new Enchantment(self::TYPE_INVALID, "unknown", 0, 0, 0); } - public static function getEffectByName($name){ + public static function getEnchantmentByName($name){ if(defined(Enchantment::class . "::TYPE_" . strtoupper($name))){ return self::getEnchantment(constant(Enchantment::class . "::TYPE_" . strtoupper($name))); - } - return null; + }elseif(defined(Enchantment::class . "::TYPE_WEAPON_" . strtoupper($name))){ + return self::getEnchantment(constant(Enchantment::class . "::TYPE_WEAPON_" . strtoupper($name))); + }elseif(defined(Enchantment::class . "::TYPE_ARMOR_" . strtoupper($name))){ + return self::getEnchantment(constant(Enchantment::class . "::TYPE_ARMOR_" . strtoupper($name))); + }elseif(defined(Enchantment::class . "::TYPE_MINING_" . strtoupper($name))){ + return self::getEnchantment(constant(Enchantment::class . "::TYPE_MINING_" . strtoupper($name))); + }elseif(defined(Enchantment::class . "::TYPE_BOW_" . strtoupper($name))){ + return self::getEnchantment(constant(Enchantment::class . "::TYPE_BOW_" . strtoupper($name))); + }elseif(defined(Enchantment::class . "::TYPE_FISHING_" . strtoupper($name))){ + return self::getEnchantment(constant(Enchantment::class . "::TYPE_FISHING_" . strtoupper($name))); + }else{ + return new Enchantment(self::TYPE_INVALID, "unknown", 0, 0, 0); + } } public static function getEnchantAbility(Item $item){ @@ -249,7 +260,7 @@ public static function getEnchantMaxLevel(int $enchantmentId){ case self::TYPE_ARMOR_FIRE_PROTECTION: case self::TYPE_ARMOR_FALL_PROTECTION: case self::TYPE_ARMOR_EXPLOSION_PROTECTION: - case self::TYPE_ARMOR_PROJECsolidentity_PROTECTION: + case self::TYPE_ARMOR_PROJECTILE_PROTECTION: return 4; case self::TYPE_ARMOR_THORNS: return 3; @@ -352,4 +363,4 @@ public static function getRandomName(){ } return implode(" ", $set); } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/items/enchantment/EnchantmentLevelTable.php b/src/devmine/inventory/items/enchantment/EnchantmentLevelTable.php index 7b8bffd..8cad7a2 100644 --- a/src/devmine/inventory/items/enchantment/EnchantmentLevelTable.php +++ b/src/devmine/inventory/items/enchantment/EnchantmentLevelTable.php @@ -1,6 +1,23 @@ [ + Enchantment::TYPE_ARMOR_PROJECTILE_PROTECTION => [ new Range(3, 18), new Range(9, 24), new Range(15, 30), @@ -183,7 +200,7 @@ public static function getPossibleEnchantments(Item $item, int $modifiedLevel){ $enchantmentIds[] = Enchantment::TYPE_ARMOR_PROTECTION; $enchantmentIds[] = Enchantment::TYPE_ARMOR_FIRE_PROTECTION; $enchantmentIds[] = Enchantment::TYPE_ARMOR_EXPLOSION_PROTECTION; - $enchantmentIds[] = Enchantment::TYPE_ARMOR_PROJECsolidentity_PROTECTION; + $enchantmentIds[] = Enchantment::TYPE_ARMOR_PROJECTILE_PROTECTION; $enchantmentIds[] = Enchantment::TYPE_ARMOR_THORNS; if($item->isBoots()){ diff --git a/src/devmine/inventory/layout/AnvilInventory.php b/src/devmine/inventory/layout/AnvilInventory.php index c1d5347..2ec4481 100644 --- a/src/devmine/inventory/layout/AnvilInventory.php +++ b/src/devmine/inventory/layout/AnvilInventory.php @@ -5,10 +5,16 @@ namespace devmine\inventory\layout; use devmine\inventory\items\Item; -use devmine\levels\Position; -use devmine\Player; +use devmine\worlds\Position; +use devmine\creatures\player; + +class AnvilInventory extends TemporaryInventory{ + + const TARGET = 0; + const SACRIFICE = 1; + const RESULT = 2; + -class AnvilInventory extends ContainerInventory{ public function __construct(Position $pos){ parent::__construct(new FakeBlockMenu($this, $pos), InventoryType::get(InventoryType::ANVIL)); } @@ -20,21 +26,47 @@ public function getHolder(){ return $this->holder; } - public function onRename(Item $item, Player $player) : bool{ - if($player->getExpLevel() > $item->getRepairCost()){ - $player->setExpLevel($player->getExpLevel() - $item->getRepairCost()); - return true; + public function getResultSlotIndex(){ + return self::RESULT; + } + + public function onRename(Player $player, Item $resultItem) : bool{ + if(!$resultItem->deepEquals($this->getItem(self::TARGET), true, false, true)){ + //Item does not match target item. Everything must match except the tags. + return false; + } + + if($player->getXpLevel() < $resultItem->getRepairCost()){ //Not enough exp + return false; + } + $player->takeXpLevel($resultItem->getRepairCost()); + + $this->clearAll(); + if(!$player->getServer()->allowInventoryCheats and !$player->isCreative()){ + if(!$player->getFloatingInventory()->canAddItem($resultItem)){ + return false; + } + $player->getFloatingInventory()->addItem($resultItem); + } + return true; + } + + public function processSlotChange(Transaction $transaction): bool{ + if($transaction->getSlot() === $this->getResultSlotIndex()){ + return false; } - return false; + return true; + } + + public function onSlotChange($index, $before, $send){ + //Do not send anvil slot updates to anyone. This will cause a client crash. } public function onClose(Player $who){ - $who->updateExperience(); parent::onClose($who); $this->getHolder()->getLevel()->dropItem($this->getHolder()->add(0.5, 0.5, 0.5), $this->getItem(0)); $this->getHolder()->getLevel()->dropItem($this->getHolder()->add(0.5, 0.5, 0.5), $this->getItem(1)); - $this->clear(0); $this->clear(1); $this->clear(2); diff --git a/src/devmine/inventory/layout/BaseInventory.php b/src/devmine/inventory/layout/BaseInventory.php index b29b2a9..8cbaf9b 100644 --- a/src/devmine/inventory/layout/BaseInventory.php +++ b/src/devmine/inventory/layout/BaseInventory.php @@ -5,14 +5,14 @@ namespace devmine\inventory\layout; use devmine\creatures\entities\Entity; -use devmine\server\events\entity\EntityInventoryChangeEvent; -use devmine\server\events\inventory\InventoryOpenEvent; +use devmine\events\entity\EntityInventoryChangeEvent; +use devmine\events\inventory\InventoryOpenEvent; use devmine\inventory\items\Item; use devmine\server\network\Network; use devmine\server\network\protocol\ContainerSetContentPacket; use devmine\server\network\protocol\ContainerSetSlotPacket; -use devmine\Player; -use devmine\Server; +use devmine\creatures\player; +use devmine\server\server; abstract class BaseInventory implements Inventory{ @@ -101,7 +101,7 @@ public function getContents(){ /** * @param Item[] $items */ - public function setContents(array $items){ + public function setContents(array $items, $send = true){ if(count($items) > $this->size){ $items = array_slice($items, 0, $this->size, true); } @@ -109,22 +109,22 @@ public function setContents(array $items){ for($i = 0; $i < $this->size; ++$i){ if(!isset($items[$i])){ if(isset($this->slots[$i])){ - $this->clear($i); + $this->clear($i, $send); } }else{ - if (!$this->setItem($i, $items[$i])){ - $this->clear($i); + if (!$this->setItem($i, $items[$i], $send)){ + $this->clear($i, $send); } } } } - public function setItem($index, Item $item){ + public function setItem($index, Item $item, $send = true){ $item = clone $item; if($index < 0 or $index >= $this->size){ return false; }elseif($item->getId() === 0 or $item->getCount() <= 0){ - return $this->clear($index); + return $this->clear($index, $send); } $holder = $this->getHolder(); @@ -139,7 +139,8 @@ public function setItem($index, Item $item){ $old = $this->getItem($index); $this->slots[$index] = clone $item; - $this->onSlotChange($index, $old); + $this->onSlotChange($index, $old, $send); + return true; } @@ -160,6 +161,14 @@ public function contains(Item $item){ return false; } + public function slotContains($slot, Item $item, $matchCount = false){ + if($matchCount){ + return $this->getItem($slot)->deepEquals($item, true, true, true); + }else{ + return $this->getItem($slot)->deepEquals($item) and $this->getItem($slot)->getCount() >= $item->getCount(); + } + } + public function all(Item $item){ $slots = []; $checkDamage = $item->getDamage() === null ? false : true; @@ -173,14 +182,14 @@ public function all(Item $item){ return $slots; } - public function remove(Item $item){ + public function remove(Item $item, $send = true){ $checkDamage = $item->getDamage() === null ? false : true; $checkTags = $item->getCompoundTag() === null ? false : true; $checkCount = $item->getCount() === null ? false : true; foreach($this->getContents() as $index => $i){ if($item->equals($i, $checkDamage, $checkTags, $checkCount)){ - $this->clear($index); + $this->clear($index, $send); break; } } @@ -209,12 +218,21 @@ public function firstEmpty(){ return -1; } + + public function firstOccupied(){ + for($i = 0; $i < $this->size; $i++){ + if(($item = $this->getItem($i))->getId() !== Item::AIR and $item->getCount() > 0){ + return $i; + } + } + return -1; + } public function canAddItem(Item $item){ $item = clone $item; $checkDamage = $item->getDamage() === null ? false : true; $checkTags = $item->getCompoundTag() === null ? false : true; - for($i = 0; $i < ($this->getSize() - $this->getHotbarSize()); ++$i){ + for($i = 0; $i < $this->getSize(); ++$i){ $slot = $this->getItem($i); if($item->equals($slot, $checkDamage, $checkTags)){ if(($diff = $slot->getMaxStackSize() - $slot->getCount()) > 0){ @@ -238,7 +256,7 @@ public function addItem(...$slots){ $itemSlots = []; foreach($slots as $slot){ if(!($slot instanceof Item)){ - throw new \InvalidArgumentException("Expected Item[], got ".gettype($slot)); + throw new \InvalidArgumentException("Expected Item, got ".gettype($slot)); } if($slot->getId() !== 0 and $slot->getCount() > 0){ $itemSlots[] = clone $slot; @@ -247,7 +265,7 @@ public function addItem(...$slots){ $emptySlots = []; - for($i = 0; $i < ($this->getSize() - $this->getHotbarSize()); ++$i){ + for($i = 0; $i < $this->getSize(); ++$i){ $item = $this->getItem($i); if($item->getId() === Item::AIR or $item->getCount() <= 0){ $emptySlots[] = $i; @@ -305,7 +323,7 @@ public function removeItem(...$slots){ } } - for($i = 0; $i < ($this->getSize() - $this->getHotbarSize()); ++$i){ + for($i = 0; $i < $this->getSize(); ++$i){ $item = $this->getItem($i); if($item->getId() === Item::AIR or $item->getCount() <= 0){ continue; @@ -331,7 +349,7 @@ public function removeItem(...$slots){ return $itemSlots; } - public function clear($index){ + public function clear($index, $send = true){ if(isset($this->slots[$index])){ $item = Item::get(Item::AIR, null, 0); $old = $this->slots[$index]; @@ -349,16 +367,15 @@ public function clear($index){ }else{ unset($this->slots[$index]); } - - $this->onSlotChange($index, $old); + $this->onSlotChange($index, $old, $send); } return true; } - public function clearAll(){ + public function clearAll($send = true){ foreach($this->getContents() as $index => $i){ - $this->clear($index); + $this->clear($index, $send); } } @@ -399,8 +416,14 @@ public function onClose(Player $who){ unset($this->viewers[spl_object_hash($who)]); } - public function onSlotChange($index, $before){ - $this->sendSlot($index, $this->getViewers()); + public function onSlotChange($index, $before, $send){ + if($send){ + $this->sendSlot($index, $this->getViewers()); + } + } + + public function processSlotChange(Transaction $transaction): bool{ + return true; } diff --git a/src/devmine/inventory/layout/BaseTransaction.php b/src/devmine/inventory/layout/BaseTransaction.php index 1b57110..0a689f9 100644 --- a/src/devmine/inventory/layout/BaseTransaction.php +++ b/src/devmine/inventory/layout/BaseTransaction.php @@ -5,6 +5,7 @@ namespace devmine\inventory\layout; use devmine\inventory\items\Item; +use devmine\creatures\player; class BaseTransaction implements Transaction{ /** @var Inventory */ @@ -12,24 +13,32 @@ class BaseTransaction implements Transaction{ /** @var int */ protected $slot; /** @var Item */ - protected $sourceItem; - /** @var Item */ protected $targetItem; /** @var float */ protected $creationTime; + /** @var int */ + protected $transactionType = Transaction::TYPE_NORMAL; + /** @var int */ + protected $failures = 0; + /** @var bool */ + protected $wasSuccessful = false; + /** @var string */ + protected $achievements = []; /** * @param Inventory $inventory * @param int $slot - * @param Item $sourceItem * @param Item $targetItem + * @param string[] $achievements + * @param int $transactionType */ - public function __construct(Inventory $inventory, $slot, Item $sourceItem, Item $targetItem){ + public function __construct($inventory, $slot, Item $targetItem, $achievements = [], $transactionType = Transaction::TYPE_NORMAL){ $this->inventory = $inventory; $this->slot = (int) $slot; - $this->sourceItem = clone $sourceItem; $this->targetItem = clone $targetItem; $this->creationTime = microtime(true); + $this->transactionType = $transactionType; + $this->achievements = $achievements; } public function getCreationTime(){ @@ -44,11 +53,161 @@ public function getSlot(){ return $this->slot; } - public function getSourceItem(){ - return clone $this->sourceItem; - } - public function getTargetItem(){ return clone $this->targetItem; } + + public function setTargetItem(Item $item){ + $this->targetItem = clone $item; + } + + public function getFailures(){ + return $this->failures; + } + + public function addFailure(){ + $this->failures++; + } + + public function succeeded(){ + return $this->wasSuccessful; + } + + public function setSuccess($value = true){ + $this->wasSuccessful = $value; + } + + public function getTransactionType(){ + return $this->transactionType; + } + + public function getAchievements(){ + return $this->achievements; + } + + public function hasAchievements(){ + return count($this->achievements) !== 0; + } + + public function addAchievement(string $achievementName){ + $this->achievements[] = $achievementName; + } + + /** + * @param Player $source + * + * Sends a slot update to inventory viewers + * For successful transactions, update non-source viewers (source does not need updating) + * For failed transactions, update the source (non-source viewers will see nothing anyway) + */ + public function sendSlotUpdate(Player $source){ + if($this->getInventory() instanceof TemporaryInventory){ + return; + } + + $targets = []; + if($this->wasSuccessful){ + $targets = $this->getInventory()->getViewers(); + unset($targets[spl_object_hash($source)]); + }else{ + $targets = [$source]; + } + $this->inventory->sendSlot($this->slot, $targets); + } + + /** + * Returns the change in inventory resulting from this transaction + * @return Item[ + * "in" => items added to the inventory + * "out" => items removed from the inventory + * ] + */ + public function getChange(){ + $sourceItem = $this->getInventory()->getItem($this->slot); + + if($sourceItem->deepEquals($this->targetItem, true, true, true)){ + //This should never happen, somehow a change happened where nothing changed + return null; + + }elseif($sourceItem->deepEquals($this->targetItem)){ //Same item, change of count + $item = clone $sourceItem; + $countDiff = $this->targetItem->getCount() - $sourceItem->getCount(); + $item->setCount(abs($countDiff)); + + if($countDiff < 0){ //Count decreased + return ["in" => null, + "out" => $item]; + }elseif($countDiff > 0){ //Count increased + return [ + "in" => $item, + "out" => null]; + }else{ + //Should be impossible (identical items and no count change) + //This should be caught by the first condition even if it was possible + return null; + } + }elseif($sourceItem->getId() !== Item::AIR and $this->targetItem->getId() === Item::AIR){ + //Slot emptied (item removed) + return ["in" => null, + "out" => clone $sourceItem]; + + }elseif($sourceItem->getId() === Item::AIR and $this->targetItem->getId() !== Item::AIR){ + //Slot filled (item added) + return ["in" => $this->getTargetItem(), + "out" => null]; + + }else{ + //Some other slot change - an item swap (tool damage changes will be ignored as they are processed server-side before any change is sent by the client + return ["in" => $this->getTargetItem(), + "out" => clone $sourceItem]; + } + } + + /** + * @param Player $source + * @return bool + * + * Handles transaction execution. Returns whether transaction was successful or not. + */ + + public function execute(Player $source): bool{ + if($this->getInventory()->processSlotChange($this)){ //This means that the transaction should be handled the normal way + if(!$source->getServer()->allowInventoryCheats and !$source->isCreative()){ + $change = $this->getChange(); + + if($change === null){ //No changes to make, ignore this transaction + return true; + } + + /* Verify that we have the required items */ + if($change["out"] instanceof Item){ + if(!$this->getInventory()->slotContains($this->getSlot(), $change["out"])){ + return false; + } + } + if($change["in"] instanceof Item){ + if(!$source->getFloatingInventory()->contains($change["in"])){ + return false; + } + } + + /* All checks passed, make changes to floating inventory + * This will not be reached unless all requirements are met */ + if($change["out"] instanceof Item){ + $source->getFloatingInventory()->addItem($change["out"]); + } + if($change["in"] instanceof Item){ + $source->getFloatingInventory()->removeItem($change["in"]); + } + } + $this->getInventory()->setItem($this->getSlot(), $this->getTargetItem(), false); + } + + /* Process transaction achievements, like getting iron from a furnace */ + foreach($this->achievements as $achievement){ + $source->awardAchievement($achievement); + } + + return true; + } } \ No newline at end of file diff --git a/src/devmine/inventory/layout/BrewingInventory.php b/src/devmine/inventory/layout/BrewingInventory.php index 718628a..9844732 100644 --- a/src/devmine/inventory/layout/BrewingInventory.php +++ b/src/devmine/inventory/layout/BrewingInventory.php @@ -1,6 +1,23 @@ getItem(0); } - public function onSlotChange($index, $before){ - parent::onSlotChange($index, $before); + public function onSlotChange($index, $before, $send){ + parent::onSlotChange($index, $before, $send); $this->getHolder()->scheduleUpdate(); $this->getHolder()->updateSurface(); diff --git a/src/devmine/inventory/layout/BrewingRecipe.php b/src/devmine/inventory/layout/BrewingRecipe.php index 468df93..5432090 100644 --- a/src/devmine/inventory/layout/BrewingRecipe.php +++ b/src/devmine/inventory/layout/BrewingRecipe.php @@ -1,11 +1,28 @@ holder; } + public function getContents($withAir = false){ + if($withAir){ + $contents = []; + for($i = 0; $i < $this->getSize(); ++$i){ + $contents[$i] = $this->getItem($i); + } + + return $contents; + } + return parent::getContents(); + } + public function onOpen(Player $who){ parent::onOpen($who); diff --git a/src/devmine/inventory/layout/ContainerInventory.php b/src/devmine/inventory/layout/ContainerInventory.php index 0e55f6b..88dbe4d 100644 --- a/src/devmine/inventory/layout/ContainerInventory.php +++ b/src/devmine/inventory/layout/ContainerInventory.php @@ -8,7 +8,7 @@ use devmine\server\network\Network; use devmine\server\network\protocol\ContainerClosePacket; use devmine\server\network\protocol\ContainerOpenPacket; -use devmine\Player; +use devmine\creatures\player; abstract class ContainerInventory extends BaseInventory{ public function onOpen(Player $who){ diff --git a/src/devmine/inventory/layout/CraftingManager.php b/src/devmine/inventory/layout/CraftingManager.php index 58f0e83..3e2981f 100644 --- a/src/devmine/inventory/layout/CraftingManager.php +++ b/src/devmine/inventory/layout/CraftingManager.php @@ -14,7 +14,7 @@ use devmine\inventory\items\Item; use devmine\inventory\items\Potion; use devmine\utilities\main\UUID; -use devmine\Server; +use devmine\server\server; use devmine\utilities\main\MainLogger; use devmine\utilities\main\Config; @@ -35,700 +35,52 @@ class CraftingManager{ public function __construct(bool $useJson = false){ $this->registerBrewingStand(); - if($useJson){ - // load recipes from src/devmine/recipes.json - $recipes = new Config(Server::getInstance()->getFilePath() . "src/devmine/resources/recipes.json", Config::JSON, []); - MainLogger::getLogger()->info("Loading recipes..."); - foreach($recipes->getAll() as $recipe){ - switch($recipe["Type"]){ - case 0: - // TODO: handle multiple result items - if(count($recipe["Result"]) == 1){ - $first = $recipe["Result"][0]; - $result = new ShapelessRecipe(Item::get($first["ID"], $first["Damage"], $first["Count"])); + // load recipes from src/devmine/server/resources/recipes.json + $recipes = new Config(Server::getInstance()->getFilePath() . "src/devmine/server/resources/recipes.json", Config::JSON, []); - foreach($recipe["Ingredients"] as $ingredient){ - $result->addIngredient(Item::get($ingredient["ID"], $ingredient["Damage"], $ingredient["Count"])); - } - $this->registerRecipe($result); - } - break; - case 1: - // TODO: handle multiple result items - if(count($recipe["Result"]) == 1){ - $first = $recipe["Result"][0]; - $result = new ShapedRecipeFromJson(Item::get($first["ID"], $first["Damage"], $first["Count"]), $recipe["Height"], $recipe["Width"]); + foreach($recipes->getAll() as $recipe){ + switch($recipe["type"]){ + case 0: + // TODO: handle multiple result items + if(count($recipe["output"]) === 1){ + $first = $recipe["output"][0]; + $result = new ShapelessRecipe(Item::get($first["id"], $first["damage"], $first["count"], $first["nbt"])); - $shape = array_chunk($recipe["Ingredients"], $recipe["Width"]); - foreach($shape as $y => $row){ - foreach($row as $x => $ingredient){ - $result->addIngredient($x, $y, Item::get($ingredient["ID"], ($ingredient["Damage"] < 0 ? null : $ingredient["Damage"]), $ingredient["Count"])); - } + foreach($recipe["input"] as $ingredient){ + $result->addIngredient(Item::get($ingredient["id"], $ingredient["damage"], $ingredient["count"], $first["nbt"])); + } + $this->registerRecipe($result); + } + break; + case 1: + // TODO: handle multiple result items + if(count($recipe["output"]) === 1){ + $first = $recipe["output"][0]; + $result = new ShapedRecipe(Item::get($first["id"], $first["damage"], $first["count"], $first["nbt"]), $recipe["height"], $recipe["width"]); + + $shape = array_chunk($recipe["input"], $recipe["width"]); + foreach($shape as $y => $row){ + foreach($row as $x => $ingredient){ + $result->addIngredient($x, $y, Item::get($ingredient["id"], ($ingredient["damage"] < 0 ? null : $ingredient["damage"]), $ingredient["count"], $ingredient["nbt"])); } - $this->registerRecipe($result); } - break; - case 2: - $result = $recipe["Result"]; - $resultItem = Item::get($result["ID"], $result["Damage"], $result["Count"]); - $this->registerRecipe(new FurnaceRecipe($resultItem, Item::get($recipe["Ingredients"], 0,1))); - break; - case 3: - $result = $recipe["Result"]; - $resultItem = Item::get($result["ID"], $result["Damage"], $result["Count"]); - $this->registerRecipe(new FurnaceRecipe($resultItem, Item::get($recipe["Ingredients"]["ID"], $recipe["Ingredients"]["Damage"], 1))); - break; - default: - break; - } + $this->registerRecipe($result); + } + break; + case 2: + case 3: + $result = $recipe["output"]; + $resultItem = Item::get($result["id"], $result["damage"], $result["count"], $result["nbt"]); + $this->registerRecipe(new FurnaceRecipe($resultItem, Item::get($recipe["inputId"], $recipe["inputDamage"] ?? null, 1))); + break; + default: + break; } - }else{ - $this->registerFurnace(); - $this->registerDyes(); - $this->registerIngots(); - $this->registerPotions(); - $this->registerTools(); - $this->registerWeapons(); - $this->registerArmor(); - $this->registerFood(); - $this->registerBrewingStand(); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::CLAY_BLOCK, 0, 1), - "XX ", - "XX ", - " " - ))->setIngredient("X", Item::get(Item::CLAY, 0, 4))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WORKBENCH, 0, 1), - "XX", - "XX" - ))->setIngredient("X", Item::get(Item::WOODEN_PLANK, null))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::GLOWSTONE_BLOCK, 0, 1), - "XX", - "XX" - ))->setIngredient("X", Item::get(Item::GLOWSTONE_DUST, 0, 4))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::LIT_PUMPKIN, 0, 1), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::PUMPKIN, 0, 1))->setIngredient("Y", Item::get(Item::TORCH, 0, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::SNOW_BLOCK, 0, 1), - "XX", - "XX" - ))->setIngredient("X", Item::get(Item::SNOWBALL))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::SNOW_LAYER, 0, 6), - "X" - ))->setIngredient("X", Item::get(Item::SNOW_BLOCK, 0, 3))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::STICK, 0, 4), - "X ", - "X " - ))->setIngredient("X", Item::get(Item::WOODEN_PLANK, null))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOODEN_PLANK, Planks::OAK, 4), - "X" - ))->setIngredient("X", Item::get(Item::WOOD, Wood::OAK, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOODEN_PLANK, Planks::SPRUCE, 4), - "X" - ))->setIngredient("X", Item::get(Item::WOOD, Wood::SPRUCE, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOODEN_PLANK, Planks::BIRCH, 4), - "X" - ))->setIngredient("X", Item::get(Item::WOOD, Wood::BIRCH, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOODEN_PLANK, Planks::JUNGLE, 4), - "X" - ))->setIngredient("X", Item::get(Item::WOOD, Wood::JUNGLE, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOODEN_PLANK, Planks::ACACIA, 4), - "X" - ))->setIngredient("X", Item::get(Item::WOOD2, Wood2::ACACIA, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOODEN_PLANK, Planks::DARK_OAK, 4), - "X" - ))->setIngredient("X", Item::get(Item::WOOD2, Wood2::DARK_OAK, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOOL, 0, 1), - "XX", - "XX" - ))->setIngredient("X", Item::get(Item::STRING, 0, 4))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::TORCH, 0, 4), - "C ", - "S" - ))->setIngredient("C", Item::get(Item::COAL, 0, 1))->setIngredient("S", Item::get(Item::STICK, 0, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::TORCH, 0, 4), - "C ", - "S" - ))->setIngredient("C", Item::get(Item::COAL, 1, 1))->setIngredient("S", Item::get(Item::STICK, 0, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::SUGAR, 0, 1), - "S" - ))->setIngredient("S", Item::get(Item::SUGARCANE, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BED, 0, 1), - "WWW", - "PPP", - " " - ))->setIngredient("W", Item::get(Item::WOOL, null, 3))->setIngredient("P", Item::get(Item::WOODEN_PLANK, null, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::CHEST, 0, 1), - "PPP", - "P P", - "PPP" - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, null, 8))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::ENCHANTMENT_TABLE, 0, 1), - " B ", - "DOD", - "OOO" - ))->setIngredient("D", Item::get(Item::DIAMOND, 0, 2))->setIngredient("O", Item::get(Item::OBSIDIAN, 0, 4))->setIngredient("B", Item::get(Item::BOOK, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE, 0, 3), - "PSP", - "PSP", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 2))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::OAK, 4))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE, Planks::SPRUCE, 3), - "PSP", - "PSP", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 2))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::SPRUCE, 4))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE, Planks::BIRCH, 3), - "PSP", - "PSP", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 2))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::BIRCH, 4))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE, Planks::JUNGLE, 3), - "PSP", - "PSP", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 2))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::JUNGLE, 4))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE, Planks::ACACIA, 3), - "PSP", - "PSP", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 2))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::ACACIA, 4))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE, Planks::DARK_OAK, 3), - "PSP", - "PSP", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 2))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::DARK_OAK, 4))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE_GATE, 0, 1), - "SPS", - "SPS", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 4))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::OAK, 2))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE_GATE_SPRUCE, 0, 1), - "SPS", - "SPS", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 4))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::SPRUCE, 2))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE_GATE_BIRCH, 0, 1), - "SPS", - "SPS", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 4))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::BIRCH, 2))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE_GATE_JUNGLE, 0, 1), - "SPS", - "SPS", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 4))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::JUNGLE, 2))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE_GATE_DARK_OAK, 0, 1), - "SPS", - "SPS", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 4))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::DARK_OAK, 2))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FENCE_GATE_ACACIA, 0, 1), - "SPS", - "SPS", - " " - ))->setIngredient("S", Item::get(Item::STICK, 0, 4))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::ACACIA, 2))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FURNACE, 0, 1), - "CCC", - "C C", - "CCC" - ))->setIngredient("C", Item::get(Item::COBBLESTONE, 0, 8))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::GLASS_PANE, 0, 16), - "GGG", - "GGG", - " " - ))->setIngredient("G", Item::get(Item::GLASS, 0, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::LADDER, 0, 2), - "S S", - "SSS", - "S S" - ))->setIngredient("S", Item::get(Item::STICK, 0, 7))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::TRAPDOOR, 0, 2), - "PPP", - "PPP", - " " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, null, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::WOODEN_DOOR, 0, 3), - "PP ", - "PP ", - "PP " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, null, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BIRCH_DOOR, 0, 3), - "PP ", - "PP ", - "PP " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::BIRCH, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::SPRUCE_DOOR, 0, 3), - "PP ", - "PP ", - "PP " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::SPRUCE, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::JUNGLE_DOOR, 0, 3), - "PP ", - "PP ", - "PP " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::JUNGLE, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::ACACIA_DOOR, 0, 3), - "PP ", - "PP ", - "PP " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::ACACIA, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::DARK_OAK_DOOR, 0, 3), - "PP ", - "PP ", - "PP " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::DARK_OAK, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::IRON_DOOR, 0, 1), - "II ", - "II ", - "II " - ))->setIngredient("I", Item::get(Item::IRON_INGOT, 0, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BOAT, 0, 1), - "PSP", - "PPP", - " " - ))->setIngredient("S", Item::get(Item::WOODEN_SHOVEL, 0, 1))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::OAK, 5))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BOAT, 1, 1), - "PSP", - "PPP", - " " - ))->setIngredient("S", Item::get(Item::WOODEN_SHOVEL, 0, 1))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::SPRUCE, 5))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BOAT, 2, 1), - "PSP", - "PPP", - " " - ))->setIngredient("S", Item::get(Item::WOODEN_SHOVEL, 0, 1))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::BIRCH, 5))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BOAT, 3, 1), - "PSP", - "PPP", - " " - ))->setIngredient("S", Item::get(Item::WOODEN_SHOVEL, 0, 1))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::JUNGLE, 5))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BOAT, 4, 1), - "PSP", - "PPP", - " " - ))->setIngredient("S", Item::get(Item::WOODEN_SHOVEL, 0, 1))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::ACACIA, 5))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BOAT, 5, 1), - "PSP", - "PPP", - " " - ))->setIngredient("S", Item::get(Item::WOODEN_SHOVEL, 0, 1))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::DARK_OAK, 5))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::WOODEN_STAIRS, 0, 4), - " P", - " PP", - "PPP" - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::OAK, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::WOOD_SLAB, Planks::OAK, 6), - "PPP", - " ", - " " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::OAK, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::SPRUCE_WOOD_STAIRS, 0, 4), - " P", - " PP", - "PPP" - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::SPRUCE, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::WOOD_SLAB, Planks::SPRUCE, 6), - "PPP", - " ", - " " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::SPRUCE, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BIRCH_WOOD_STAIRS, 0, 4), - " P", - " PP", - "PPP" - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::BIRCH, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::WOOD_SLAB, Planks::BIRCH, 6), - "PPP", - " ", - " " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::BIRCH, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::JUNGLE_WOOD_STAIRS, 0, 4), - "P", - "PP", - "PPP" - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::JUNGLE, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::WOOD_SLAB, Planks::JUNGLE, 6), - "PPP", - " ", - " " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::JUNGLE, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::ACACIA_WOOD_STAIRS, 0, 4), - " P", - " PP", - "PPP" - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::ACACIA, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::WOOD_SLAB, Planks::ACACIA, 6), - "PPP", - " ", - " " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::ACACIA, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::DARK_OAK_WOOD_STAIRS, 0, 4), - " P", - " PP", - "PPP" - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::DARK_OAK, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::WOOD_SLAB, Planks::DARK_OAK, 6), - "PPP", - " ", - " " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, Planks::DARK_OAK, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BUCKET, 0, 1), - "I I", - " I ", - " " - ))->setIngredient("I", Item::get(Item::IRON_INGOT, 0, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::CLOCK, 0, 1), - " G ", - "GRG", - " G " - ))->setIngredient("G", Item::get(Item::GOLD_INGOT, 0, 4))->setIngredient("R", Item::get(Item::REDSTONE_DUST, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::COMPASS, 0, 1), - " I ", - "IRI", - " I" - ))->setIngredient("I", Item::get(Item::IRON_INGOT, 0, 4))->setIngredient("R", Item::get(Item::REDSTONE_DUST, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::TNT, 0, 1), - "GSG", - "SGS", - "GSG" - ))->setIngredient("G", Item::get(Item::GUNPOWDER, 0, 5))->setIngredient("S", Item::get(Item::SAND, null, 4))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BOWL, 0, 4), - "P P", - " P ", - " " - ))->setIngredient("P", Item::get(Item::WOODEN_PLANKS, null, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::MINECART, 0, 1), - "I I", - "III" - ))->setIngredient("I", Item::get(Item::IRON_INGOT, 0, 5))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BOOK, 0, 1), - " ", - "PP ", - "P " - ))->setIngredient("P", Item::get(Item::PAPER, 0, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BOOKSHELF, 0, 1), - "PPP", - "BBB", - "PPP" - ))->setIngredient("P", Item::get(Item::WOODEN_PLANK, null, 6))->setIngredient("B", Item::get(Item::BOOK, 0, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::PAINTING, 0, 1), - "SSS", - "SWS", - "SSS" - ))->setIngredient("S", Item::get(Item::STICK, 0, 8))->setIngredient("W", Item::get(Item::WOOL, null, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::PAPER, 0, 3), - " ", - "SSS", - " " - ))->setIngredient("S", Item::get(Item::SUGARCANE, 0, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::SIGN, 0, 3), - "PPP", - "PPP", - " S" - ))->setIngredient("S", Item::get(Item::STICK, 0, 1))->setIngredient("P", Item::get(Item::WOODEN_PLANKS, null, 6))); //TODO: check if it gives one sign or three - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::IRON_BARS, 0, 16), - "III", - "III", - " " - ))->setIngredient("I", Item::get(Item::IRON_INGOT, 0, 6))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::GLASS_BOTTLE, 0, 3), - "G G", - " G ", - " " - ))->setIngredient("G", Item::get(Item::GLASS, 0, 3))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::WOODEN_PRESSURE_PLATE, 0, 1), - " ", - " ", - "XX " - ))->setIngredient("X", Item::get(Item::WOODEN_PLANK, null, 2))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::HEAVY_WEIGHTED_PRESSURE_PLATE, 0, 1), - " ", - "XX ", - " " - ))->setIngredient("X", Item::get(Item::IRON_INGOT, 0, 2))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::LIGHT_WEIGHTED_PRESSURE_PLATE, 0, 1), - " ", - "XX ", - " " - ))->setIngredient("X", Item::get(Item::GOLD_INGOT, 0, 2))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE_PRESSURE_PLATE, 0, 1), - " ", - "XX ", - " " - ))->setIngredient("X", Item::get(Item::STONE, 0, 2))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::INACTIVE_REDSTONE_LAMP, 0, 1), - " R ", - "RGR", - " R " - ))->setIngredient("R", Item::get(Item::REDSTONE, 0, 4))->setIngredient("G", Item::get(Item::GLOWSTONE_BLOCK, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::REDSTONE_TORCH, 0, 1), - " ", - " R ", - " S " - ))->setIngredient("R", Item::get(Item::REDSTONE, 0, 1))->setIngredient("S", Item::get(Item::STICK, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::WOODEN_BUTTON, 0, 1), - " ", - " X ", - " " - ))->setIngredient("X", Item::get(Item::WOODEN_PLANK, null, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE_BUTTON, 0, 1), - " ", - " X ", - " " - ))->setIngredient("X", Item::get(Item::COBBLESTONE, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::LEVER, 0, 1), - " ", - " X ", - " Y " - ))->setIngredient("X", Item::get(Item::STICK, 0, 1))->setIngredient("Y", Item::get(Item::COBBLESTONE, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::COBBLESTONE_STAIRS, 0, 4), - "P ", - "PP ", - "PPP" - ))->setIngredient("P", Item::get(Item::COBBLESTONE, 0, 6))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE_BRICK_STAIRS, 0, 4), - "P ", - "PP ", - "PPP" - ))->setIngredient("P", Item::get(Item::STONE_BRICK, 0, 6))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::SLAB, 0, 6), - " ", - "PPP", - " " - ))->setIngredient("P", Item::get(Item::STONE, '', 3))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::SLAB, 5, 6), - " ", - "PPP", - " " - ))->setIngredient("P", Item::get(Item::STONE_BRICK, '', 3))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE_BRICK, 3, 1), - " ", - "PP " - ))->setIngredient("P", Item::get(Item::SLAB, 5, 2))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::SLAB, 1, 6), - "PPP", - " ", - " " - ))->setIngredient("P", Item::get(Item::SANDSTONE, null, 3))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::RED_SANDSTONE_SLAB, 0, 6), - "PPP", - " ", - " " - ))->setIngredient("P", Item::get(Item::RED_SANDSTONE, null, 3))); - - $this->registerRecipe((new ShapedRecipe(Item::get(Item::SANDSTONE, 1, 1), - "P ", - "P " - ))->setIngredient("P", Item::get(Item::SLAB, 1, 2))); - - $this->registerRecipe((new ShapedRecipe(Item::get(Item::RED_SANDSTONE, 1, 1), - "P ", - "P " - ))->setIngredient("P", Item::get(Item::RED_SANDSTONE_SLAB, 0, 2))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE_BRICK, 0, 4), - "XX ", - "XX ", - " " - ))->setIngredient("X", Item::get(Item::STONE, '', 4))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::QUARTZ_BLOCK, 0, 1), - "XX ", - "XX ", - " " - ))->setIngredient("X", Item::get(Item::QUARTZ, 0, 4))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BRICK_STAIRS, 0, 4), - "P ", - "PP ", - "PPP" - ))->setIngredient("P", Item::get(Item::BRICKS_BLOCK, 0, 6))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BRICKS_BLOCK, 0, 1), - "XX ", - "XX " - ))->setIngredient("X", Item::get(Item::BRICK, 0, 4))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FLOWER_POT, 0, 1), - "X X", - " X ", - " " - ))->setIngredient("X", Item::get(Item::BRICK, 0, 3))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::SLAB, 4, 6), - " ", - "PPP", - " " - ))->setIngredient("P", Item::get(Item::BRICKS_BLOCK, 0, 3))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::QUARTZ_BLOCK, 1, 1), - " ", - "PP " - ))->setIngredient("P", Item::get(Item::SLAB, 6, 2))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::SLAB, 3, 6), - " ", - "PPP", - " " - ))->setIngredient("P", Item::get(Item::COBBLESTONE, 0, 3))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::COBBLESTONE, 0, 1), - " ", - "PP " - ))->setIngredient("P", Item::get(Item::SLAB, 3, 2))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::COBBLESTONE_WALL, 0, 6), - "PPP", - "PPP", - " " - ))->setIngredient("P", Item::get(Item::COBBLESTONE, 0, 6))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::COBBLESTONE_WALL, 1, 6), - "PPP", - "PPP", - " " - ))->setIngredient("P", Item::get(Item::MOSS_STONE, 0, 6))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::NETHER_BRICKS, 0, 1), - "XX ", - "XX " - ))->setIngredient("X", Item::get(Item::NETHER_BRICK, 0, 4))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::NETHER_BRICKS_STAIRS, 0, 4), - "XXX", - "XXX" - ))->setIngredient("X", Item::get(Item::NETHER_BRICKS, 0, 6))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::QUARTZ_BLOCK, 2, 2), - "P ", - "P ", - " " - ))->setIngredient("P", Item::get(Item::QUARTZ_BLOCK, 0, 2))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::SLAB, 6, 6), - " ", - "PPP", - " " - ))->setIngredient("P", Item::get(Item::QUARTZ_BLOCK, 0, 3))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::SANDSTONE_STAIRS, 0, 4), - "P ", - "PP ", - "PPP" - ))->setIngredient("P", Item::get(Item::SANDSTONE, 0, 6))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::RED_SANDSTONE_STAIRS, 0, 4), - "P ", - "PP ", - "PPP" - ))->setIngredient("P", Item::get(Item::RED_SANDSTONE, 0, 6))); - - $this->registerRecipe((new ShapedRecipe(Item::get(Item::SANDSTONE, 0, 1), - "XX", - "XX" - ))->setIngredient("X", Item::get(Item::SAND, 0, 4))); - - $this->registerRecipe((new ShapedRecipe(Item::get(Item::RED_SANDSTONE, 0, 1), - "XX", - "XX" - ))->setIngredient("X", Item::get(Item::SAND, 1, 4))); - - $this->registerRecipe((new ShapedRecipe(Item::get(Item::SANDSTONE, 2, 4), - "XX", - "XX" - ))->setIngredient("X", Item::get(Item::SANDSTONE, 0, 4))); - - $this->registerRecipe((new ShapedRecipe(Item::get(Item::RED_SANDSTONE, 2, 4), - "XX", - "XX" - ))->setIngredient("X", Item::get(Item::RED_SANDSTONE, 0, 4))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE, Stone::POLISHED_GRANITE, 4), - "XX ", - "XX " - ))->setIngredient("X", Item::get(Item::STONE, Stone::GRANITE, 4))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE, Stone::POLISHED_DIORITE, 4), - "XX ", - "XX " - ))->setIngredient("X", Item::get(Item::STONE, Stone::DIORITE, 4))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE, Stone::POLISHED_ANDESITE, 4), - "XX ", - "XX " - ))->setIngredient("X", Item::get(Item::STONE, Stone::ANDESITE, 4))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE_BRICK, 1, 1), - " ", - " Y ", - " X " - ))->setIngredient("X", Item::get(Item::STONE_BRICK, 0, 1))->setIngredient("Y", Item::get(Item::VINES, 0, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE, Stone::GRANITE, 1), - " ", - " Y ", - " X " - ))->setIngredient("X", Item::get(Item::STONE, Stone::DIORITE, 1))->setIngredient("Y", Item::get(Item::QUARTZ, 0, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE, Stone::DIORITE, 2), - "YY ", - "XX ", - " " - ))->setIngredient("X", Item::get(Item::COBBLESTONE, 0, 2))->setIngredient("Y", Item::get(Item::QUARTZ, 0, 2))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STONE, Stone::ANDESITE, 2), - " ", - " Y ", - " X " - ))->setIngredient("X", Item::get(Item::COBBLESTONE, 0, 1))->setIngredient("Y", Item::get(Item::STONE, Stone::DIORITE, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::FLOWER_POT, 0, 1), - "B B", - " B ", - " " - ))->setIngredient("B", Item::get(Item::BRICK, null, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::NOTEBLOCK, 0, 1), - "PPP", - "PRP", - "PPP" - ))->setIngredient("P", Item::get(Item::PLANK, null, 1))->setIngredient("R", Item::get(Item::REDSTONE, null, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::ITEM_FRAME, 0, 1), - "SSS", - "SLS", - "SSS" - ))->setIngredient("S", Item::get(Item::STICK, null, 1))->setIngredient("L", Item::get(Item::LEATHER, null, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::CAULDRON, 0, 1), - "I I", - "I I", - "III" - ))->setIngredient("I", Item::get(Item::IRON_INGOT, null, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::ANVIL, 0 ,1), - "III", - " G ", - "GGG" - ))->setIngredient("I", Item::get(Item::IRON_BLOCK, 0, 1))->setIngredient("G", Item::get(Item::IRON_INGOT, null, 1))); } } protected function registerBrewingStand(){ - /*$this->registerBrewingRecipe(new BrewingRecipe(Item::get(Item::POTION, Potion::AWKWARD, 1), Item::get(Item::NETHER_WART, 0, 1), Item::get(Item::POTION, Potion::WATER_BOTTLE, 1))); //Akward - // Potion - $this->registerBrewingRecipe(new BrewingRecipe(Item::get(Item::POTION, Potion::SWIFTNESS, 1), Item::get(Item::SUGAR, 0, 1), Item::get(Item::POTION, Potion::AWKWARD, 1))); //Swiftness - $this->registerBrewingRecipe(new BrewingRecipe(Item::get(Item::POTION, Potion::SWIFTNESS_T, 1), Item::get(Item::REDSTONE, 0, 1), Item::get(Item::POTION, Potion::SWIFTNESS, 1))); //Swiftness Extended - $this->registerBrewingRecipe(new BrewingRecipe(Item::get(Item::POTION, Potion::SWIFTNESS_TWO, 1), Item::get(Item::GLOWSTONE_DUST, 0, 1), Item::get(Item::POTION, Potion::SWIFTNESS, 1))); //Swiftness II -*/ //Potion //WATER_BOTTLE $this->registerBrewingRecipe(new BrewingRecipe(Item::get(Item::POTION, Potion::AWKWARD, 1), Item::get(Item::NETHER_WART, 0, 1), Item::get(Item::POTION, Potion::WATER_BOTTLE, 1))); @@ -867,455 +219,6 @@ protected function registerBrewingStand(){ } } - protected function registerFurnace(){ - //TODO 修复unll机制 Fix a bug that "NULL" do not working properly - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::STONE, 0, 1), Item::get(Item::COBBLESTONE, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::STONE_BRICK, 2, 1), Item::get(Item::STONE_BRICK, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::GLASS, 0, 1), Item::get(Item::SAND, null, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::GLASS, 0, 1), Item::get(Item::SAND, 1, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::COAL, 1, 1), Item::get(Item::TRUNK, null, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::COAL, 1, 1), Item::get(Item::TRUNK2, null, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::GOLD_INGOT, 0, 1), Item::get(Item::GOLD_ORE, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::IRON_INGOT, 0, 1), Item::get(Item::IRON_ORE, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::EMERALD, 0, 1), Item::get(Item::EMERALD_ORE, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::DIAMOND, 0, 1), Item::get(Item::DIAMOND_ORE, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::NETHER_BRICK, 0, 1), Item::get(Item::NETHERRACK, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::COOKED_PORKCHOP, 0, 1), Item::get(Item::RAW_PORKCHOP, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::BRICK, 0, 1), Item::get(Item::CLAY, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::COOKED_FISH, 0, 1), Item::get(Item::RAW_FISH, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::COOKED_FISH, 1, 1), Item::get(Item::RAW_FISH, 1, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::DYE, 2, 1), Item::get(Item::CACTUS, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::DYE, 1, 1), Item::get(Item::RED_MUSHROOM, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::STEAK, 0, 1), Item::get(Item::RAW_BEEF, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::COOKED_CHICKEN, 0, 1), Item::get(Item::RAW_CHICKEN, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::BAKED_POTATO, 0, 1), Item::get(Item::POTATO, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::HARDENED_CLAY, 0, 1), Item::get(Item::CLAY_BLOCK, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::COOKED_RABBIT, 0, 1), Item::get(Item::RAW_RABBIT, 0, 1))); - $this->registerRecipe(new FurnaceRecipe(Item::get(Item::COOKED_MUTTON, 0, 1), Item::get(Item::RAW_MUTTON, 0, 1))); - - - } - - private function sortAndAddRecipesArray(&$recipes){ - // Sort the recipes based on the result item name with the bubblesort algoritm. - for($i = 0; $i < count($recipes); ++$i){ - $current = $recipes[$i]; - $result = $current->getResult(); - for($j = count($recipes) - 1; $j > $i; --$j){ - if($this->sort($result, $recipes[$j]->getResult()) > 0){ - $swap = $current; - $current = $recipes[$j]; - $recipes[$j] = $swap; - $result = $current->getResult(); - } - } - $this->registerRecipe($current); - } - } - - private function createOneIngedientRecipe($recipeshape, $resultitem, $resultitemmeta, $resultitemamound, $ingedienttype, $ingredientmeta, $ingredientname, $inventoryType = ""){ - $ingredientamount = 0; - $height = 0; - // count how many of the ingredient are in the recipe and check height for big or small recipe. - foreach($recipeshape as $line){ - $height += 1; - $width = strlen($line); - $ingredientamount += substr_count($line, $ingredientname); - } - $recipe = null; - if($height < 3){ - // Process small recipe - $fullClassName = "devmine\\inventory\\" . $inventoryType . "ShapedRecipe";// $ShapeClass."ShapedRecipe"; - $recipe = ((new $fullClassName(Item::get($resultitem, $resultitemmeta, $resultitemamound), - ...$recipeshape - ))->setIngredient($ingredientname, Item::get($ingedienttype, $ingredientmeta, $ingredientamount))); - }else{ - // Process big recipe - $fullClassName = "devmine\\inventory\\" . $inventoryType . "BigShapedRecipe"; - $recipe = ((new $fullClassName(Item::get($resultitem, $resultitemmeta, $resultitemamound), - ...$recipeshape - ))->setIngredient($ingredientname, Item::get($ingedienttype, $ingredientmeta, $ingredientamount))); - } - return $recipe; - } - - protected function registerFood(){ - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::MELON_BLOCK, 0, 1), - "XXX", - "XXX", - "XXX" - ))->setIngredient("X", Item::get(Item::MELON_SLICE, 0, 9))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BEETROOT_SOUP, 0, 1), - "XXX", - "XXX", - " Y " - ))->setIngredient("X", Item::get(Item::BEETROOT, 0, 6))->setIngredient("Y", Item::get(Item::BOWL, 0, 1))); - - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BREAD, 0, 1), - " ", - " ", - "XXX" - ))->setIngredient("X", Item::get(Item::WHEAT, 0, 3))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::CAKE, 0, 1), - "XXX", - "YZY", - "AAA" - ))->setIngredient("X", Item::get(Item::BUCKET, 1, 3))->setIngredient("Y", Item::get(Item::SUGAR, 0, 2))->setIngredient("Z", Item::get(Item::EGG, 0, 1))->setIngredient("A", Item::get(Item::WHEAT, 0, 3))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::COOKIE, 0, 1), - " ", - " ", - "XYX" - ))->setIngredient("X", Item::get(Item::WHEAT, 0, 2))->setIngredient("Y", Item::get(Item::DYE, 3, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::GOLDEN_APPLE, 0, 1), - "XXX", - "XYX", - "XXX" - ))->setIngredient("X", Item::get(Item::GOLD_INGOT, 0, 9))->setIngredient("Y", Item::get(Item::APPLE, 0, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::ENCHANTED_GOLDEN_APPLE, 1, 1), - "XXX", - "XYX", - "XXX" - ))->setIngredient("X", Item::get(Item::GOLD_BLOCK, 0, 9))->setIngredient("Y", Item::get(Item::APPLE, 0, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::MUSHROOM_STEW, 0, 1), - " X ", - " Y ", - " Z " - ))->setIngredient("X", Item::get(Item::RED_MUSHROOM, 0, 1))->setIngredient("Y", Item::get(Item::BROWN_MUSHROOM, 0, 1))->setIngredient("Z", Item::get(Item::BOWL, 0, 1))); - - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::PUMPKIN_PIE, 0, 1), - " ", - "XY ", - "Z " - ))->setIngredient("X", Item::get(Item::PUMPKIN, 0, 1))->setIngredient("Y", Item::get(Item::EGG, 0, 1))->setIngredient("Z", Item::get(Item::SUGAR, 0, 1))); - - $this->registerRecipe((new ShapedRecipe(Item::get(Item::MELON_SEEDS, 0, 1), - "X ", - " " - ))->setIngredient("X", Item::get(Item::MELON_SLICE, 0, 1))); - - $this->registerRecipe((new ShapedRecipe(Item::get(Item::PUMPKIN_SEEDS, 0, 4), - "X ", - " " - ))->setIngredient("X", Item::get(Item::PUMPKIN, 0, 1))); - - $this->registerRecipe((new ShapedRecipe(Item::get(Item::RABBIT_STEW, 0, 1), - " A ", - "BCD", - " E " - ))->setIngredient("A", Item::get(Item::COOKED_RABBIT, 0, 1)) - ->setIngredient("B", Item::get(Item::CARROT, 0, 1)) - ->setIngredient("C", Item::get(Item::BAKED_POTATO, 0, 1)) - ->setIngredient("D", Item::get(Item::BROWN_MUSHROOM, 0, 1)) - ->setIngredient("E", Item::get(Item::BOWL, 0, 1)) - ); - - $this->registerRecipe((new ShapedRecipe(Item::get(Item::RABBIT_STEW, 0, 1), - " A ", - "BCD", - " E " - ))->setIngredient("A", Item::get(Item::COOKED_RABBIT, 0, 1)) - ->setIngredient("B", Item::get(Item::CARROT, 0, 1)) - ->setIngredient("C", Item::get(Item::BAKED_POTATO, 0, 1)) - ->setIngredient("D", Item::get(Item::RED_MUSHROOM, 0, 1)) - ->setIngredient("E", Item::get(Item::BOWL, 0, 1)) - ); - } - - protected function registerArmor(){ - $types = [ - [Item::LEATHER, Item::FIRE, Item::IRON_INGOT, Item::DIAMOND, Item::GOLD_INGOT], - [Item::LEATHER_CAP, Item::CHAIN_HELMET, Item::IRON_HELMET, Item::DIAMOND_HELMET, Item::GOLD_HELMET], - [ - Item::LEATHER_TUNIC, - Item::CHAIN_CHESTPLATE, - Item::IRON_CHESTPLATE, - Item::DIAMOND_CHESTPLATE, - Item::GOLD_CHESTPLATE - ], - [ - Item::LEATHER_PANTS, - Item::CHAIN_LEGGINGS, - Item::IRON_LEGGINGS, - Item::DIAMOND_LEGGINGS, - Item::GOLD_LEGGINGS - ], - [Item::LEATHER_BOOTS, Item::CHAIN_BOOTS, Item::IRON_BOOTS, Item::DIAMOND_BOOTS, Item::GOLD_BOOTS], - ]; - $shapes = [ - [ - "XXX", - "X X", - " " - ], - [ - "X X", - "XXX", - "XXX" - ], - [ - "XXX", - "X X", - "X X" - ], - [ - " ", - "X X", - "X X" - ] - ]; - for($i = 1; $i < 5; ++$i){ - foreach($types[$i] as $j => $type){ - $this->registerRecipe((new BigShapedRecipe(Item::get($type, 0, 1), ...$shapes[$i - 1]))->setIngredient("X", Item::get($types[0][$j], 0, 1))); - } - } - } - - protected function registerWeapons(){ - $types = [ - [Item::WOODEN_PLANK, Item::COBBLESTONE, Item::IRON_INGOT, Item::DIAMOND, Item::GOLD_INGOT], - [Item::WOODEN_SWORD, Item::STONE_SWORD, Item::IRON_SWORD, Item::DIAMOND_SWORD, Item::GOLD_SWORD], - ]; - for($i = 1; $i < 2; ++$i){ - foreach($types[$i] as $j => $type){ - $this->registerRecipe((new BigShapedRecipe(Item::get($type, 0, 1), - " X ", - " X ", - " I " - ))->setIngredient("X", Item::get($types[0][$j], null))->setIngredient("I", Item::get(Item::STICK))); - } - } - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::ARROW, 0, 1), - " F ", - " S ", - " P " - ))->setIngredient("S", Item::get(Item::STICK))->setIngredient("F", Item::get(Item::FLINT))->setIngredient("P", Item::get(Item::FEATHER))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BOW, 0, 1), - " X~", - "X ~", - " X~" - ))->setIngredient("~", Item::get(Item::STRING))->setIngredient("X", Item::get(Item::STICK))); - } - - protected function registerTools(){ - $types = [ - [Item::WOODEN_PLANK, Item::COBBLESTONE, Item::IRON_INGOT, Item::DIAMOND, Item::GOLD_INGOT], - [Item::WOODEN_PICKAXE, Item::STONE_PICKAXE, Item::IRON_PICKAXE, Item::DIAMOND_PICKAXE, Item::GOLD_PICKAXE], - [Item::WOODEN_SHOVEL, Item::STONE_SHOVEL, Item::IRON_SHOVEL, Item::DIAMOND_SHOVEL, Item::GOLD_SHOVEL], - [Item::WOODEN_AXE, Item::STONE_AXE, Item::IRON_AXE, Item::DIAMOND_AXE, Item::GOLD_AXE], - [Item::WOODEN_HOE, Item::STONE_HOE, Item::IRON_HOE, Item::DIAMOND_HOE, Item::GOLD_HOE], - ]; - $shapes = [ - [ - "XXX", - " I ", - " I " - ], - [ - " X ", - " I ", - " I " - ], - [ - "XX ", - "XI ", - " I " - ], - [ - "XX ", - " I ", - " I " - ] - ]; - for($i = 1; $i < 5; ++$i){ - foreach($types[$i] as $j => $type){ - $this->registerRecipe((new BigShapedRecipe(Item::get($type, 0, 1), ...$shapes[$i - 1]))->setIngredient("X", Item::get($types[0][$j], null))->setIngredient("I", Item::get(Item::STICK))); - } - } - $this->registerRecipe((new ShapedRecipe(Item::get(Item::FLINT_AND_STEEL, 0, 1), - " S", - "F " - ))->setIngredient("F", Item::get(Item::FLINT))->setIngredient("S", Item::get(Item::IRON_INGOT))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::SHEARS, 0, 1), - " X", - "X " - ))->setIngredient("X", Item::get(Item::IRON_INGOT))); - } - - protected function registerDyes(){ - /*$this->registerRecipe((new BigShapedRecipe(Item::get(Item::POTION, Potion::SWIFTNESS_TWO, 1), - "XXX", - "XXX", - "XXX" - ))->setIngredient("X", Item::get(Item::COBBLESTONE, 0, 9)));*/ - for($i = 0; $i < 16; ++$i){ - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOOL, 15 - $i, 1), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, $i, 1))->setIngredient("Y", Item::get(Item::WOOL, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::STAINED_CLAY, 15 - $i, 8), - "YYY", - "YXY", - "YYY" - ))->setIngredient("X", Item::get(Item::DYE, $i, 1))->setIngredient("Y", Item::get(Item::HARDENED_CLAY, 0, 8))); - //TODO: add glass things? - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOOL, 15 - $i, 1), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, $i, 1))->setIngredient("Y", Item::get(Item::WOOL, 0, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOOL, 15 - $i, 1), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, $i, 1))->setIngredient("Y", Item::get(Item::WOOL, 0, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::WOOL, 15 - $i, 1), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, $i, 1))->setIngredient("Y", Item::get(Item::WOOL, 0, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::CARPET, $i, 3), - "XX" - ))->setIngredient("X", Item::get(Item::WOOL, $i, 2))); - } - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 11, 2), - "X" - ))->setIngredient("X", Item::get(Item::DANDELION, 0, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 15, 3), - "X" - ))->setIngredient("X", Item::get(Item::BONE, 0, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 3, 2), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, 14, 1))->setIngredient("Y", Item::get(Item::DYE, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::DYE, 3, 3), - " X ", - " Y ", - " Z " - ))->setIngredient("X", Item::get(Item::DYE, 1, 1))->setIngredient("Y", Item::get(Item::DYE, 0, 1))->setIngredient("Z", Item::get(Item::DYE, 11, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 9, 2), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, 15, 1))->setIngredient("Y", Item::get(Item::DYE, 1, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 14, 2), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, 11, 1))->setIngredient("Y", Item::get(Item::DYE, 1, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 10, 2), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, 2, 1))->setIngredient("Y", Item::get(Item::DYE, 15, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 12, 2), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, 4, 1))->setIngredient("Y", Item::get(Item::DYE, 15, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 6, 2), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, 4, 1))->setIngredient("Y", Item::get(Item::DYE, 2, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 5, 2), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, 4, 1))->setIngredient("Y", Item::get(Item::DYE, 1, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::DYE, 13, 3), - " X ", - " Y ", - " Z " - ))->setIngredient("X", Item::get(Item::DYE, 4, 1))->setIngredient("Y", Item::get(Item::DYE, 1, 1))->setIngredient("Z", Item::get(Item::DYE, 15, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 1, 1), - "X" - ))->setIngredient("X", Item::get(Item::BEETROOT, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::DYE, 13, 4), - " X ", - "Y Y", - " Z " - ))->setIngredient("X", Item::get(Item::DYE, 15, 1))->setIngredient("Y", Item::get(Item::DYE, 1, 2))->setIngredient("Z", Item::get(Item::DYE, 4, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 13, 2), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, 5, 1))->setIngredient("Y", Item::get(Item::DYE, 9, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 8, 2), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, 0, 1))->setIngredient("Y", Item::get(Item::DYE, 15, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 7, 3), - "X ", - "YY" - ))->setIngredient("X", Item::get(Item::DYE, 0, 1))->setIngredient("Y", Item::get(Item::DYE, 15, 2))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::DYE, 7, 2), - "X ", - "Y " - ))->setIngredient("X", Item::get(Item::DYE, 0, 1))->setIngredient("Y", Item::get(Item::DYE, 8, 1))); - } - - protected function registerIngots(){ - $ingots = [ - Item::GOLD_BLOCK => Item::GOLD_INGOT, - Item::IRON_BLOCK => Item::IRON_INGOT, - Item::DIAMOND_BLOCK => Item::DIAMOND, - Item::EMERALD_BLOCK => Item::EMERALD, - Item::REDSTONE_BLOCK => Item::REDSTONE_DUST, - Item::COAL_BLOCK => Item::COAL, - Item::HAY_BALE => Item::WHEAT, - Item::GOLD_INGOT => Item::GOLD_NUGGET - ]; - foreach($ingots as $block => $ingot){ - $this->registerRecipe((new BigShapedRecipe(Item::get($ingot, 0, 9), - " ", - " D ", - " " - ))->setIngredient("D", Item::get($block, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get($block, 0, 1), - "GGG", - "GGG", - "GGG" - ))->setIngredient("G", Item::get($ingot, 0, 9))); - } - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::LAPIS_BLOCK, 0, 1), - "GGG", - "GGG", - "GGG" - ))->setIngredient("G", Item::get(Item::DYE, 4, 9))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::DYE, 4, 9), - " ", - " L ", - " " - ))->setIngredient("L", Item::get(Item::LAPIS_BLOCK, 0, 1))); - } - - protected function registerPotions(){ - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::BREWING_STAND, 0, 1), - " ", - " B ", - "CCC" - ))->setIngredient("B", Item::get(Item::BLAZE_ROD, 0, 1))->setIngredient("C", Item::get(Item::COBBLE, 0, 3))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::BLAZE_POWDER, 0, 2), - "B ", - " " - ))->setIngredient("B", Item::get(Item::BLAZE_ROD, 0, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::MAGMA_CREAM, 0, 1), - "BS", - " " - ))->setIngredient("B", Item::get(Item::BLAZE_ROD, 0, 1))->setIngredient("S", Item::get(Item::SLIMEBALL, 0, 1))); - $this->registerRecipe((new ShapedRecipe(Item::get(Item::FERMENTED_SPIDER_EYE, 0, 1), - "XY", - " Z" - ))->setIngredient("X", Item::get(Item::SPIDER_EYE, 0, 1))->setIngredient("Y", Item::get(Item::SUGAR, 0, 1))->setIngredient("Z", Item::get(Item::BROWN_MUSHROOM, 0, 1))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::GLISTERING_MELON, 0, 1), - "YYY", - "YXY", - "YYY" - ))->setIngredient("X", Item::get(Item::MELON, 0, 1))->setIngredient("Y", Item::get(Item::GOLD_NUGGET, 0, 8))); - $this->registerRecipe((new BigShapedRecipe(Item::get(Item::GOLDEN_CARROT, 0, 1), - "YYY", - "YXY", - "YYY" - ))->setIngredient("X", Item::get(Item::CARROT, 0, 1))->setIngredient("Y", Item::get(Item::GOLD_NUGGET, 0, 8))); - } - public function sort(Item $i1, Item $i2){ if($i1->getId() > $i2->getId()){ return 1; @@ -1350,6 +253,9 @@ public function getRecipes(){ return $this->recipes; } + public function getRecipesByResult(Item $item){ + return @array_values($this->recipeLookup[$item->getId() . ":" . $item->getDamage()]) ?? []; + } /** * @return FurnaceRecipe[] */ diff --git a/src/devmine/inventory/layout/CreativeItems.php b/src/devmine/inventory/layout/CreativeItems.php deleted file mode 100644 index 2ccb4e3..0000000 --- a/src/devmine/inventory/layout/CreativeItems.php +++ /dev/null @@ -1,706 +0,0 @@ - [ - ["id" => Item::COBBLESTONE], - ["id" => Item::STONE_BRICKS], - ["id" => Item::STONE_BRICKS, "meta" => StoneBricks::MOSSY], - ["id" => Item::STONE_BRICKS, "meta" => StoneBricks::CRACKED], - ["id" => Item::STONE_BRICKS, "meta" => StoneBricks::CHISELED], - ["id" => Item::MOSS_STONE], - ["id" => Item::PLANKS, "meta" => Planks::OAK], - ["id" => Item::PLANKS, "meta" => Planks::SPRUCE], - ["id" => Item::PLANKS, "meta" => Planks::BIRCH], - ["id" => Item::PLANKS, "meta" => Planks::JUNGLE], - ["id" => Item::PLANKS, "meta" => Planks::ACACIA], - ["id" => Item::PLANKS, "meta" => Planks::DARK_OAK], - ["id" => Item::BRICKS], - ["id" => Item::STONE], - ["id" => Item::STONE, "meta" => Stone::GRANITE], - ["id" => Item::STONE, "meta" => Stone::POLISHED_GRANITE], - ["id" => Item::STONE, "meta" => Stone::DIORITE], - ["id" => Item::STONE, "meta" => Stone::POLISHED_DIORITE], - ["id" => Item::STONE, "meta" => Stone::ANDESITE], - ["id" => Item::STONE, "meta" => Stone::POLISHED_ANDESITE], - ["id" => Item::DIRT], - ["id" => Item::PODZOL], - ["id" => Item::GRASS], - ["id" => Item::MYCELIUM], - ["id" => Item::CLAY_BLOCK], - ["id" => Item::HARDENED_CLAY], - ["id" => Item::STAINED_CLAY, "meta" => 0], //TODO: Make a class containing colour constants - ["id" => Item::STAINED_CLAY, "meta" => 1], - ["id" => Item::STAINED_CLAY, "meta" => 2], - ["id" => Item::STAINED_CLAY, "meta" => 3], - ["id" => Item::STAINED_CLAY, "meta" => 4], - ["id" => Item::STAINED_CLAY, "meta" => 5], - ["id" => Item::STAINED_CLAY, "meta" => 6], - ["id" => Item::STAINED_CLAY, "meta" => 7], - ["id" => Item::STAINED_CLAY, "meta" => 8], - ["id" => Item::STAINED_CLAY, "meta" => 9], - ["id" => Item::STAINED_CLAY, "meta" => 10], - ["id" => Item::STAINED_CLAY, "meta" => 11], - ["id" => Item::STAINED_CLAY, "meta" => 12], - ["id" => Item::STAINED_CLAY, "meta" => 13], - ["id" => Item::STAINED_CLAY, "meta" => 14], - ["id" => Item::STAINED_CLAY, "meta" => 15], - ["id" => Item::SANDSTONE], - ["id" => Item::SANDSTONE, "meta" => Sandstone::CHISELED], //Creeper sandstone - ["id" => Item::SANDSTONE, "meta" => Sandstone::SMOOTH], - ["id" => Item::RED_SANDSTONE], - ["id" => Item::RED_SANDSTONE, "meta" => Sandstone::CHISELED], //Wither sandstone - ["id" => Item::RED_SANDSTONE, "meta" => Sandstone::SMOOTH], - ["id" => Item::SAND], - ["id" => Item::SAND, "meta" => Sand::RED], - ["id" => Item::GRAVEL], - ["id" => Item::WOOD, "meta" => Wood::OAK], - ["id" => Item::WOOD, "meta" => Wood::SPRUCE], - ["id" => Item::WOOD, "meta" => Wood::BIRCH], - ["id" => Item::WOOD, "meta" => Wood::JUNGLE], - ["id" => Item::WOOD2, "meta" => Wood2::ACACIA], #blamemojang - ["id" => Item::WOOD2, "meta" => Wood2::DARK_OAK], - ["id" => Item::NETHER_BRICK_BLOCK], - ["id" => Item::NETHERRACK], - ["id" => Item::SOUL_SAND], - ["id" => Item::BEDROCK], - ["id" => Item::COBBLE_STAIRS], - ["id" => Item::OAK_WOOD_STAIRS], - ["id" => Item::SPRUCE_WOOD_STAIRS], - ["id" => Item::BIRCH_WOOD_STAIRS], - ["id" => Item::JUNGLE_WOOD_STAIRS], - ["id" => Item::ACACIA_WOOD_STAIRS], - ["id" => Item::DARK_OAK_WOOD_STAIRS], - ["id" => Item::BRICK_STAIRS], - ["id" => Item::SANDSTONE_STAIRS], - ["id" => Item::RED_SANDSTONE_STAIRS], - ["id" => Item::STONE_BRICK_STAIRS], - ["id" => Item::NETHER_BRICK_STAIRS], - ["id" => Item::QUARTZ_STAIRS], - ["id" => Item::STONE_SLAB], - ["id" => Item::STONE_SLAB, "meta" => StoneSlab::COBBLESTONE], - ["id" => Item::WOODEN_SLAB, "meta" => Planks::OAK], - ["id" => Item::WOODEN_SLAB, "meta" => Planks::SPRUCE], - ["id" => Item::WOODEN_SLAB, "meta" => Planks::BIRCH], - ["id" => Item::WOODEN_SLAB, "meta" => Planks::JUNGLE], - ["id" => Item::WOODEN_SLAB, "meta" => Planks::ACACIA], - ["id" => Item::WOODEN_SLAB, "meta" => Planks::DARK_OAK], - ["id" => Item::STONE_SLAB, "meta" => StoneSlab::BRICK], - ["id" => Item::STONE_SLAB, "meta" => StoneSlab::SANDSTONE], - ["id" => Item::RED_SANDSTONE_SLAB], #blamemojang - ["id" => Item::STONE_SLAB, "meta" => StoneSlab::STONE_BRICK], - ["id" => Item::STONE_SLAB, "meta" => StoneSlab::QUARTZ], - ["id" => Item::STONE_SLAB, "meta" => StoneSlab::NETHER_BRICK], - ["id" => Item::QUARTZ_BLOCK], - ["id" => Item::QUARTZ_BLOCK, "meta" => Quartz::QUARTZ_PILLAR], - ["id" => Item::QUARTZ_BLOCK, "meta" => Quartz::QUARTZ_CHISELED], - ["id" => Item::COAL_ORE], - ["id" => Item::IRON_ORE], - ["id" => Item::GOLD_ORE], - ["id" => Item::DIAMOND_ORE], - ["id" => Item::LAPIS_ORE], - ["id" => Item::REDSTONE_ORE], - ["id" => Item::EMERALD_ORE], - ["id" => Item::NETHER_QUARTZ_ORE], - ["id" => Item::OBSIDIAN], - ["id" => Item::ICE], - ["id" => Item::PACKED_ICE], - ["id" => Item::SNOW_BLOCK], - ["id" => Item::END_STONE], - ], - self::CATEGORY_DECORATION => [ - ["id" => Item::COBBLESTONE_WALL], - ["id" => Item::COBBLESTONE_WALL, "meta" => StoneWall::MOSSY_WALL], - ["id" => Item::LILY_PAD], - ["id" => Item::GOLD_BLOCK], - ["id" => Item::IRON_BLOCK], - ["id" => Item::DIAMOND_BLOCK], - ["id" => Item::LAPIS_BLOCK], - ["id" => Item::COAL_BLOCK], - ["id" => Item::EMERALD_BLOCK], - ["id" => Item::REDSTONE_BLOCK], - ["id" => Item::SNOW_LAYER], - ["id" => Item::GLASS], - ["id" => Item::GLOWSTONE], - ["id" => Item::VINES], - ["id" => Item::LADDER], - ["id" => Item::SPONGE], - ["id" => Item::GLASS_PANE], - ["id" => Item::OAK_DOOR], - ["id" => Item::SPRUCE_DOOR], - ["id" => Item::BIRCH_DOOR], - ["id" => Item::JUNGLE_DOOR], - ["id" => Item::ACACIA_DOOR], - ["id" => Item::DARK_OAK_DOOR], - ["id" => Item::IRON_DOOR], - ["id" => Item::WOODEN_TRAPDOOR], - ["id" => Item::IRON_TRAPDOOR], - ["id" => Item::FENCE, "meta" => Planks::OAK], - ["id" => Item::FENCE, "meta" => Planks::SPRUCE], - ["id" => Item::FENCE, "meta" => Planks::BIRCH], - ["id" => Item::FENCE, "meta" => Planks::JUNGLE], - ["id" => Item::FENCE, "meta" => Planks::ACACIA], - ["id" => Item::FENCE, "meta" => Planks::DARK_OAK], - ["id" => Item::NETHER_BRICK_FENCE], - ["id" => Item::OAK_FENCE_GATE], - ["id" => Item::SPRUCE_FENCE_GATE], - ["id" => Item::BIRCH_FENCE_GATE], - ["id" => Item::JUNGLE_FENCE_GATE], - ["id" => Item::ACACIA_FENCE_GATE], - ["id" => Item::DARK_OAK_FENCE_GATE], - ["id" => Item::IRON_BARS], - ["id" => Item::BED], - ["id" => Item::BOOKSHELF], - ["id" => Item::SIGN], - ["id" => Item::PAINTING], - ["id" => Item::ITEM_FRAME], - ["id" => Item::CRAFTING_TABLE], - ["id" => Item::STONECUTTER], - ["id" => Item::CHEST], - ["id" => Item::TRAPPED_CHEST], - ["id" => Item::FURNACE], - ["id" => Item::BREWING_STAND], - ["id" => Item::CAULDRON], - ["id" => Item::NOTEBLOCK], - ["id" => Item::END_PORTAL_FRAME], - ["id" => Item::ANVIL], - ["id" => Item::ANVIL, "meta" => Anvil::SLIGHTLY_DAMAGED], - ["id" => Item::ANVIL, "meta" => Anvil::VERY_DAMAGED], - ["id" => Item::DANDELION], - ["id" => Item::POPPY, "meta" => Flower::TYPE_POPPY], - ["id" => Item::POPPY, "meta" => Flower::TYPE_BLUE_ORCHID], - ["id" => Item::POPPY, "meta" => Flower::TYPE_ALLIUM], - ["id" => Item::POPPY, "meta" => Flower::TYPE_AZURE_BLUET], - ["id" => Item::POPPY, "meta" => Flower::TYPE_RED_TULIP], - ["id" => Item::POPPY, "meta" => Flower::TYPE_ORANGE_TULIP], - ["id" => Item::POPPY, "meta" => Flower::TYPE_WHITE_TULIP], - ["id" => Item::POPPY, "meta" => Flower::TYPE_PINK_TULIP], - ["id" => Item::POPPY, "meta" => Flower::TYPE_OXEYE_DAISY], - ["id" => Item::DOUBLE_PLANT, "meta" => DoublePlant::SUNFLOWER], - ["id" => Item::DOUBLE_PLANT, "meta" => DoublePlant::LILAC], - ["id" => Item::DOUBLE_PLANT, "meta" => DoublePlant::DOUBLE_TALLGRASS], - ["id" => Item::DOUBLE_PLANT, "meta" => DoublePlant::LARGE_FERN], - ["id" => Item::DOUBLE_PLANT, "meta" => DoublePlant::ROSE_BUSH], - ["id" => Item::DOUBLE_PLANT, "meta" => DoublePlant::PEONY], - ["id" => Item::BROWN_MUSHROOM], - ["id" => Item::RED_MUSHROOM], - ["id" => Item::BROWN_MUSHROOM_BLOCK, "meta" => 14], - ["id" => Item::RED_MUSHROOM_BLOCK, "meta" => 14], - ["id" => Item::BROWN_MUSHROOM_BLOCK, "meta" => 0], - ["id" => Item::BROWN_MUSHROOM_BLOCK, "meta" => 15], - ["id" => Item::CACTUS], - ["id" => Item::MELON_BLOCK], - ["id" => Item::PUMPKIN], - ["id" => Item::JACK_O_LANTERN], - ["id" => Item::COBWEB], - ["id" => Item::HAY_BALE], - ["id" => Item::TALL_GRASS, "meta" => TallGrass::NORMAL], - ["id" => Item::TALL_GRASS, "meta" => TallGrass::FERN], - ["id" => Item::DEAD_BUSH], - ["id" => Item::SAPLING, "meta" => Sapling::OAK], - ["id" => Item::SAPLING, "meta" => Sapling::SPRUCE], - ["id" => Item::SAPLING, "meta" => Sapling::BIRCH], - ["id" => Item::SAPLING, "meta" => Sapling::JUNGLE], - ["id" => Item::SAPLING, "meta" => Sapling::ACACIA], - ["id" => Item::SAPLING, "meta" => Sapling::DARK_OAK], - ["id" => Item::LEAVES, "meta" => Leaves::OAK], - ["id" => Item::LEAVES, "meta" => Leaves::SPRUCE], - ["id" => Item::LEAVES, "meta" => Leaves::BIRCH], - ["id" => Item::LEAVES, "meta" => Leaves::JUNGLE], - ["id" => Item::LEAVES2, "meta" => Leaves::ACACIA], #blamemojang - ["id" => Item::LEAVES2, "meta" => Leaves::DARK_OAK], - ["id" => Item::CAKE], - ["id" => Item::SKULL, "meta" => Skull::SKELETON], - ["id" => Item::SKULL, "meta" => Skull::WITHER_SKELETON], - ["id" => Item::SKULL, "meta" => Skull::ZOMBIE_HEAD], - ["id" => Item::SKULL, "meta" => Skull::STEVE_HEAD], - ["id" => Item::SKULL, "meta" => Skull::CREEPER_HEAD], - ["id" => Item::FLOWER_POT], - ["id" => Item::MONSTER_SPAWNER], - ["id" => Item::ENCHANTMENT_TABLE], - ["id" => Item::SLIME_BLOCK], - ["id" => Item::WOOL, "meta" => 0], //White - ["id" => Item::WOOL, "meta" => 8], //Light grey - ["id" => Item::WOOL, "meta" => 7], //Dark grey - ["id" => Item::WOOL, "meta" => 15], //Black - ["id" => Item::WOOL, "meta" => 12], //Brown - ["id" => Item::WOOL, "meta" => 14], //Red - ["id" => Item::WOOL, "meta" => 1], //Orange - ["id" => Item::WOOL, "meta" => 4], //Yellow - ["id" => Item::WOOL, "meta" => 5], //Lime - ["id" => Item::WOOL, "meta" => 13], //Green - ["id" => Item::WOOL, "meta" => 9], //Cyan - ["id" => Item::WOOL, "meta" => 3], //Light blue - ["id" => Item::WOOL, "meta" => 11], //Blue - ["id" => Item::WOOL, "meta" => 10], //Purple - ["id" => Item::WOOL, "meta" => 2], //Magenta - ["id" => Item::WOOL, "meta" => 6], //Pink - ["id" => Item::CARPET, "meta" => 0], //White - ["id" => Item::CARPET, "meta" => 8], //Light grey - ["id" => Item::CARPET, "meta" => 7], //Dark grey - ["id" => Item::CARPET, "meta" => 15], //Black - ["id" => Item::CARPET, "meta" => 12], //Brown - ["id" => Item::CARPET, "meta" => 14], //Red - ["id" => Item::CARPET, "meta" => 1], //Orange - ["id" => Item::CARPET, "meta" => 4], //Yellow - ["id" => Item::CARPET, "meta" => 5], //Lime - ["id" => Item::CARPET, "meta" => 13], //Green - ["id" => Item::CARPET, "meta" => 9], //Cyan - ["id" => Item::CARPET, "meta" => 3], //Light blue - ["id" => Item::CARPET, "meta" => 11], //Blue - ["id" => Item::CARPET, "meta" => 10], //Purple - ["id" => Item::CARPET, "meta" => 2], //Magenta - ["id" => Item::CARPET, "meta" => 6], //Pink - ], - self::CATEGORY_TOOLS => [ - ["id" => Item::RAIL], - ["id" => Item::POWERED_RAIL], - ["id" => Item::DETECTOR_RAIL], - ["id" => Item::ACTIVATOR_RAIL], - ["id" => Item::TORCH], - ["id" => Item::BUCKET], - ["id" => Item::BUCKET, "meta" => 1], - ["id" => Item::BUCKET, "meta" => 8], - ["id" => Item::BUCKET, "meta" => 10], - ["id" => Item::TNT], - ["id" => Item::LEAD], - ["id" => Item::NAMETAG], - ["id" => Item::REDSTONE_DUST], - ["id" => Item::BOW], - ["id" => Item::FISHING_ROD], - ["id" => Item::FLINT_STEEL], - ["id" => Item::SHEARS], - ["id" => Item::CLOCK], - ["id" => Item::COMPASS], - ["id" => Item::MINECART], - ["id" => Item::MINECART_WITH_CHEST], - ["id" => Item::MINECART_WITH_HOPPER], - ["id" => Item::MINECART_WITH_TNT], - ["id" => Item::BOAT, "meta" => Planks::OAK], - ["id" => Item::BOAT, "meta" => Planks::SPRUCE], - ["id" => Item::BOAT, "meta" => Planks::BIRCH], - ["id" => Item::BOAT, "meta" => Planks::JUNGLE], - ["id" => Item::BOAT, "meta" => Planks::ACACIA], - ["id" => Item::BOAT, "meta" => Planks::DARK_OAK], - ["id" => Item::SADDLE], - ["id" => Item::LEATHER_HORSE_ARMOR], - ["id" => Item::IRON_HORSE_ARMOR], - ["id" => Item::GOLD_HORSE_ARMOR], - ["id" => Item::DIAMOND_HORSE_ARMOR], - ["id" => Item::SPAWN_EGG, "meta" => 15], //Villager - ["id" => Item::SPAWN_EGG, "meta" => 10], //Chicken - ["id" => Item::SPAWN_EGG, "meta" => 11], //Cow - ["id" => Item::SPAWN_EGG, "meta" => 12], //Pig - ["id" => Item::SPAWN_EGG, "meta" => 13], //Sheep - ["id" => Item::SPAWN_EGG, "meta" => 14], //Wolf - ["id" => Item::SPAWN_EGG, "meta" => 22], //Ocelot - ["id" => Item::SPAWN_EGG, "meta" => 16], //Mooshroom - ["id" => Item::SPAWN_EGG, "meta" => 19], //Bat - ["id" => Item::SPAWN_EGG, "meta" => 18], //Rabbit - ["id" => Item::SPAWN_EGG, "meta" => 23], //Horse - ["id" => Item::SPAWN_EGG, "meta" => 24], //Donkey - ["id" => Item::SPAWN_EGG, "meta" => 25], //Mule - ["id" => Item::SPAWN_EGG, "meta" => 26], //Skeleton Horse - ["id" => Item::SPAWN_EGG, "meta" => 27], //Zombie horse - ["id" => Item::SPAWN_EGG, "meta" => 33], //Creeper - ["id" => Item::SPAWN_EGG, "meta" => 38], //Enderman - ["id" => Item::SPAWN_EGG, "meta" => 39], //Silverfish - ["id" => Item::SPAWN_EGG, "meta" => 34], //Skeleton - ["id" => Item::SPAWN_EGG, "meta" => 48], //Wither skeleton - ["id" => Item::SPAWN_EGG, "meta" => 46], //Stray - ["id" => Item::SPAWN_EGG, "meta" => 37], //Slime - ["id" => Item::SPAWN_EGG, "meta" => 35], //Spider - ["id" => Item::SPAWN_EGG, "meta" => 32], //Zombie - ["id" => Item::SPAWN_EGG, "meta" => 36], //Zombie Pigman - ["id" => Item::SPAWN_EGG, "meta" => 47], //Husk - ["id" => Item::SPAWN_EGG, "meta" => 17], //Squid - ["id" => Item::SPAWN_EGG, "meta" => 40], //Cave Spider - ["id" => Item::SPAWN_EGG, "meta" => 45], //Witch - ["id" => Item::SPAWN_EGG, "meta" => 42], //Magma Cube - ["id" => Item::SPAWN_EGG, "meta" => 41], //Ghast - ["id" => Item::SPAWN_EGG, "meta" => 43], //Blaze - ["id" => Item::FIRE_CHARGE], - ["id" => Item::WOODEN_SWORD], - ["id" => Item::WOODEN_HOE], - ["id" => Item::WOODEN_SHOVEL], - ["id" => Item::WOODEN_PICKAXE], - ["id" => Item::WOODEN_AXE], - ["id" => Item::STONE_SWORD], - ["id" => Item::STONE_HOE], - ["id" => Item::STONE_SHOVEL], - ["id" => Item::STONE_PICKAXE], - ["id" => Item::STONE_AXE], - ["id" => Item::IRON_SWORD], - ["id" => Item::IRON_HOE], - ["id" => Item::IRON_SHOVEL], - ["id" => Item::IRON_PICKAXE], - ["id" => Item::IRON_AXE], - ["id" => Item::DIAMOND_SWORD], - ["id" => Item::DIAMOND_HOE], - ["id" => Item::DIAMOND_SHOVEL], - ["id" => Item::DIAMOND_PICKAXE], - ["id" => Item::DIAMOND_AXE], - ["id" => Item::GOLD_SWORD], - ["id" => Item::GOLD_HOE], - ["id" => Item::GOLD_SHOVEL], - ["id" => Item::GOLD_PICKAXE], - ["id" => Item::GOLD_AXE], - ["id" => Item::LEATHER_CAP], - ["id" => Item::LEATHER_TUNIC], - ["id" => Item::LEATHER_PANTS], - ["id" => Item::LEATHER_BOOTS], - ["id" => Item::CHAIN_HELMET], - ["id" => Item::CHAIN_CHESTPLATE], - ["id" => Item::CHAIN_LEGGINGS], - ["id" => Item::CHAIN_BOOTS], - ["id" => Item::IRON_HELMET], - ["id" => Item::IRON_CHESTPLATE], - ["id" => Item::IRON_LEGGINGS], - ["id" => Item::IRON_BOOTS], - ["id" => Item::DIAMOND_HELMET], - ["id" => Item::DIAMOND_CHESTPLATE], - ["id" => Item::DIAMOND_LEGGINGS], - ["id" => Item::DIAMOND_BOOTS], - ["id" => Item::GOLD_HELMET], - ["id" => Item::GOLD_CHESTPLATE], - ["id" => Item::GOLD_LEGGINGS], - ["id" => Item::GOLD_BOOTS], - ["id" => Item::LEVER], - ["id" => Item::REDSTONE_LAMP], - ["id" => Item::REDSTONE_TORCH], - ["id" => Item::WOODEN_PRESSURE_PLATE], - ["id" => Item::STONE_PRESSURE_PLATE], - ["id" => Item::GOLD_PRESSURE_PLATE], - ["id" => Item::IRON_PRESSURE_PLATE], - ["id" => Item::WOODEN_BUTTON, "meta" => 5], //meta 5: Fix inventory icon looking wrong - ["id" => Item::STONE_BUTTON, "meta" => 5], - ["id" => Item::DAYLIGHT_SENSOR], - ["id" => Item::TRIPWIRE_HOOK], - ["id" => Item::REPEATER], - ["id" => Item::COMPARATOR], - ["id" => Item::DISPENSER], - ["id" => Item::DROPPER], - ["id" => Item::PISTON], - ["id" => Item::STICKY_PISTON], - ["id" => Item::OBSERVER], - ["id" => Item::HOPPER], - ["id" => Item::SNOWBALL] #blamemojang - ], - self::CATEGORY_MISCELLANEOUS => [ - ["id" => Item::COAL], - ["id" => Item::COAL, "meta" => Coal::CHARCOAL], - ["id" => Item::DIAMOND], - ["id" => Item::IRON_INGOT], - ["id" => Item::GOLD_INGOT], - ["id" => Item::EMERALD], - ["id" => Item::STICK], - ["id" => Item::BOWL], - ["id" => Item::STRING], - ["id" => Item::FEATHER], - ["id" => Item::FLINT], - ["id" => Item::LEATHER], - ["id" => Item::RABBIT_HIDE], - ["id" => Item::CLAY], - ["id" => Item::SUGAR], - ["id" => Item::QUARTZ], - ["id" => Item::PAPER], - ["id" => Item::BOOK], - ["id" => Item::ARROW], - ["id" => Item::BONE], - ["id" => Item::EMPTY_MAP], - ["id" => Item::SUGARCANE], - ["id" => Item::WHEAT], - ["id" => Item::ARROW, "meta" => 6], //TODO: Pull these out into the Arrow class - ["id" => Item::ARROW, "meta" => 7], - ["id" => Item::ARROW, "meta" => 8], - ["id" => Item::ARROW, "meta" => 9], - ["id" => Item::ARROW, "meta" => 10], - ["id" => Item::ARROW, "meta" => 11], - ["id" => Item::ARROW, "meta" => 12], - ["id" => Item::ARROW, "meta" => 13], - ["id" => Item::ARROW, "meta" => 14], - ["id" => Item::ARROW, "meta" => 15], - ["id" => Item::ARROW, "meta" => 16], - ["id" => Item::ARROW, "meta" => 17], - ["id" => Item::ARROW, "meta" => 18], - ["id" => Item::ARROW, "meta" => 19], - ["id" => Item::ARROW, "meta" => 20], - ["id" => Item::ARROW, "meta" => 21], - ["id" => Item::ARROW, "meta" => 22], - ["id" => Item::ARROW, "meta" => 23], - ["id" => Item::ARROW, "meta" => 24], - ["id" => Item::ARROW, "meta" => 25], - ["id" => Item::ARROW, "meta" => 26], - ["id" => Item::ARROW, "meta" => 27], - ["id" => Item::ARROW, "meta" => 28], - ["id" => Item::ARROW, "meta" => 29], - ["id" => Item::ARROW, "meta" => 30], - ["id" => Item::ARROW, "meta" => 31], - ["id" => Item::ARROW, "meta" => 32], - ["id" => Item::ARROW, "meta" => 33], - ["id" => Item::ARROW, "meta" => 34], - ["id" => Item::ARROW, "meta" => 35], - ["id" => Item::ARROW, "meta" => 36], - ["id" => Item::SEEDS], - ["id" => Item::PUMPKIN_SEEDS], - ["id" => Item::MELON_SEEDS], - ["id" => Item::BEETROOT_SEEDS], - ["id" => Item::EGG], - ["id" => Item::APPLE], - ["id" => Item::GOLDEN_APPLE], - ["id" => Item::ENCHANTED_GOLDEN_APPLE], - ["id" => Item::RAW_FISH], - ["id" => Item::RAW_SALMON], - ["id" => Item::CLOWN_FISH], - ["id" => Item::PUFFER_FISH], - ["id" => Item::COOKED_FISH], - ["id" => Item::COOKED_SALMON], - ["id" => Item::ROTTEN_FLESH], - ["id" => Item::MUSHROOM_STEW], - ["id" => Item::BREAD], - ["id" => Item::RAW_PORKCHOP], - ["id" => Item::COOKED_PORKCHOP], - ["id" => Item::RAW_CHICKEN], - ["id" => Item::COOKED_CHICKEN], - ["id" => Item::RAW_MUTTON], - ["id" => Item::COOKED_MUTTON], - ["id" => Item::RAW_BEEF], - ["id" => Item::STEAK], - ["id" => Item::MELON], - ["id" => Item::CARROT], - ["id" => Item::POTATO], - ["id" => Item::BAKED_POTATO], - ["id" => Item::POISONOUS_POTATO], - ["id" => Item::BEETROOT], - ["id" => Item::COOKIE], - ["id" => Item::PUMPKIN_PIE], - ["id" => Item::RAW_RABBIT], - ["id" => Item::COOKED_RABBIT], - ["id" => Item::RABBIT_STEW], - ["id" => Item::MAGMA_CREAM], - ["id" => Item::BLAZE_ROD], - ["id" => Item::GOLD_NUGGET], - ["id" => Item::GOLDEN_CARROT], - ["id" => Item::GLISTERING_MELON], - ["id" => Item::RABBIT_FOOT], - ["id" => Item::GHAST_TEAR], - ["id" => Item::SLIMEBALL], - ["id" => Item::BLAZE_POWDER], - ["id" => Item::NETHER_WART], - ["id" => Item::GUNPOWDER], - ["id" => Item::GLOWSTONE_DUST], - ["id" => Item::SPIDER_EYE], - ["id" => Item::FERMENTED_SPIDER_EYE], - ["id" => Item::CARROT_ON_A_STICK], - ["id" => Item::BOTTLE_O_ENCHANTING], - /*["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_PROTECTION, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_PROTECTION, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_PROTECTION, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_PROTECTION, "lvl" => 4]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_FIRE_PROTECTION, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_FIRE_PROTECTION, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_FIRE_PROTECTION, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_FIRE_PROTECTION, "lvl" => 4]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_FALL_PROTECTION, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_FALL_PROTECTION, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_FALL_PROTECTION, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_FALL_PROTECTION, "lvl" => 4]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_EXPLOSION_PROTECTION, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_EXPLOSION_PROTECTION, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_EXPLOSION_PROTECTION, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_EXPLOSION_PROTECTION, "lvl" => 4]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_PROJECsolidentity_PROTECTION, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_PROJECsolidentity_PROTECTION, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_PROJECsolidentity_PROTECTION, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_PROJECsolidentity_PROTECTION, "lvl" => 4]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_THORNS, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_THORNS, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_ARMOR_THORNS, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WATER_BREATHING, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WATER_BREATHING, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WATER_BREATHING, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WATER_SPEED, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WATER_SPEED, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WATER_SPEED, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WATER_AFFINITY, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_SHARPNESS, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_SHARPNESS, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_SHARPNESS, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_SHARPNESS, "lvl" => 4]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_SHARPNESS, "lvl" => 5]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_SMITE, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_SMITE, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_SMITE, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_SMITE, "lvl" => 4]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_SMITE, "lvl" => 5]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_ARTHROPODS, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_ARTHROPODS, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_ARTHROPODS, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_ARTHROPODS, "lvl" => 4]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_ARTHROPODS, "lvl" => 5]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_KNOCKBACK, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_KNOCKBACK, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_FIRE_ASPECT, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_FIRE_ASPECT, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_LOOTING, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_LOOTING, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_WEAPON_LOOTING, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_EFFICIENCY, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_EFFICIENCY, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_EFFICIENCY, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_EFFICIENCY, "lvl" => 4]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_EFFICIENCY, "lvl" => 5]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_SILK_TOUCH, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_DURABILITY, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_DURABILITY, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_DURABILITY, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_FORTUNE, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_FORTUNE, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_MINING_FORTUNE, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_BOW_POWER, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_BOW_POWER, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_BOW_POWER, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_BOW_POWER, "lvl" => 4]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_BOW_POWER, "lvl" => 5]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_BOW_KNOCKBACK, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_BOW_KNOCKBACK, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_BOW_FLAME, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_BOW_INFINITY, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_FISHING_FORTUNE, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_FISHING_FORTUNE, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_FISHING_FORTUNE, "lvl" => 3]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_FISHING_LURE, "lvl" => 1]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_FISHING_LURE, "lvl" => 2]]], - ["id" => Item::ENCHANTED_BOOK, "ench" => [["id" => Enchantment::TYPE_FISHING_LURE, "lvl" => 3]]],*/ - ["id" => Item::DYE, "meta" => Dye::BLACK], - ["id" => Item::DYE, "meta" => Dye::GRAY], - ["id" => Item::DYE, "meta" => Dye::LIGHT_GRAY], - ["id" => Item::DYE, "meta" => Dye::BONE_MEAL], - ["id" => Item::DYE, "meta" => Dye::LIGHT_BLUE], - ["id" => Item::DYE, "meta" => Dye::ORANGE], - ["id" => Item::DYE, "meta" => Dye::RED], - ["id" => Item::DYE, "meta" => Dye::LAPIS_LAZULI], - ["id" => Item::DYE, "meta" => Dye::PURPLE], - ["id" => Item::DYE, "meta" => Dye::MAGENTA], - ["id" => Item::DYE, "meta" => Dye::PINK], - ["id" => Item::DYE, "meta" => Dye::COCOA_BEANS], - ["id" => Item::DYE, "meta" => Dye::YELLOW], - ["id" => Item::DYE, "meta" => Dye::LIME], - ["id" => Item::DYE, "meta" => Dye::GREEN], - ["id" => Item::DYE, "meta" => Dye::CYAN], - ["id" => Item::GLASS_BOTTLE], - ["id" => Item::POTION, "meta" => Potion::WATER_BOTTLE], - ["id" => Item::POTION, "meta" => Potion::MUNDANE], - ["id" => Item::POTION, "meta" => Potion::MUNDANE_EXTENDED], - ["id" => Item::POTION, "meta" => Potion::THICK], - ["id" => Item::POTION, "meta" => Potion::AWKWARD], - ["id" => Item::POTION, "meta" => Potion::NIGHT_VISION], - ["id" => Item::POTION, "meta" => Potion::NIGHT_VISION_T], - ["id" => Item::POTION, "meta" => Potion::INVISIBILITY], - ["id" => Item::POTION, "meta" => Potion::INVISIBILITY_T], - ["id" => Item::POTION, "meta" => Potion::LEAPING], - ["id" => Item::POTION, "meta" => Potion::LEAPING_T], - ["id" => Item::POTION, "meta" => Potion::LEAPING_TWO], - ["id" => Item::POTION, "meta" => Potion::FIRE_RESISTANCE], - ["id" => Item::POTION, "meta" => Potion::FIRE_RESISTANCE_T], - ["id" => Item::POTION, "meta" => Potion::SWIFTNESS], - ["id" => Item::POTION, "meta" => Potion::SWIFTNESS_T], - ["id" => Item::POTION, "meta" => Potion::SWIFTNESS_TWO], - ["id" => Item::POTION, "meta" => Potion::SLOWNESS], - ["id" => Item::POTION, "meta" => Potion::SLOWNESS_T], - ["id" => Item::POTION, "meta" => Potion::WATER_BREATHING], - ["id" => Item::POTION, "meta" => Potion::WATER_BREATHING_T], - ["id" => Item::POTION, "meta" => Potion::HEALING], - ["id" => Item::POTION, "meta" => Potion::HEALING_TWO], - ["id" => Item::POTION, "meta" => Potion::HARMING], - ["id" => Item::POTION, "meta" => Potion::HARMING_TWO], - ["id" => Item::POTION, "meta" => Potion::POISON], - ["id" => Item::POTION, "meta" => Potion::POISON_T], - ["id" => Item::POTION, "meta" => Potion::POISON_TWO], - ["id" => Item::POTION, "meta" => Potion::REGENERATION], - ["id" => Item::POTION, "meta" => Potion::REGENERATION_T], - ["id" => Item::POTION, "meta" => Potion::REGENERATION_TWO], - ["id" => Item::POTION, "meta" => Potion::STRENGTH], - ["id" => Item::POTION, "meta" => Potion::STRENGTH_T], - ["id" => Item::POTION, "meta" => Potion::STRENGTH_TWO], - ["id" => Item::POTION, "meta" => Potion::WEAKNESS], - ["id" => Item::POTION, "meta" => Potion::WEAKNESS_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::WATER_BOTTLE], - ["id" => Item::SPLASH_POTION, "meta" => Potion::MUNDANE], - ["id" => Item::SPLASH_POTION, "meta" => Potion::MUNDANE_EXTENDED], - ["id" => Item::SPLASH_POTION, "meta" => Potion::THICK], - ["id" => Item::SPLASH_POTION, "meta" => Potion::AWKWARD], - ["id" => Item::SPLASH_POTION, "meta" => Potion::NIGHT_VISION], - ["id" => Item::SPLASH_POTION, "meta" => Potion::NIGHT_VISION_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::INVISIBILITY], - ["id" => Item::SPLASH_POTION, "meta" => Potion::INVISIBILITY_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::LEAPING], - ["id" => Item::SPLASH_POTION, "meta" => Potion::LEAPING_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::LEAPING_TWO], - ["id" => Item::SPLASH_POTION, "meta" => Potion::FIRE_RESISTANCE], - ["id" => Item::SPLASH_POTION, "meta" => Potion::FIRE_RESISTANCE_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::SWIFTNESS], - ["id" => Item::SPLASH_POTION, "meta" => Potion::SWIFTNESS_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::SWIFTNESS_TWO], - ["id" => Item::SPLASH_POTION, "meta" => Potion::SLOWNESS], - ["id" => Item::SPLASH_POTION, "meta" => Potion::SLOWNESS_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::WATER_BREATHING], - ["id" => Item::SPLASH_POTION, "meta" => Potion::WATER_BREATHING_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::HEALING], - ["id" => Item::SPLASH_POTION, "meta" => Potion::HEALING_TWO], - ["id" => Item::SPLASH_POTION, "meta" => Potion::HARMING], - ["id" => Item::SPLASH_POTION, "meta" => Potion::HARMING_TWO], - ["id" => Item::SPLASH_POTION, "meta" => Potion::POISON], - ["id" => Item::SPLASH_POTION, "meta" => Potion::POISON_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::POISON_TWO], - ["id" => Item::SPLASH_POTION, "meta" => Potion::REGENERATION], - ["id" => Item::SPLASH_POTION, "meta" => Potion::REGENERATION_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::REGENERATION_TWO], - ["id" => Item::SPLASH_POTION, "meta" => Potion::STRENGTH], - ["id" => Item::SPLASH_POTION, "meta" => Potion::STRENGTH_T], - ["id" => Item::SPLASH_POTION, "meta" => Potion::STRENGTH_TWO], - ["id" => Item::SPLASH_POTION, "meta" => Potion::WEAKNESS], - ["id" => Item::SPLASH_POTION, "meta" => Potion::WEAKNESS_T], - ], - ]; - -} diff --git a/src/devmine/inventory/layout/DispenserInventory.php b/src/devmine/inventory/layout/DispenserInventory.php index 0221f3e..f305a5e 100644 --- a/src/devmine/inventory/layout/DispenserInventory.php +++ b/src/devmine/inventory/layout/DispenserInventory.php @@ -1,14 +1,31 @@ left = $left->getRealInventory(); $this->right = $right->getRealInventory(); - $items = array_merge($this->left->getContents(), $this->right->getContents()); + $items = array_merge($this->left->getContents(true), $this->right->getContents(true)); BaseInventory::__construct($this, InventoryType::get(InventoryType::DOUBLE_CHEST), $items); } diff --git a/src/devmine/inventory/layout/DropItemTransaction.php b/src/devmine/inventory/layout/DropItemTransaction.php new file mode 100644 index 0000000..f0cf4b6 --- /dev/null +++ b/src/devmine/inventory/layout/DropItemTransaction.php @@ -0,0 +1,76 @@ +targetItem = $droppedItem; + } + + public function setSourceItem(Item $item){ + //Nothing to update + } + + public function getInventory(){ + return null; + } + + public function getSlot(){ + return null; + } + + public function sendSlotUpdate(Player $source){ + //Nothing to update + } + + public function getChange(){ + return ["in" => $this->getTargetItem(), + "out" => null]; + } + + public function execute(Player $source): bool{ + $droppedItem = $this->getTargetItem(); + if(!$source->getServer()->allowInventoryCheats and !$source->isCreative()){ + if(!$source->getFloatingInventory()->contains($droppedItem)){ + return false; + } + $source->getFloatingInventory()->removeItem($droppedItem); + } + $source->dropItem($droppedItem); + return true; + } +} \ No newline at end of file diff --git a/src/devmine/inventory/layout/DropperInventory.php b/src/devmine/inventory/layout/DropperInventory.php index 974cf64..a28b13f 100644 --- a/src/devmine/inventory/layout/DropperInventory.php +++ b/src/devmine/inventory/layout/DropperInventory.php @@ -1,14 +1,31 @@ holder; } + + public function getResultSlotIndex(){ + return -1; //enchanting tables don't have result slots, they modify the item in the target slot instead + } public function onOpen(Player $who){ parent::onOpen($who); @@ -63,16 +68,16 @@ private function randomFloat($min = 0, $max = 1){ return $min + mt_rand() / mt_getrandmax() * ($max - $min); } - public function onSlotChange($index, $before){ - parent::onSlotChange($index, $before); + public function onSlotChange($index, $before, $send){ + parent::onSlotChange($index, $before, $send); - if($index == 0){ + if($index === 0){ $item = $this->getItem(0); - if($item->getId() == Item::AIR){ + if($item->getId() === Item::AIR){ $this->entries = null; }elseif($before->getId() == Item::AIR and !$item->hasEnchantments()){ //before enchant - if($this->entries == null){ + if($this->entries === null){ $enchantAbility = Enchantment::getEnchantAbility($item); $this->entries = []; for($i = 0; $i < 3; $i++){ @@ -166,7 +171,7 @@ public function onClose(Player $who){ $this->clear($i); } - if(count($this->getViewers()) == 0){ + if(count($this->getViewers()) === 0){ $this->levels = null; $this->entries = null; $this->bookshelfAmount = 0; @@ -196,7 +201,7 @@ public function checkEnts(array $ent1, array $ent2){ } public function onEnchant(Player $who, Item $before, Item $after){ - $result = ($before->getId() == Item::BOOK) ? new EnchantedBook() : $before; + $result = ($before->getId() === Item::BOOK) ? new EnchantedBook() : $before; if(!$before->hasEnchantments() and $after->hasEnchantments() and $after->getId() == $result->getId() and $this->levels != null and $this->entries != null ){ @@ -204,7 +209,7 @@ public function onEnchant(Player $who, Item $before, Item $after){ for($i = 0; $i < 3; $i++){ if($this->checkEnts($enchantments, $this->entries[$i]->getEnchantments())){ $lapis = $this->getItem(1); - $level = $who->getExpLevel(); + $level = $who->getXpLevel(); $cost = $this->entries[$i]->getCost(); if($lapis->getId() == Item::DYE and $lapis->getDamage() == Dye::BLUE and $lapis->getCount() > $i and $level >= $cost){ foreach($enchantments as $enchantment){ @@ -213,7 +218,7 @@ public function onEnchant(Player $who, Item $before, Item $after){ $this->setItem(0, $result); $lapis->setCount($lapis->getCount() - $i - 1); $this->setItem(1, $lapis); - $who->setExpLevel($level - $i - 1); + $who->takeXpLevel($i + 1); break; } } @@ -244,7 +249,7 @@ public function countBookshelf() : int{ public function sendEnchantmentList(){ $pk = new CraftingDataPacket(); - if($this->entries != null and $this->levels != null){ + if($this->entries !== null and $this->levels !== null){ $list = new EnchantmentList(count($this->entries)); for($i = 0; $i < count($this->entries); $i++){ $list->setSlot($i, $this->entries[$i]); @@ -281,7 +286,7 @@ public function removeConflictEnchantment(Enchantment $enchantment, array $encha continue; } - if(($id == Enchantment::TYPE_MINING_SILK_TOUCH and $enchantment->getId() == Enchantment::TYPE_MINING_FORTUNE) or ($id == Enchantment::TYPE_MINING_FORTUNE and $enchantment->getId() == Enchantment::TYPE_MINING_SILK_TOUCH)){ + if(($id === Enchantment::TYPE_MINING_SILK_TOUCH and $enchantment->getId() === Enchantment::TYPE_MINING_FORTUNE) or ($id === Enchantment::TYPE_MINING_FORTUNE and $enchantment->getId() === Enchantment::TYPE_MINING_SILK_TOUCH)){ //Protection unset($enchantments[$id]); continue; diff --git a/src/devmine/inventory/layout/FakeBlockMenu.php b/src/devmine/inventory/layout/FakeBlockMenu.php index 6e1211c..01a4088 100644 --- a/src/devmine/inventory/layout/FakeBlockMenu.php +++ b/src/devmine/inventory/layout/FakeBlockMenu.php @@ -5,7 +5,7 @@ namespace devmine\inventory\layout; -use devmine\levels\Position; +use devmine\worlds\Position; class FakeBlockMenu extends Position implements InventoryHolder{ diff --git a/src/devmine/inventory/layout/FloatingInventory.php b/src/devmine/inventory/layout/FloatingInventory.php new file mode 100644 index 0000000..b9d8472 --- /dev/null +++ b/src/devmine/inventory/layout/FloatingInventory.php @@ -0,0 +1,36 @@ +getItem(2); + return $this->getItem(self::RESULT); } /** * @return Item */ public function getFuel(){ - return $this->getItem(1); + return $this->getItem(self::FUEL); } /** * @return Item */ public function getSmelting(){ - return $this->getItem(0); + return $this->getItem(self::SMELTING); } /** @@ -47,7 +52,7 @@ public function getSmelting(){ * @return bool */ public function setResult(Item $item){ - return $this->setItem(2, $item); + return $this->setItem(self::RESULT, $item); } /** @@ -56,7 +61,7 @@ public function setResult(Item $item){ * @return bool */ public function setFuel(Item $item){ - return $this->setItem(1, $item); + return $this->setItem(self::FUEL, $item); } /** @@ -65,11 +70,11 @@ public function setFuel(Item $item){ * @return bool */ public function setSmelting(Item $item){ - return $this->setItem(0, $item); + return $this->setItem(self::SMELTING, $item); } - public function onSlotChange($index, $before){ - parent::onSlotChange($index, $before); + public function onSlotChange($index, $before, $send){ + parent::onSlotChange($index, $before, $send); $this->getHolder()->scheduleUpdate(); } diff --git a/src/devmine/inventory/layout/FurnaceRecipe.php b/src/devmine/inventory/layout/FurnaceRecipe.php index a184dcb..02c35c9 100644 --- a/src/devmine/inventory/layout/FurnaceRecipe.php +++ b/src/devmine/inventory/layout/FurnaceRecipe.php @@ -5,7 +5,7 @@ namespace devmine\inventory\layout; use devmine\inventory\items\Item; -use devmine\Server; +use devmine\server\server; use devmine\utilities\main\UUID; class FurnaceRecipe implements Recipe{ diff --git a/src/devmine/inventory/layout/HopperInventory.php b/src/devmine/inventory/layout/HopperInventory.php new file mode 100644 index 0000000..acebbc8 --- /dev/null +++ b/src/devmine/inventory/layout/HopperInventory.php @@ -0,0 +1,37 @@ +holder; + } +} \ No newline at end of file diff --git a/src/devmine/inventory/layout/Inventory.php b/src/devmine/inventory/layout/Inventory.php index 20d5114..2c205a9 100644 --- a/src/devmine/inventory/layout/Inventory.php +++ b/src/devmine/inventory/layout/Inventory.php @@ -8,7 +8,7 @@ namespace devmine\inventory\layout; use devmine\inventory\items\Item; -use devmine\Player; +use devmine\creatures\player; interface Inventory{ const MAX_STACK = 64; @@ -99,7 +99,7 @@ public function sendSlot($index, $target); /** * Checks if the inventory contains any Item with the same material data. - * It will check id, amount, and epilogos (if not null) + * It will check id, amount, and metadata (if not null) * * @param Item $item * @@ -108,7 +108,7 @@ public function sendSlot($index, $target); public function contains(Item $item); /** - * Will return all the Items that has the same id and epilogos (if not null). + * Will return all the Items that has the same id and metadata (if not null). * Won't check amount * * @param Item $item @@ -118,7 +118,7 @@ public function contains(Item $item); public function all(Item $item); /** - * Will return the first slot has the same id and epilogos (if not null) as the Item. + * Will return the first slot has the same id and metadata (if not null) as the Item. * -1 if not found, will check amount * * @param Item $item @@ -135,7 +135,7 @@ public function first(Item $item); public function firstEmpty(); /** - * Will remove all the Items that has the same id and epilogos (if not null) + * Will remove all the Items that has the same id and metadata (if not null) * * @param Item $item */ @@ -197,6 +197,7 @@ public function onClose(Player $who); /** * @param int $index * @param Item $before + * @param bool $send */ - public function onSlotChange($index, $before); + public function onSlotChange($index, $before, $send); } diff --git a/src/devmine/inventory/layout/InventoryType.php b/src/devmine/inventory/layout/InventoryType.php index 382cd68..3e8ce57 100644 --- a/src/devmine/inventory/layout/InventoryType.php +++ b/src/devmine/inventory/layout/InventoryType.php @@ -22,6 +22,8 @@ class InventoryType{ const DROPPER = 11; const HOPPER = 12; + const PLAYER_FLOATING = 254; + private static $default = []; private $size; @@ -37,24 +39,25 @@ public static function get($index){ return isset(static::$default[$index]) ? static::$default[$index] : null; } - public static function init($num = 36){ + public static function init(){ if(count(static::$default) > 0){ return; } static::$default[static::CHEST] = new InventoryType(27, "Chest", 0); static::$default[static::DOUBLE_CHEST] = new InventoryType(27 + 27, "Double Chest", 0); - static::$default[static::PLAYER] = new InventoryType($num + 4 + 9, "Player", 0); //27 CONTAINER, 4 ARMOR (9 reference HOTBAR slots) + static::$default[static::PLAYER] = new InventoryType(36 + 4, "Player", 0); //36 CONTAINER, 4 ARMOR static::$default[static::FURNACE] = new InventoryType(3, "Furnace", 2); static::$default[static::CRAFTING] = new InventoryType(5, "Crafting", 1); //4 CRAFTING slots, 1 RESULT static::$default[static::WORKBENCH] = new InventoryType(10, "Crafting", 1); //9 CRAFTING slots, 1 RESULT - //static::$default[static::STONECUTTER] = new InventoryType(10, "Crafting", 1); //9 CRAFTING slots, 1 RESULT static::$default[static::ENCHANT_TABLE] = new InventoryType(2, "Enchant", 3); //1 INPUT/OUTPUT, 1 LAPIS static::$default[static::BREWING_STAND] = new InventoryType(4, "Brewing", 4); //1 INPUT, 3 POTION static::$default[static::ANVIL] = new InventoryType(3, "Anvil", 5); //2 INPUT, 1 OUTPUT static::$default[static::DISPENSER] = new InventoryType(9, "Dispenser", 6); //9 CONTAINER static::$default[static::DROPPER] = new InventoryType(9, "Dropper", 7); //9 CONTAINER static::$default[static::HOPPER] = new InventoryType(5, "Hopper", 8); //5 CONTAINER + + static::$default[static::PLAYER_FLOATING] = new InventoryType(36, "Floating", null); //Mirror all slots of main inventory (needed for large item pickups) } /** diff --git a/src/devmine/inventory/layout/MultiRecipe.php b/src/devmine/inventory/layout/MultiRecipe.php new file mode 100644 index 0000000..b6c2526 --- /dev/null +++ b/src/devmine/inventory/layout/MultiRecipe.php @@ -0,0 +1,17 @@ +uuid = $uuid; + } + +} \ No newline at end of file diff --git a/src/devmine/inventory/layout/PlayerInventory.php b/src/devmine/inventory/layout/PlayerInventory.php index 4858778..21b308c 100644 --- a/src/devmine/inventory/layout/PlayerInventory.php +++ b/src/devmine/inventory/layout/PlayerInventory.php @@ -5,16 +5,18 @@ namespace devmine\inventory\layout; use devmine\creatures\entities\Human; -use devmine\server\events\entity\EntityArmorChangeEvent; -use devmine\server\events\entity\EntityInventoryChangeEvent; -use devmine\server\events\player\PlayerItemHeldEvent; +use devmine\events\entity\EntityArmorChangeEvent; +use devmine\events\entity\EntityInventoryChangeEvent; +use devmine\events\player\PlayerItemHeldEvent; use devmine\inventory\items\Item; +use devmine\creatures\player\NBT; +use devmine\creatures\player\tag\ListTag; use devmine\server\network\protocol\ContainerSetContentPacket; use devmine\server\network\protocol\ContainerSetSlotPacket; use devmine\server\network\protocol\MobArmorEquipmentPacket; use devmine\server\network\protocol\MobEquipmentPacket; -use devmine\Player; -use devmine\Server; +use devmine\creatures\player; +use devmine\server\server; class PlayerInventory extends BaseInventory{ @@ -22,9 +24,36 @@ class PlayerInventory extends BaseInventory{ /** @var int[] */ protected $hotbar; - public function __construct(Human $player){ - $this->hotbar = array_fill(0, $this->getHotbarSize(), -1); + public function __construct(Human $player, $contents = null){ + $this->hotbar = range(0, $this->getHotbarSize() - 1, 1); parent::__construct($player, InventoryType::get(InventoryType::PLAYER)); + + if($contents !== null){ + if($contents instanceof ListTag){ //Saved data to be loaded into the inventory + foreach($contents as $item){ + if($item["Slot"] >= 0 and $item["Slot"] < $this->getHotbarSize()){ //Hotbar + if(isset($item["TrueSlot"])){ + + //Valid slot was found, change the linkage to this slot + if(0 <= $item["TrueSlot"] and $item["TrueSlot"] < $this->getSize()){ + $this->hotbar[$item["Slot"]] = $item["TrueSlot"]; + + }elseif($item["TrueSlot"] < 0){ //Link to an empty slot (empty hand) + $this->hotbar[$item["Slot"]] = -1; + } + } + /* If TrueSlot is not set, leave the slot index as its default which was filled in above + * This only overwrites slot indexes for valid links */ + }elseif($item["Slot"] >= 100 and $item["Slot"] < 104){ //Armor + $this->setItem($this->getSize() + $item["Slot"] - 100, Item::nbtDeserialize($item), false); + }else{ + $this->setItem($item["Slot"] - $this->getHotbarSize(), Item::nbtDeserialize($item), false); + } + } + }else{ + throw new \InvalidArgumentException("Expecting ListTag, received ".gettype($contents)); + } + } } public function getSize(){ @@ -36,30 +65,95 @@ public function setSize($size){ $this->sendContents($this->getViewers()); } + /** + * @param int $index + * + * @return int + * + * Returns the index of the inventory slot linked to the specified hotbar slot + */ public function getHotbarSlotIndex($index){ return ($index >= 0 and $index < $this->getHotbarSize()) ? $this->hotbar[$index] : -1; } + /** + * @deprecated + * + * Changes the linkage of the specified hotbar slot. This should never be done unless it is requested by the client. + */ public function setHotbarSlotIndex($index, $slot){ - if ($index >= 0 and $index < $this->getHotbarSize() and $slot >= -1 and $slot < $this->getSize()) { - $this->hotbar[$index] = $slot;//calculate has been done by client + if($this->getHolder()->getServer()->getProperty("settings.deprecated-verbose") !== false){ + trigger_error("Do not attempt to change hotbar links in plugins!", E_USER_DEPRECATED); } } + /** + * @return int + * + * Returns the index of the inventory slot the player is currently holding + */ public function getHeldItemIndex(){ return $this->itemInHandIndex; } - public function setHeldItemIndex($index, $sendHeldItem = true){ - if($index >= 0 and $index < $this->getHotbarSize()){ - $this->itemInHandIndex = $index; + /** + * @param int $hotbarSlotIndex + * @param bool $sendToHolder + * @param int $slotMapping + * + * Sets which hotbar slot the player is currently holding. + * Allows slot remapping as specified by a MobEquipmentPacket. DO NOT CHANGE SLOT MAPPING IN PLUGINS! + * This new implementation is fully compatible with older APIs. + * NOTE: Slot mapping is the raw slot index sent by MCPE, which will be between 9 and 44. + */ + public function setHeldItemIndex($hotbarSlotIndex, $sendToHolder = true, $slotMapping = null){ + if($slotMapping !== null){ + //Get the index of the slot in the actual inventory + $slotMapping -= $this->getHotbarSize(); + } + if(0 <= $hotbarSlotIndex and $hotbarSlotIndex < $this->getHotbarSize()){ + $this->itemInHandIndex = $hotbarSlotIndex; + if($slotMapping !== null){ + /* Handle a hotbar slot mapping change. This allows PE to select different inventory slots. + * This is the only time slot mapping should ever be changed. */ + + if($slotMapping < 0 or $slotMapping >= $this->getSize()){ + //Mapping was not in range of the inventory, set it to -1 + //This happens if the client selected a blank slot (sends 255) + $slotMapping = -1; + } + + $item = $this->getItem($slotMapping); + if($this->getHolder() instanceof Player){ + Server::getInstance()->getPluginManager()->callEvent($ev = new PlayerItemHeldEvent($this->getHolder(), $item, $slotMapping, $hotbarSlotIndex)); + if($ev->isCancelled()){ + $this->sendHeldItem($this->getHolder()); + $this->sendContents($this->getHolder()); + return; + } + } - if($sendHeldItem){ - $this->sendHeldItem($this->getHolder()->getViewers()); + if(($key = array_search($slotMapping, $this->hotbar)) !== false and $slotMapping !== -1){ + /* Do not do slot swaps if the slot was null + * Chosen slot is already linked to a hotbar slot, swap the two slots around. + * This will already have been done on the client-side so no changes need to be sent. */ + $this->hotbar[$key] = $this->hotbar[$this->itemInHandIndex]; + } + + $this->hotbar[$this->itemInHandIndex] = $slotMapping; + } + $this->sendHeldItem($this->getHolder()->getViewers()); + if($sendToHolder){ + $this->sendHeldItem($this->getHolder()); } } } + /** + * @return Item + * + * Returns the item the player is currently holding + */ public function getItemInHand(){ $item = $this->getItem($this->getHeldItemSlot()); if($item instanceof Item){ @@ -73,31 +167,36 @@ public function getItemInHand(){ * @param Item $item * * @return bool + * + * Sets the item in the inventory slot the player is currently holding. */ public function setItemInHand(Item $item){ return $this->setItem($this->getHeldItemSlot(), $item); } + /** + * @return int[] + * + * Returns an array of hotbar indices + */ + public function getHotbar(){ + return $this->hotbar; + } + + /** + * @return int + * + * Returns the inventory slot index of the currently equipped slot + */ public function getHeldItemSlot(){ return $this->getHotbarSlotIndex($this->itemInHandIndex); } + /** + * @deprecated + * @param int $slot + */ public function setHeldItemSlot($slot){ - if($slot >= -1 and $slot < $this->getSize()){ - $item = $this->getItem($slot); - - $itemIndex = $this->getHeldItemIndex(); - - if($this->getHolder() instanceof Player){ - Server::getInstance()->getPluginManager()->callEvent($ev = new PlayerItemHeldEvent($this->getHolder(), $item, $slot, $itemIndex)); - if($ev->isCancelled()){ - $this->sendContents($this->getHolder()); - return; - } - } - - $this->setHotbarSlotIndex($itemIndex, $slot); - } } /** @@ -128,15 +227,22 @@ public function sendHeldItem($target){ } } - public function onSlotChange($index, $before){ - $holder = $this->getHolder(); - if(!$holder instanceof Player or !$holder->spawned){ - return; - } + public function onSlotChange($index, $before, $send){ + if($send){ + $holder = $this->getHolder(); + if(!$holder instanceof Player or !$holder->spawned){ + return; + } - parent::onSlotChange($index, $before); + parent::onSlotChange($index, $before, $send); + } + if($index === $this->itemInHandIndex){ + $this->sendHeldItem($this->getHolder()->getViewers()); + if($send){ + $this->sendHeldItem($this->getHolder()); + } - if($index >= $this->getSize()){ + }elseif($index >= $this->getSize()){ //Armour equipment $this->sendArmorSlot($index, $this->getViewers()); $this->sendArmorSlot($index, $this->getHolder()->getViewers()); } @@ -153,6 +259,14 @@ public function getArmorItem($index){ public function setArmorItem($index, Item $item){ return $this->setItem($this->getSize() + $index, $item); } + + public function damageArmor($index, $cost){ + $this->slots[$this->getSize() + $index]->useOn($this->slots[$this->getSize() + $index], $cost); + if($this->slots[$this->getSize() + $index]->getDamage() >= $this->slots[$this->getSize() + $index]->getMaxDurability()){ + $this->setItem($this->getSize() + $index, Item::get(Item::AIR, 0, 0)); + } + $this->sendArmorContents($this->getViewers()); + } public function getHelmet(){ return $this->getItem($this->getSize()); @@ -186,11 +300,11 @@ public function setBoots(Item $boots){ return $this->setItem($this->getSize() + 3, $boots); } - public function setItem($index, Item $item){ + public function setItem($index, Item $item, $send = true){ if($index < 0 or $index >= $this->size){ return false; }elseif($item->getId() === 0 or $item->getCount() <= 0){ - return $this->clear($index); + return $this->clear($index, $send); } if($index >= $this->getSize()){ //Armor change @@ -212,12 +326,12 @@ public function setItem($index, Item $item){ $old = $this->getItem($index); $this->slots[$index] = clone $item; - $this->onSlotChange($index, $old); + $this->onSlotChange($index, $old, $send); return true; } - public function clear($index){ + public function clear($index, $send = true){ if(isset($this->slots[$index])){ $item = Item::get(Item::AIR, null, 0); $old = $this->slots[$index]; @@ -250,7 +364,7 @@ public function clear($index){ unset($this->slots[$index]); } - $this->onSlotChange($index, $old); + $this->onSlotChange($index, $old, $send); } return true; @@ -272,8 +386,10 @@ public function getArmorContents(){ public function clearAll(){ $limit = $this->getSize() + 4; for($index = 0; $index < $limit; ++$index){ - $this->clear($index); + $this->clear($index, false); } + $this->hotbar = range(0, $this->getHotbarSize() - 1, 1); + $this->sendContents($this->getViewers()); } /** @@ -367,12 +483,17 @@ public function sendContents($target){ $pk->slots[$i] = $this->getItem($i); } + //Because PE is stupid and shows 9 less slots than you send it, give it 9 dummy slots so it shows all the REAL slots. + for($i = $this->getSize(); $i < $this->getSize() + $this->getHotbarSize(); ++$i){ + $pk->slots[$i] = Item::get(Item::AIR, 0, 0); + } + foreach($target as $player){ $pk->hotbar = []; if($player === $this->getHolder()){ for($i = 0; $i < $this->getHotbarSize(); ++$i){ $index = $this->getHotbarSlotIndex($i); - $pk->hotbar[] = $index <= -1 ? -1 : $index + $this->getHotbarSize(); + $pk->hotbar[$i] = $index <= -1 ? -1 : $index + $this->getHotbarSize(); } } if(($id = $player->getWindowId($this)) === -1 or $player->spawned !== true){ diff --git a/src/devmine/inventory/layout/ShapedRecipe.php b/src/devmine/inventory/layout/ShapedRecipe.php index 33e6b37..8287803 100644 --- a/src/devmine/inventory/layout/ShapedRecipe.php +++ b/src/devmine/inventory/layout/ShapedRecipe.php @@ -5,7 +5,7 @@ namespace devmine\inventory\layout; use devmine\inventory\items\Item; -use devmine\Server; +use devmine\server\server; use devmine\utilities\main\UUID; use devmine\server\calculations\Vector2; @@ -24,33 +24,18 @@ class ShapedRecipe implements Recipe{ private $shapeItems = []; /** - * @param Item $result - * @param string[] $shape + * @param Item $result + * @param int $height + * @param int $width * - * @throws \Throwable + * @throws \Exception */ - public function __construct(Item $result, ...$shape){ - if(count($shape) === 0){ - throw new \InvalidArgumentException("Must provide a shape"); - } - if(count($shape) > 3){ - throw new \InvalidStateException("Crafting recipes should be 1, 2, 3 rows, not " . count($shape)); - } - foreach($shape as $y => $row){ - if(strlen($row) === 0 or strlen($row) > 3){ - throw new \InvalidStateException("Crafting rows should be 1, 2, 3 characters, not " . count($row)); - } - $this->ingredients[] = array_fill(0, strlen($row), null); - $len = strlen($row); - for($i = 0; $i < $len; ++$i){ - $this->shape[$row{$i}] = null; - - if(!isset($this->shapeItems[$row{$i}])){ - $this->shapeItems[$row{$i}] = [new Vector2($i, $y)]; - }else{ - $this->shapeItems[$row{$i}][] = new Vector2($i, $y); - } + public function __construct(Item $result, $height, $width){ + for($h = 0; $h < $height; $h++){ + if($width === 0 or $width > 3){ + throw new \InvalidStateException("Crafting rows should be 1, 2, 3 wide, not $width"); } + $this->ingredients[] = array_fill(0, $width, null); } $this->output = clone $result; @@ -80,6 +65,11 @@ public function setId(UUID $id){ $this->id = $id; } + public function addIngredient($x, $y, Item $item){ + $this->ingredients[$y][$x] = clone $item; + return $this; + } + /** * @param string $key * @param Item $item @@ -92,6 +82,7 @@ public function setIngredient($key, Item $item){ throw new \Exception("Symbol does not appear in the shape: " . $key); } + $item->setCount(1); $this->fixRecipe($key, $item); return $this; @@ -122,6 +113,23 @@ public function getIngredientMap(){ return $ingredients; } + /** + * @return Item[] + */ + public function getIngredientList(){ + $ingredients = []; + for ($x = 0; $x < 3; ++$x){ + for ($y = 0; $y < 3; ++$y){ + if (!empty($this->ingredients[$x][$y])){ + if ($this->ingredients[$x][$y]->getId() !== Item::AIR){ + $ingredients[] = clone $this->ingredients[$x][$y]; + } + } + } + } + return $ingredients; + } + /** * @param $x * @param $y diff --git a/src/devmine/inventory/layout/ShapedRecipeFromJson.php b/src/devmine/inventory/layout/ShapedRecipeFromJson.php index 53d69eb..2f5b7de 100644 --- a/src/devmine/inventory/layout/ShapedRecipeFromJson.php +++ b/src/devmine/inventory/layout/ShapedRecipeFromJson.php @@ -5,7 +5,7 @@ namespace devmine\inventory\layout; use devmine\inventory\items\Item; -use devmine\Server; +use devmine\server\server; use devmine\utilities\main\UUID; use devmine\server\calculations\Vector2; diff --git a/src/devmine/inventory/layout/ShapelessRecipe.php b/src/devmine/inventory/layout/ShapelessRecipe.php index 6e5b58a..f9b1f27 100644 --- a/src/devmine/inventory/layout/ShapelessRecipe.php +++ b/src/devmine/inventory/layout/ShapelessRecipe.php @@ -5,7 +5,7 @@ namespace devmine\inventory\layout; use devmine\inventory\items\Item; -use devmine\Server; +use devmine\server\server; use devmine\utilities\main\UUID; class ShapelessRecipe implements Recipe{ diff --git a/src/devmine/inventory/layout/SimpleTransactionGroup.php b/src/devmine/inventory/layout/SimpleTransactionGroup.php deleted file mode 100644 index 072b7b2..0000000 --- a/src/devmine/inventory/layout/SimpleTransactionGroup.php +++ /dev/null @@ -1,148 +0,0 @@ -creationTime = microtime(true); - $this->source = $source; - } - - /** - * @return Player - */ - public function getSource(){ - return $this->source; - } - - public function getCreationTime(){ - return $this->creationTime; - } - - public function getInventories(){ - return $this->inventories; - } - - public function getTransactions(){ - return $this->transactions; - } - - public function addTransaction(Transaction $transaction){ - if(isset($this->transactions[spl_object_hash($transaction)])){ - return; - } - foreach($this->transactions as $hash => $tx){ - if($tx->getInventory() === $transaction->getInventory() and $tx->getSlot() === $transaction->getSlot()){ - if($transaction->getCreationTime() >= $tx->getCreationTime()){ - unset($this->transactions[$hash]); - }else{ - return; - } - } - } - $this->transactions[spl_object_hash($transaction)] = $transaction; - $this->inventories[spl_object_hash($transaction->getInventory())] = $transaction->getInventory(); - } - - /** - * @param Item[] $needItems - * @param Item[] $haveItems - * - * @return bool - */ - protected function matchItems(array &$needItems, array &$haveItems){ - foreach($this->transactions as $key => $ts){ - if($ts->getTargetItem()->getId() !== Item::AIR){ - $needItems[] = $ts->getTargetItem(); - } - $checkSourceItem = $ts->getInventory()->getItem($ts->getSlot()); - $sourceItem = $ts->getSourceItem(); - if(!$checkSourceItem->deepEquals($sourceItem, true, false) or $sourceItem->getCount() !== $checkSourceItem->getCount()){ - return false; - } - if($sourceItem->getId() !== Item::AIR){ - $haveItems[] = $sourceItem; - } - } - - foreach($needItems as $i => $needItem){ - foreach($haveItems as $j => $haveItem){ - if($needItem->deepEquals($haveItem, true, false)){ - $amount = min($needItem->getCount(), $haveItem->getCount()); - $needItem->setCount($needItem->getCount() - $amount); - $haveItem->setCount($haveItem->getCount() - $amount); - if($haveItem->getCount() === 0){ - unset($haveItems[$j]); - } - if($needItem->getCount() === 0){ - unset($needItems[$i]); - break; - } - } - } - } - - return true; - } - - public function canExecute(){ - $haveItems = []; - $needItems = []; - - return $this->matchItems($haveItems, $needItems) and count($haveItems) === 0 and count($needItems) === 0 and count($this->transactions) > 0; - } - - public function execute(){ - if($this->hasExecuted() or !$this->canExecute()){ - return false; - } - - Server::getInstance()->getPluginManager()->callEvent($ev = new InventoryTransactionEvent($this)); - if($ev->isCancelled()){ - foreach($this->inventories as $inventory){ - if($inventory instanceof PlayerInventory){ - $inventory->sendArmorContents($this->getSource()); - } - $inventory->sendContents($this->getSource()); - } - - return false; - } - - foreach($this->transactions as $transaction){ - $transaction->getInventory()->setItem($transaction->getSlot(), $transaction->getTargetItem()); - } - - $this->hasExecuted = true; - - return true; - } - - public function hasExecuted(){ - return $this->hasExecuted; - } -} \ No newline at end of file diff --git a/src/devmine/inventory/layout/SimpleTransactionQueue.php b/src/devmine/inventory/layout/SimpleTransactionQueue.php new file mode 100644 index 0000000..8eb4246 --- /dev/null +++ b/src/devmine/inventory/layout/SimpleTransactionQueue.php @@ -0,0 +1,132 @@ +player = $player; + $this->transactionQueue = new \SplQueue(); + $this->transactionsToRetry = new \SplQueue(); + } + + /** + * @return Player + */ + public function getPlayer(){ + return $this->player; + } + + public function getInventories(){ + return $this->inventories; + } + + public function getTransactions(){ + return $this->transactionQueue; + } + + public function getTransactionCount(){ + return $this->transactionCount; + } + + public function addTransaction(Transaction $transaction){ + $this->transactionQueue->enqueue($transaction); + if($transaction->getInventory() instanceof Inventory){ + /** For dropping items, the target inventory is open air, a.k.a. null. */ + $this->inventories[spl_object_hash($transaction)] = $transaction->getInventory(); + } + $this->lastUpdate = microtime(true); + $this->transactionCount += 1; + } + + public function execute(){ + /** @var Transaction[] */ + $failed = []; + + while(!$this->transactionsToRetry->isEmpty()){ + //Some failed transactions are waiting from the previous execution to be retried + $this->transactionQueue->enqueue($this->transactionsToRetry->dequeue()); + } + + if(!$this->transactionQueue->isEmpty()){ + $this->player->getServer()->getPluginManager()->callEvent($ev = new InventoryTransactionEvent($this)); + }else{ + return; + } + + while(!$this->transactionQueue->isEmpty()){ + $transaction = $this->transactionQueue->dequeue(); + + if($ev->isCancelled()){ + $this->transactionCount -= 1; + $transaction->sendSlotUpdate($this->player); //Send update back to client for cancelled transaction + unset($this->inventories[spl_object_hash($transaction)]); + continue; + }elseif(!$transaction->execute($this->player)){ + $transaction->addFailure(); + if($transaction->getFailures() >= self::DEFAULT_ALLOWED_RETRIES){ + /* Transaction failed completely after several retries, hold onto it to send a slot update */ + $this->transactionCount -= 1; + $failed[] = $transaction; + }else{ + /* Add the transaction to the back of the queue to be retried on the next tick */ + $this->transactionsToRetry->enqueue($transaction); + } + continue; + } + + $this->transactionCount -= 1; + $transaction->setSuccess(); + $transaction->sendSlotUpdate($this->player); + unset($this->inventories[spl_object_hash($transaction)]); + } + + foreach($failed as $f){ + $f->sendSlotUpdate($this->player); + unset($this->inventories[spl_object_hash($f)]); + } + } +} \ No newline at end of file diff --git a/src/devmine/inventory/layout/SlotType.php b/src/devmine/inventory/layout/SlotType.php deleted file mode 100644 index ecf1120..0000000 --- a/src/devmine/inventory/layout/SlotType.php +++ /dev/null @@ -1,22 +0,0 @@ -getContents() as $slot => $item){ + if($slot === $this->getResultSlotIndex()){ + //Do not drop the item in the result slot - it is a virtual item and does not actually exist. + continue; + } + $who->dropItem($item); + } + $this->clearAll(); + } +} \ No newline at end of file diff --git a/src/devmine/inventory/layout/Transaction.php b/src/devmine/inventory/layout/Transaction.php index c56563a..9cab458 100644 --- a/src/devmine/inventory/layout/Transaction.php +++ b/src/devmine/inventory/layout/Transaction.php @@ -4,10 +4,15 @@ namespace devmine\inventory\layout; +use devmine\creatures\player; use devmine\inventory\items\Item; interface Transaction{ + //Transaction type constants + const TYPE_NORMAL = 0; + const TYPE_DROP_ITEM = 1; + /** * @return Inventory */ @@ -18,11 +23,6 @@ public function getInventory(); */ public function getSlot(); - /** - * @return Item - */ - public function getSourceItem(); - /** * @return Item */ @@ -32,4 +32,10 @@ public function getTargetItem(); * @return float */ public function getCreationTime(); + + /** + * @param Player $source + * @return bool + */ + public function execute(Player $source): bool; } \ No newline at end of file diff --git a/src/devmine/inventory/layout/TransactionGroup.php b/src/devmine/inventory/layout/TransactionGroup.php deleted file mode 100644 index 55c9db0..0000000 --- a/src/devmine/inventory/layout/TransactionGroup.php +++ /dev/null @@ -1,44 +0,0 @@ -spawnToAll(); + if($this->chunk instanceof Chunk){ + $this->chunk->setChanged(); + $this->level->clearChunkCache($this->chunk->getX(), $this->chunk->getZ()); + } + } + + public function getSpawnCompound(){ + return new CompoundTag("", [ + new StringTag("id", Tile::BEACON), + new IntTag("x", (int) $this->x), + new IntTag("y", (int) $this->y), + new IntTag("z", (int) $this->z) + ]); + } + } + diff --git a/src/devmine/inventory/solidentity/BrewingStand.php b/src/devmine/inventory/solidentity/BrewingStand.php index 8625b0b..0e9f4b2 100644 --- a/src/devmine/inventory/solidentity/BrewingStand.php +++ b/src/devmine/inventory/solidentity/BrewingStand.php @@ -1,6 +1,23 @@ 0, ]; - public function __construct(FullChunk $chunk, CompoundTag $nbt){ + public function __construct(Chunk $chunk, CompoundTag $nbt){ parent::__construct($chunk, $nbt); $this->inventory = new BrewingInventory($this); @@ -133,7 +150,7 @@ public function getItem($index){ if($i < 0){ return Item::get(Item::AIR, 0, 0); }else{ - return NBT::getItemHelper($this->namedtag->Items[$i]); + return Item::nbtDeserialize($this->namedtag->Items[$i]); } } @@ -148,8 +165,6 @@ public function getItem($index){ public function setItem($index, Item $item){ $i = $this->getSlotIndex($index); - $d = NBT::putItemHelper($item, $index); - if($item->getId() === Item::AIR or $item->getCount() <= 0){ if($i >= 0){ unset($this->namedtag->Items[$i]); @@ -160,9 +175,9 @@ public function setItem($index, Item $item){ break; } } - $this->namedtag->Items[$i] = $d; + $this->namedtag->Items[$i] = $item->nbtSerialize($index); }else{ - $this->namedtag->Items[$i] = $d; + $this->namedtag->Items[$i] = $item->nbtSerialize($index); } return true; @@ -287,7 +302,7 @@ public function onUpdate(){ public function getSpawnCompound(){ $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::BREWING_STAND), + new StringTag("id", Tile::BREWING_STAND), new IntTag("x", (int) $this->x), new IntTag("y", (int) $this->y), new IntTag("z", (int) $this->z), diff --git a/src/devmine/inventory/solidentity/Cauldron.php b/src/devmine/inventory/solidentity/Cauldron.php index d5d9016..59b7e3e 100644 --- a/src/devmine/inventory/solidentity/Cauldron.php +++ b/src/devmine/inventory/solidentity/Cauldron.php @@ -1,6 +1,23 @@ PotionId)){ $nbt->PotionId = new ShortTag("PotionId", 0xffff); } @@ -120,7 +137,7 @@ public function clearCustomColor(){ public function getSpawnCompound(){ $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::CAULDRON), + new StringTag("id", Tile::CAULDRON), new IntTag("x", (Int) $this->x), new IntTag("y", (Int) $this->y), new IntTag("z", (Int) $this->z), diff --git a/src/devmine/inventory/solidentity/Chest.php b/src/devmine/inventory/solidentity/Chest.php index 86ad073..2e3a9be 100644 --- a/src/devmine/inventory/solidentity/Chest.php +++ b/src/devmine/inventory/solidentity/Chest.php @@ -8,7 +8,7 @@ use devmine\inventory\layout\DoubleChestInventory; use devmine\inventory\layout\InventoryHolder; use devmine\inventory\items\Item; -use devmine\levels\format\FullChunk; +use devmine\worlds\format\Chunk; use devmine\server\calculations\Vector3; use devmine\creatures\player\NBT; @@ -25,7 +25,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ /** @var DoubleChestInventory */ protected $doubleInventory = null; - public function __construct(FullChunk $chunk, CompoundTag $nbt){ + public function __construct(Chunk $chunk, CompoundTag $nbt){ parent::__construct($chunk, $nbt); $this->inventory = new ChestInventory($this); @@ -94,7 +94,7 @@ public function getItem($index){ if($i < 0){ return Item::get(Item::AIR, 0, 0); }else{ - return NBT::getItemHelper($this->namedtag->Items[$i]); + return Item::nbtDeserialize($this->namedtag->Items[$i]); } } @@ -109,8 +109,6 @@ public function getItem($index){ public function setItem($index, Item $item){ $i = $this->getSlotIndex($index); - $d = NBT::putItemHelper($item, $index); - if($item->getId() === Item::AIR or $item->getCount() <= 0){ if($i >= 0){ unset($this->namedtag->Items[$i]); @@ -121,9 +119,9 @@ public function setItem($index, Item $item){ break; } } - $this->namedtag->Items[$i] = $d; + $this->namedtag->Items[$i] = $item->nbtSerialize($index); }else{ - $this->namedtag->Items[$i] = $d; + $this->namedtag->Items[$i] = $item->nbtSerialize($index); } return true; @@ -146,6 +144,13 @@ public function getRealInventory(){ return $this->inventory; } + /** + * @return DoubleChestInventory|null + */ + public function getDoubleInventory(){ + return $this->doubleInventory; + } + protected function checkPairing(){ if(($pair = $this->getPair()) instanceof Chest){ if(!$pair->isPaired()){ @@ -153,10 +158,14 @@ protected function checkPairing(){ $pair->checkPairing(); } if($this->doubleInventory === null){ - if(($pair->x + ($pair->z << 15)) > ($this->x + ($this->z << 15))){ //Order them correctly - $this->doubleInventory = new DoubleChestInventory($pair, $this); + if(($p = $pair->getDoubleInventory()) instanceof DoubleChestInventory){ + $this->doubleInventory = $p; }else{ - $this->doubleInventory = new DoubleChestInventory($this, $pair); + if(($pair->x + ($pair->z << 15)) > ($this->x + ($this->z << 15))){ //Order them correctly + $this->doubleInventory = new DoubleChestInventory($pair, $this); + }else{ + $this->doubleInventory = new DoubleChestInventory($this, $pair); + } } } }else{ @@ -195,35 +204,35 @@ public function isPaired(){ */ public function getPair(){ if($this->isPaired()){ - $solidentity = $this->getLevel()->getsolidentity(new Vector3((int) $this->namedtag["pairx"], $this->y, (int) $this->namedtag["pairz"])); - if($solidentity instanceof Chest){ - return $solidentity; + $tile = $this->getLevel()->getTile(new Vector3((int) $this->namedtag["pairx"], $this->y, (int) $this->namedtag["pairz"])); + if($tile instanceof Chest){ + return $tile; } } return null; } - public function pairWith(Chest $solidentity){ - if($this->isPaired() or $solidentity->isPaired()){ + public function pairWith(Chest $tile){ + if($this->isPaired() or $tile->isPaired()){ return false; } - $this->createPair($solidentity); + $this->createPair($tile); $this->spawnToAll(); - $solidentity->spawnToAll(); + $tile->spawnToAll(); $this->checkPairing(); return true; } - private function createPair(Chest $solidentity){ - $this->namedtag->pairx = new IntTag("pairx", $solidentity->x); - $this->namedtag->pairz = new IntTag("pairz", $solidentity->z); + private function createPair(Chest $tile){ + $this->namedtag->pairx = new IntTag("pairx", $tile->x); + $this->namedtag->pairz = new IntTag("pairz", $tile->z); - $solidentity->namedtag->pairx = new IntTag("pairx", $this->x); - $solidentity->namedtag->pairz = new IntTag("pairz", $this->z); + $tile->namedtag->pairx = new IntTag("pairx", $this->x); + $tile->namedtag->pairz = new IntTag("pairz", $this->z); } public function unpair(){ @@ -231,15 +240,15 @@ public function unpair(){ return false; } - $solidentity = $this->getPair(); + $tile = $this->getPair(); unset($this->namedtag->pairx, $this->namedtag->pairz); $this->spawnToAll(); - if($solidentity instanceof Chest){ - unset($solidentity->namedtag->pairx, $solidentity->namedtag->pairz); - $solidentity->checkPairing(); - $solidentity->spawnToAll(); + if($tile instanceof Chest){ + unset($tile->namedtag->pairx, $tile->namedtag->pairz); + $tile->checkPairing(); + $tile->spawnToAll(); } $this->checkPairing(); @@ -249,7 +258,7 @@ public function unpair(){ public function getSpawnCompound(){ if($this->isPaired()){ $c = new CompoundTag("", [ - new StringTag("id", solidentity::CHEST), + new StringTag("id", Tile::CHEST), new IntTag("x", (int) $this->x), new IntTag("y", (int) $this->y), new IntTag("z", (int) $this->z), @@ -258,7 +267,7 @@ public function getSpawnCompound(){ ]); }else{ $c = new CompoundTag("", [ - new StringTag("id", solidentity::CHEST), + new StringTag("id", Tile::CHEST), new IntTag("x", (int) $this->x), new IntTag("y", (int) $this->y), new IntTag("z", (int) $this->z) diff --git a/src/devmine/inventory/solidentity/DLDetector.php b/src/devmine/inventory/solidentity/DLDetector.php index 4a2848d..73bb37f 100644 --- a/src/devmine/inventory/solidentity/DLDetector.php +++ b/src/devmine/inventory/solidentity/DLDetector.php @@ -1,21 +1,38 @@ scheduleUpdate(); } @@ -98,7 +115,7 @@ public function onUpdate(){ public function getSpawnCompound(){ return new CompoundTag("", [ - new StringTag("id", solidentity::DAY_LIGHT_DETECTOR), + new StringTag("id", Tile::DAY_LIGHT_DETECTOR), new IntTag("x", (int) $this->x), new IntTag("y", (int) $this->y), new IntTag("z", (int) $this->z), diff --git a/src/devmine/inventory/solidentity/Dispenser.php b/src/devmine/inventory/solidentity/Dispenser.php index c2c1ccb..dbe6fab 100644 --- a/src/devmine/inventory/solidentity/Dispenser.php +++ b/src/devmine/inventory/solidentity/Dispenser.php @@ -1,6 +1,23 @@ inventory = new DispenserInventory($this); @@ -106,7 +123,7 @@ public function getItem($index){ if($i < 0){ return Item::get(Item::AIR, 0, 0); }else{ - return NBT::getItemHelper($this->namedtag->Items[$i]); + return Item::nbtDeserialize($this->namedtag->Items[$i]); } } @@ -121,8 +138,6 @@ public function getItem($index){ public function setItem($index, Item $item){ $i = $this->getSlotIndex($index); - $d = NBT::putItemHelper($item, $index); - if($item->getId() === Item::AIR or $item->getCount() <= 0){ if($i >= 0){ unset($this->namedtag->Items[$i]); @@ -133,9 +148,9 @@ public function setItem($index, Item $item){ break; } } - $this->namedtag->Items[$i] = $d; + $this->namedtag->Items[$i] = $item->nbtSerialize($index); }else{ - $this->namedtag->Items[$i] = $d; + $this->namedtag->Items[$i] = $item->nbtSerialize($index); } return true; @@ -330,9 +345,7 @@ public function activate(){ break; default: - $itemTag = NBT::putItemHelper($needItem); - $itemTag->setName("Item"); - + $nbt = new CompoundTag("", [ "Pos" => new ListTag("Pos", [ new DoubleTag("", $this->x + $motion[0] * 2 + 0.5), @@ -349,7 +362,7 @@ public function activate(){ new FloatTag("", 0) ]), "Health" => new ShortTag("Health", 5), - "Item" => $itemTag, + "Item" => $needItem->nbtSerialize(-1, "Item"), "PickupDelay" => new ShortTag("PickupDelay", 10) ]); @@ -368,7 +381,7 @@ public function activate(){ public function getSpawnCompound(){ $c = new CompoundTag("", [ - new StringTag("id", solidentity::DISPENSER), + new StringTag("id", Tile::DISPENSER), new IntTag("x", (int) $this->x), new IntTag("y", (int) $this->y), new IntTag("z", (int) $this->z) @@ -380,4 +393,4 @@ public function getSpawnCompound(){ return $c; } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/solidentity/Dropper.php b/src/devmine/inventory/solidentity/Dropper.php index e2c566c..0e35308 100644 --- a/src/devmine/inventory/solidentity/Dropper.php +++ b/src/devmine/inventory/solidentity/Dropper.php @@ -1,6 +1,23 @@ inventory = new DropperInventory($this); @@ -101,7 +118,7 @@ public function getItem($index){ if($i < 0){ return Item::get(Item::AIR, 0, 0); }else{ - return NBT::getItemHelper($this->namedtag->Items[$i]); + return Item::nbtDeserialize($this->namedtag->Items[$i]); } } @@ -116,8 +133,6 @@ public function getItem($index){ public function setItem($index, Item $item){ $i = $this->getSlotIndex($index); - $d = NBT::putItemHelper($item, $index); - if($item->getId() === Item::AIR or $item->getCount() <= 0){ if($i >= 0){ unset($this->namedtag->Items[$i]); @@ -128,9 +143,9 @@ public function setItem($index, Item $item){ break; } } - $this->namedtag->Items[$i] = $d; + $this->namedtag->Items[$i] = $item->nbtSerialize($index); }else{ - $this->namedtag->Items[$i] = $d; + $this->namedtag->Items[$i] = $item->nbtSerialize($index); } return true; @@ -208,9 +223,9 @@ public function activate(){ case Block::DISPENSER: case Block::BREWING_STAND_BLOCK: case Block::FURNACE: - $t = $this->getLevel()->getsolidentity($block); + $t = $this->getLevel()->getTile($block); /** @var Chest|Dispenser|Dropper|BrewingStand|Furnace $t */ - if($t instanceof solidentity){ + if($t instanceof Tile){ if($t->getInventory()->canAddItem($needItem)){ $t->getInventory()->addItem($needItem); return; @@ -218,10 +233,6 @@ public function activate(){ } } - $itemTag = NBT::putItemHelper($needItem); - $itemTag->setName("Item"); - - $nbt = new CompoundTag("", [ "Pos" => new ListTag("Pos", [ new DoubleTag("", $this->x + $motion[0] * 2 + 0.5), @@ -238,7 +249,7 @@ public function activate(){ new FloatTag("", 0) ]), "Health" => new ShortTag("Health", 5), - "Item" => $itemTag, + "Item" => $needItem->nbtSerialize(-1, "Item"), "PickupDelay" => new ShortTag("PickupDelay", 10) ]); @@ -255,7 +266,7 @@ public function activate(){ public function getSpawnCompound(){ $c = new CompoundTag("", [ - new StringTag("id", solidentity::DROPPER), + new StringTag("id", Tile::DROPPER), new IntTag("x", (int) $this->x), new IntTag("y", (int) $this->y), new IntTag("z", (int) $this->z) @@ -267,4 +278,4 @@ public function getSpawnCompound(){ return $c; } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/solidentity/EnchantTable.php b/src/devmine/inventory/solidentity/EnchantTable.php index e90206f..8288de4 100644 --- a/src/devmine/inventory/solidentity/EnchantTable.php +++ b/src/devmine/inventory/solidentity/EnchantTable.php @@ -7,18 +7,15 @@ use devmine\inventory\layout\EnchantInventory; use devmine\inventory\layout\InventoryHolder; use devmine\inventory\items\Item; -use devmine\levels\format\FullChunk; +use devmine\worlds\format\Chunk; use devmine\creatures\player\tag\CompoundTag; use devmine\creatures\player\tag\IntTag; use devmine\creatures\player\tag\StringTag; -class EnchantTable extends Spawnable implements InventoryHolder, Nameable{ - /** @var EnchantInventory */ - protected $inventory; +class EnchantTable extends Spawnable implements Nameable{ - public function __construct(FullChunk $chunk, CompoundTag $nbt){ + public function __construct(Chunk $chunk, CompoundTag $nbt){ parent::__construct($chunk, $nbt); - $this->inventory = new EnchantInventory($this); } public function getName() : string{ @@ -38,16 +35,9 @@ public function setName($str){ $this->namedtag->CustomName = new StringTag("CustomName", $str); } - /** - * @return EnchantInventory - */ - public function getInventory(){ - return $this->inventory; - } - public function getSpawnCompound(){ $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::ENCHANT_TABLE), + new StringTag("id", Tile::ENCHANT_TABLE), new IntTag("x", (int) $this->x), new IntTag("y", (int) $this->y), new IntTag("z", (int) $this->z) diff --git a/src/devmine/inventory/solidentity/FlowerPot.php b/src/devmine/inventory/solidentity/FlowerPot.php index e129aab..34f19ef 100644 --- a/src/devmine/inventory/solidentity/FlowerPot.php +++ b/src/devmine/inventory/solidentity/FlowerPot.php @@ -1,16 +1,33 @@ item)){ $nbt->item = new ShortTag("item", 0); @@ -39,22 +56,18 @@ public function getFlowerPotData(){ public function setFlowerPotData($item, $data){ $this->namedtag->item = new ShortTag("item", (int) $item); $this->namedtag->mData = new IntTag("mData", (int) $data); - $this->spawnToAll(); - if($this->chunk){ - $this->chunk->setChanged(); - $this->level->clearChunkCache($this->chunk->getX(), $this->chunk->getZ()); - } + $this->onChanged(); return true; } public function getSpawnCompound(){ return new CompoundTag("", [ - new StringTag("id", solidentity::FLOWER_POT), + new StringTag("id", Tile::FLOWER_POT), new IntTag("x", (int) $this->x), new IntTag("y", (int) $this->y), new IntTag("z", (int) $this->z), - new ShortTag("item", (int) $this->namedtag["item"]), - new IntTag("mData", (int) $this->namedtag["mData"]) + $this->namedtag->item, + $this->namedtag->mData ]); } } diff --git a/src/devmine/inventory/solidentity/Furnace.php b/src/devmine/inventory/solidentity/Furnace.php index 1e257e3..49b1586 100644 --- a/src/devmine/inventory/solidentity/Furnace.php +++ b/src/devmine/inventory/solidentity/Furnace.php @@ -5,13 +5,13 @@ namespace devmine\inventory\solidentity; use devmine\inventory\blocks\Block; -use devmine\server\events\inventory\FurnaceBurnEvent; -use devmine\server\events\inventory\FurnaceSmeltEvent; +use devmine\events\inventory\FurnaceBurnEvent; +use devmine\events\inventory\FurnaceSmeltEvent; use devmine\inventory\layout\FurnaceInventory; use devmine\inventory\layout\FurnaceRecipe; use devmine\inventory\layout\InventoryHolder; use devmine\inventory\items\Item; -use devmine\levels\format\FullChunk; +use devmine\worlds\format\Chunk; use devmine\creatures\player\NBT; use devmine\creatures\player\tag\CompoundTag; @@ -26,7 +26,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{ /** @var FurnaceInventory */ protected $inventory; - public function __construct(FullChunk $chunk, CompoundTag $nbt){ + public function __construct(Chunk $chunk, CompoundTag $nbt){ parent::__construct($chunk, $nbt); $this->inventory = new FurnaceInventory($this); @@ -122,7 +122,7 @@ public function getItem($index){ if($i < 0){ return Item::get(Item::AIR, 0, 0); }else{ - return NBT::getItemHelper($this->namedtag->Items[$i]); + return Item::nbtDeserialize($this->namedtag->Items[$i]); } } @@ -137,8 +137,6 @@ public function getItem($index){ public function setItem($index, Item $item){ $i = $this->getSlotIndex($index); - $d = NBT::putItemHelper($item, $index); - if($item->getId() === Item::AIR or $item->getCount() <= 0){ if($i >= 0){ unset($this->namedtag->Items[$i]); @@ -149,9 +147,9 @@ public function setItem($index, Item $item){ break; } } - $this->namedtag->Items[$i] = $d; + $this->namedtag->Items[$i] = $item->nbtSerialize($index); }else{ - $this->namedtag->Items[$i] = $d; + $this->namedtag->Items[$i] = $item->nbtSerialize($index); } return true; @@ -237,7 +235,6 @@ public function onUpdate(){ } $ret = true; }else{ - ; if($this->getBlock()->getId() === Item::BURNING_FURNACE){ $this->getLevel()->setBlock($this, Block::get(Item::FURNACE, $this->getBlock()->getDamage()), true); } @@ -273,7 +270,7 @@ public function onUpdate(){ public function getSpawnCompound(){ $nbt = new CompoundTag("", [ - new StringTag("id", solidentity::FURNACE), + new StringTag("id", Tile::FURNACE), new IntTag("x", (int) $this->x), new IntTag("y", (int) $this->y), new IntTag("z", (int) $this->z), diff --git a/src/devmine/inventory/solidentity/Hopper.php b/src/devmine/inventory/solidentity/Hopper.php new file mode 100644 index 0000000..ac583f0 --- /dev/null +++ b/src/devmine/inventory/solidentity/Hopper.php @@ -0,0 +1,307 @@ +inventory = new HopperInventory($this); + + if(!isset($this->namedtag->Items) or !($this->namedtag->Items instanceof ListTag)){ + $this->namedtag->Items = new ListTag("Items", []); + $this->namedtag->Items->setTagType(NBT::TAG_Compound); + } + + for($i = 0; $i < $this->getSize(); ++$i){ + $this->inventory->setItem($i, $this->getItem($i)); + } + $this->namedtag->TransferCooldown = new IntTag("TransferCooldown", 0); + + $this->scheduleUpdate(); + } + + public function close(){ + if($this->closed === false){ + foreach($this->getInventory()->getViewers() as $player){ + $player->removeWindow($this->getInventory()); + } + + foreach($this->getInventory()->getViewers() as $player){ + $player->removeWindow($this->getInventory()); + } + parent::close(); + } + } + + public function activate(){ + $this->isPowered = true; + } + + public function deactivate(){ + $this->isPowered = false; + } + + public function canUpdate(){ + return $this->namedtag->TransferCooldown->getValue() === 0 and !$this->isPowered; + } + + public function resetCooldownTicks(){ + $this->namedtag->TransferCooldown->setValue(8); + } + + public function onUpdate(){ + if(!($this->getBlock() instanceof HopperBlock)){ + return false; + } + //Pickup dropped items + //This can happen at any time regardless of cooldown + $area = clone $this->getBlock()->getBoundingBox(); //Area above hopper to draw items from + $area->maxY = ceil($area->maxY) + 1; //Account for full block above, not just 1 + 5/8 + foreach($this->getLevel()->getChunkEntities($this->getBlock()->x >> 4, $this->getBlock()->z >> 4) as $entity){ + if(!($entity instanceof DroppedItem) or !$entity->isAlive()){ + continue; + } + if(!$entity->boundingBox->intersectsWith($area)){ + continue; + } + + $item = $entity->getItem(); + if(!$item instanceof Item){ + continue; + } + if($item->getCount() < 1){ + $entity->kill(); + continue; + } + + if($this->inventory->canAddItem($item)){ + $this->inventory->addItem($item); + $entity->kill(); + } + } + + if(!$this->canUpdate()){ //Hoppers only update CONTENTS every 8th tick + $this->namedtag->TransferCooldown->setValue($this->namedtag->TransferCooldown->getValue() - 1); + return true; + } + + //Suck items from above tile inventories + $source = $this->getLevel()->getTile($this->getBlock()->getSide(Vector3::SIDE_UP)); + if($source instanceof Tile and $source instanceof InventoryHolder){ + $inventory = $source->getInventory(); + $item = clone $inventory->getItem($inventory->firstOccupied()); + $item->setCount(1); + if($this->inventory->canAddItem($item)){ + $this->inventory->addItem($item); + $inventory->removeItem($item); + $this->resetCooldownTicks(); + if($source instanceof Hopper){ + $source->resetCooldownTicks(); + } + } + } + + //Feed item into target inventory + //Do not do this if there's a hopper underneath this hopper, to follow vanilla behaviour + if(!($this->getLevel()->getTile($this->getBlock()->getSide(Vector3::SIDE_DOWN)) instanceof Hopper)){ + $target = $this->getLevel()->getTile($this->getBlock()->getSide($this->getBlock()->getDamage())); + if($target instanceof Tile and $target instanceof InventoryHolder){ + $inv = $target->getInventory(); + foreach($this->inventory->getContents() as $item){ + if($item->getId() === Item::AIR or $item->getCount() < 1){ + continue; + } + $targetItem = clone $item; + $targetItem->setCount(1); + + if($inv->canAddItem($targetItem)){ + $inv->addItem($targetItem); + $this->inventory->removeItem($targetItem); + $this->resetCooldownTicks(); + if($target instanceof Hopper){ + $target->resetCooldownTicks(); + } + break; + } + + } + } + } + + return true; + } + + /** + * @return HopperInventory + */ + public function getInventory(){ + return $this->inventory; + } + + /** + * @return int + */ + public function getSize(){ + return 5; + } + + /** + * This method should not be used by plugins, use the Inventory + * + * @param int $index + * + * @return Item + */ + public function getItem($index){ + $i = $this->getSlotIndex($index); + if($i < 0){ + return Item::get(Item::AIR, 0, 0); + }else{ + return Item::nbtDeserialize($this->namedtag->Items[$i]); + } + } + + /** + * This method should not be used by plugins, use the Inventory + * + * @param int $index + * @param Item $item + * + * @return bool + */ + public function setItem($index, Item $item){ + $i = $this->getSlotIndex($index); + + if($item->getId() === Item::AIR or $item->getCount() <= 0){ + if($i >= 0){ + unset($this->namedtag->Items[$i]); + } + }elseif($i < 0){ + for($i = 0; $i <= $this->getSize(); ++$i){ + if(!isset($this->namedtag->Items[$i])){ + break; + } + } + $this->namedtag->Items[$i] = $item->nbtSerialize($index); + }else{ + $this->namedtag->Items[$i] = $item->nbtSerialize($index); + } + + return true; + } + + /** + * @param $index + * + * @return int + */ + protected function getSlotIndex($index){ + foreach($this->namedtag->Items as $i => $slot){ + if((int) $slot["Slot"] === (int) $index){ + return (int) $i; + } + } + + return -1; + } + + public function saveNBT(){ + $this->namedtag->Items = new ListTag("Items", []); + $this->namedtag->Items->setTagType(NBT::TAG_Compound); + for($index = 0; $index < $this->getSize(); ++$index){ + $this->setItem($index, $this->inventory->getItem($index)); + } + } + + public function getName() : string{ + return isset($this->namedtag->CustomName) ? $this->namedtag->CustomName->getValue() : "Hopper"; + } + + public function hasName(){ + return isset($this->namedtag->CustomName); + } + + public function setName($str){ + if($str === ""){ + unset($this->namedtag->CustomName); + return; + } + $this->namedtag->CustomName = new StringTag("CustomName", $str); + } + + + public function hasLock(){ + return isset($this->namedtag->Lock); + } + + public function setLock(string $itemName = ""){ + if($itemName === ""){ + unset($this->namedtag->Lock); + return; + } + $this->namedtag->Lock = new StringTag("Lock", $itemName); + } + + public function checkLock(string $key){ + return $this->namedtag->Lock->getValue() === $key; + } + + public function getSpawnCompound(){ + $c = new CompoundTag("", [ + new StringTag("id", Tile::HOPPER), + new IntTag("x", (int) $this->x), + new IntTag("y", (int) $this->y), + new IntTag("z", (int) $this->z) + ]); + + if($this->hasName()){ + $c->CustomName = $this->namedtag->CustomName; + } + if($this->hasLock()){ + $c->Lock = $this->namedtag->Lock; + } + + return $c; + } +} diff --git a/src/devmine/inventory/solidentity/ItemFrame.php b/src/devmine/inventory/solidentity/ItemFrame.php index cbb8062..57b37ce 100644 --- a/src/devmine/inventory/solidentity/ItemFrame.php +++ b/src/devmine/inventory/solidentity/ItemFrame.php @@ -5,97 +5,82 @@ namespace devmine\inventory\solidentity; use devmine\inventory\items\Item; -use devmine\levels\format\FullChunk; +use devmine\worlds\format\Chunk; use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\CompoundTag; use devmine\creatures\player\tag\FloatTag; use devmine\creatures\player\tag\IntTag; use devmine\creatures\player\tag\StringTag; -use devmine\creatures\player\NBT; class ItemFrame extends Spawnable{ - - public function __construct(FullChunk $chunk, CompoundTag $nbt){ - if(!isset($nbt->Item)){ - $nbt->Item = NBT::putItemHelper(Item::get(Item::AIR)); - $nbt->Item->setName("Item"); - } - + public function __construct(Chunk $chunk, CompoundTag $nbt){ if(!isset($nbt->ItemRotation)){ $nbt->ItemRotation = new ByteTag("ItemRotation", 0); } - if(!isset($nbt->ItemDropChance)){ $nbt->ItemDropChance = new FloatTag("ItemDropChance", 1.0); } - parent::__construct($chunk, $nbt); } - - public function getName() : string{ - return "Item Frame"; + + public function dropItem(){ + if(lcg_value() < $this->getDropChance() and $this->hasItem()){ + $this->level->dropItem($this, $this->getItem()); + } + $this->setItem(null); } - - public function getItemRotation(){ - return $this->namedtag["ItemRotation"]; + + public function hasItem() : bool{ + return $this->getItem()->getId() !== Item::AIR; } - - public function setItemRotation(int $itemRotation){ - $this->namedtag->ItemRotation = new ByteTag("ItemRotation", $itemRotation); - $this->setChanged(); + + public function getItem() : Item{ + if(isset($this->namedtag->Item)){ + return Item::nbtDeserialize($this->namedtag->Item); + }else{ + return Item::get(Item::AIR); + } } - - public function getItem(){ - return NBT::getItemHelper($this->namedtag->Item); + + public function setItem(Item $item = null){ + if($item !== null and $item->getId() !== Item::AIR){ + $this->namedtag->Item = $item->nbtSerialize(-1, "Item"); + }else{ + unset($this->namedtag->Item); + } + $this->onChanged(); } - - public function setItem(Item $item, bool $setChanged = true){ - $nbtItem = NBT::putItemHelper($item); - $nbtItem->setName("Item"); - $this->namedtag->Item = $nbtItem; - if($setChanged) $this->setChanged(); + + public function getItemRotation() : int{ + return $this->namedtag->ItemRotation->getValue(); } - - public function getItemDropChance(){ - return $this->namedtag["ItemDropChance"]; + + public function setItemRotation(int $rotation){ + $this->namedtag->ItemRotation = new ByteTag("ItemRotation", $rotation); + $this->onChanged(); } - - public function setItemDropChance($chance = 1.0){ - $this->namedtag->ItemDropChance = new FloatTag("ItemDropChance", $chance); + + public function getItemDropChance() : float{ + return $this->namedtag->ItemDropChance->getValue(); } - - private function setChanged(){ - $this->spawnToAll(); - if($this->chunk instanceof FullChunk){ - $this->chunk->setChanged(); - $this->level->clearChunkCache($this->chunk->getX(), $this->chunk->getZ()); - } + + public function setItemDropChance(float $chance){ + $this->namedtag->ItemDropChance = new FloatTag("ItemDropChance", $chance); + $this->onChanged(); } - + public function getSpawnCompound(){ - if(!isset($this->namedtag->Item)) $this->setItem(Item::get(Item::AIR), false); - /** @var CompoundTag $nbtItem */ - $nbtItem = clone $this->namedtag->Item; - $nbtItem->setName("Item"); - if($nbtItem["id"] == 0){ - return new CompoundTag("", [ - new StringTag("id", solidentity::ITEM_FRAME), - new IntTag("x", (int) $this->x), - new IntTag("y", (int) $this->y), - new IntTag("z", (int) $this->z), - new ByteTag("ItemRotation", 0), - new FloatTag("ItemDropChance", (float) $this->getItemDropChance()) - ]); - }else{ - return new CompoundTag("", [ - new StringTag("id", solidentity::ITEM_FRAME), - new IntTag("x", (int) $this->x), - new IntTag("y", (int) $this->y), - new IntTag("z", (int) $this->z), - $nbtItem, - new ByteTag("ItemRotation", (int) $this->getItemRotation()), - new FloatTag("ItemDropChance", (float) $this->getItemDropChance()) - ]); + $tag = new CompoundTag("", [ + new StringTag("id", Tile::ITEM_FRAME), + new IntTag("x", (int) $this->x), + new IntTag("y", (int) $this->y), + new IntTag("z", (int) $this->z), + $this->namedtag->ItemDropChance, + $this->namedtag->ItemRotation, + ]); + if($this->hasItem()){ + $tag->Item = $this->namedtag->Item; } + return $tag; } -} \ No newline at end of file +} diff --git a/src/devmine/inventory/solidentity/MobSpawner.php b/src/devmine/inventory/solidentity/MobSpawner.php index 8f2f240..64545af 100644 --- a/src/devmine/inventory/solidentity/MobSpawner.php +++ b/src/devmine/inventory/solidentity/MobSpawner.php @@ -1,11 +1,28 @@ EntityId)){ $nbt->EntityId = new IntTag("EntityId", 0); @@ -52,7 +69,7 @@ public function getEntityId(){ public function setEntityId(int $id){ $this->namedtag->EntityId->setValue($id); $this->spawnToAll(); - if($this->chunk instanceof FullChunk){ + if($this->chunk instanceof Chunk){ $this->chunk->setChanged(); $this->level->clearChunkCache($this->chunk->getX(), $this->chunk->getZ()); } @@ -128,7 +145,7 @@ public function onUpdate(){ $this->timings->startTiming(); - if(!($this->chunk instanceof FullChunk)){ + if(!($this->chunk instanceof Chunk)){ return false; } if($this->canUpdate()){ @@ -178,7 +195,7 @@ public function onUpdate(){ public function getSpawnCompound(){ $c = new CompoundTag("", [ - new StringTag("id", solidentity::MOB_SPAWNER), + new StringTag("id", Tile::MOB_SPAWNER), new IntTag("x", (int) $this->x), new IntTag("y", (int) $this->y), new IntTag("z", (int) $this->z), diff --git a/src/devmine/inventory/solidentity/Sign.php b/src/devmine/inventory/solidentity/Sign.php index 3efeb46..e8515dd 100644 --- a/src/devmine/inventory/solidentity/Sign.php +++ b/src/devmine/inventory/solidentity/Sign.php @@ -4,14 +4,14 @@ namespace devmine\inventory\solidentity; -use devmine\levels\format\FullChunk; +use devmine\worlds\format\Chunk; use devmine\creatures\player\tag\CompoundTag; use devmine\creatures\player\tag\IntTag; use devmine\creatures\player\tag\StringTag; class Sign extends Spawnable{ - public function __construct(FullChunk $chunk, CompoundTag $nbt){ + public function __construct(Chunk $chunk, CompoundTag $nbt){ if(!isset($nbt->Text1)){ $nbt->Text1 = new StringTag("Text1", ""); } @@ -38,12 +38,7 @@ public function setText($line1 = "", $line2 = "", $line3 = "", $line4 = ""){ $this->namedtag->Text2 = new StringTag("Text2", $line2); $this->namedtag->Text3 = new StringTag("Text3", $line3); $this->namedtag->Text4 = new StringTag("Text4", $line4); - $this->spawnToAll(); - - if($this->chunk){ - $this->chunk->setChanged(); - $this->level->clearChunkCache($this->chunk->getX(), $this->chunk->getZ()); - } + $this->onChanged(); return true; } @@ -59,7 +54,7 @@ public function getText(){ public function getSpawnCompound(){ return new CompoundTag("", [ - new StringTag("id", solidentity::SIGN), + new StringTag("id", Tile::SIGN), $this->namedtag->Text1, $this->namedtag->Text2, $this->namedtag->Text3, diff --git a/src/devmine/inventory/solidentity/Skull.php b/src/devmine/inventory/solidentity/Skull.php index 44a2dd1..5a0f340 100644 --- a/src/devmine/inventory/solidentity/Skull.php +++ b/src/devmine/inventory/solidentity/Skull.php @@ -1,47 +1,45 @@ SkullType)){ - $nbt->SkullType = new StringTag("SkullType", 0); + $nbt->SkullType = new ByteTag("SkullType", 0); + } + if(!isset($nbt->Rot)){ + $nbt->Rot = new ByteTag("Rot", 0); } - parent::__construct($chunk, $nbt); } - - public function saveNBT(){ - parent::saveNBT(); - unset($this->namedtag->Creator); + public function setType($type){ + if($type >= 0 && $type <= 4){ + $this->namedtag->SkullType = new ByteTag("SkullType", $type); + $this->onChanged(); + return true; + } + return false; + } + public function getType(){ + return $this->namedtag["SkullType"]; } - public function getSpawnCompound(){ return new CompoundTag("", [ - new StringTag("id", solidentity::SKULL), + new StringTag("id", Tile::SKULL), $this->namedtag->SkullType, - new IntTag("x", (int)$this->x), - new IntTag("y", (int)$this->y), - new IntTag("z", (int)$this->z), - $this->namedtag->Rot + $this->namedtag->Rot, + new IntTag("x", (int) $this->x), + new IntTag("y", (int) $this->y), + new IntTag("z", (int) $this->z) ]); } - - public function getSkullType(){ - return $this->namedtag["SkullType"]; - } } diff --git a/src/devmine/inventory/solidentity/SolidEntity.php b/src/devmine/inventory/solidentity/SolidEntity.php index b110637..4c66b2c 100644 --- a/src/devmine/inventory/solidentity/SolidEntity.php +++ b/src/devmine/inventory/solidentity/SolidEntity.php @@ -3,38 +3,40 @@ /** - * All the solidentity classes and related classes + * All the Tile classes and related classes */ namespace devmine\inventory\solidentity; -use devmine\server\events\Timings; -use devmine\levels\format\Chunk; -use devmine\levels\format\FullChunk; -use devmine\levels\Level; -use devmine\levels\Position; +use devmine\events\Timings; +use devmine\worlds\format\Chunk; +use devmine\worlds\Level; +use devmine\worlds\Position; use devmine\creatures\player\tag\CompoundTag; use devmine\creatures\player\tag\IntTag; use devmine\creatures\player\tag\StringTag; use devmine\utilities\main\ChunkException; -abstract class solidentity extends Position{ - const SIGN = "Sign"; +abstract class Tile extends Position{ + + const BREWING_STAND = "BrewingStand"; const CHEST = "Chest"; - const FURNACE = "Furnace"; + const ENCHANT_TABLE = "EnchantTable"; const FLOWER_POT = "FlowerPot"; + const FURNACE = "Furnace"; const MOB_SPAWNER = "MobSpawner"; + const SIGN = "Sign"; const SKULL = "Skull"; - const BREWING_STAND = "BrewingStand"; - const ENCHANT_TABLE = "EnchantTable"; const ITEM_FRAME = "ItemFrame"; const DISPENSER = "Dispenser"; const DROPPER = "Dropper"; const DAY_LIGHT_DETECTOR = "DLDetector"; const CAULDRON = "Cauldron"; + const HOPPER = "Hopper"; + const BEACON = "Beacon"; - public static $solidentityCount = 1; + public static $tileCount = 1; - private static $knownsolidentities = []; + private static $knownTiles = []; private static $shortNames = []; /** @var Chunk */ @@ -45,27 +47,27 @@ abstract class solidentity extends Position{ public $y; public $z; public $attach; - public $epilogos; + public $metadata; public $closed = false; public $namedtag; protected $lastUpdate; protected $server; protected $timings; - /** @var \devmine\server\events\TimingsHandler */ + /** @var \devmine\events\TimingsHandler */ public $tickTimer; /** * @param string $type - * @param FullChunk $chunk + * @param Chunk $chunk * @param CompoundTag $nbt * @param $args * - * @return solidentity + * @return Tile */ - public static function createsolidentity($type, FullChunk $chunk, CompoundTag $nbt, ...$args){ - if(isset(self::$knownsolidentities[$type])){ - $class = self::$knownsolidentities[$type]; + public static function createTile($type, Chunk $chunk, CompoundTag $nbt, ...$args){ + if(isset(self::$knownTiles[$type])){ + $class = self::$knownTiles[$type]; return new $class($chunk, $nbt, ...$args); } @@ -77,10 +79,10 @@ public static function createsolidentity($type, FullChunk $chunk, CompoundTag $n * * @return bool */ - public static function registersolidentity($className){ + public static function registerTile($className){ $class = new \ReflectionClass($className); - if(is_a($className, solidentity::class, true) and !$class->isAbstract()){ - self::$knownsolidentities[$class->getShortName()] = $className; + if(is_a($className, Tile::class, true) and !$class->isAbstract()){ + self::$knownTiles[$class->getShortName()] = $className; self::$shortNames[$className] = $class->getShortName(); return true; } @@ -97,12 +99,12 @@ public function getSaveId(){ return self::$shortNames[static::class]; } - public function __construct(FullChunk $chunk, CompoundTag $nbt){ + public function __construct(Chunk $chunk, CompoundTag $nbt){ if($chunk === null or $chunk->getProvider() === null){ - throw new ChunkException("Invalid garbage Chunk given to solidentity"); + throw new ChunkException("Invalid garbage Chunk given to Tile"); } - $this->timings = Timings::getsolidentityEntityTimings($this); + $this->timings = Timings::getTileEntityTimings($this); $this->server = $chunk->getProvider()->getLevel()->getServer(); $this->chunk = $chunk; @@ -110,14 +112,14 @@ public function __construct(FullChunk $chunk, CompoundTag $nbt){ $this->namedtag = $nbt; $this->name = ""; $this->lastUpdate = microtime(true); - $this->id = solidentity::$solidentityCount++; + $this->id = Tile::$tileCount++; $this->x = (int) $this->namedtag["x"]; $this->y = (int) $this->namedtag["y"]; $this->z = (int) $this->namedtag["z"]; - $this->chunk->addsolidentity($this); - $this->getLevel()->addsolidentity($this); - $this->tickTimer = Timings::getsolidentityEntityTimings($this); + $this->chunk->addTile($this); + $this->getLevel()->addTile($this); + $this->tickTimer = Timings::getTileEntityTimings($this); } public function getId(){ @@ -143,7 +145,7 @@ public function onUpdate(){ } public final function scheduleUpdate(){ - $this->level->updatesolidentities[$this->id] = $this; + $this->level->updateTiles[$this->id] = $this; } public function __destruct(){ @@ -153,12 +155,12 @@ public function __destruct(){ public function close(){ if(!$this->closed){ $this->closed = true; - unset($this->level->updatesolidentities[$this->id]); - if($this->chunk instanceof FullChunk){ - $this->chunk->removesolidentity($this); + unset($this->level->updateTiles[$this->id]); + if($this->chunk instanceof Chunk){ + $this->chunk->removeTile($this); } if(($level = $this->getLevel()) instanceof Level){ - $level->removesolidentity($this); + $level->removeTile($this); } $this->level = null; } diff --git a/src/devmine/inventory/solidentity/Spawnable.php b/src/devmine/inventory/solidentity/Spawnable.php index 77fbdd3..571c3f8 100644 --- a/src/devmine/inventory/solidentity/Spawnable.php +++ b/src/devmine/inventory/solidentity/Spawnable.php @@ -1,54 +1,57 @@ closed){ return false; } - $nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt->setData($this->getSpawnCompound()); $pk = new BlockEntityDataPacket(); $pk->x = $this->x; $pk->y = $this->y; $pk->z = $this->z; - $pk->namedtag = $nbt->write(); + $pk->namedtag = $nbt->write(true); $player->dataPacket($pk); - return true; } - + /** * @return CompoundTag */ public abstract function getSpawnCompound(); - - public function __construct(FullChunk $chunk, CompoundTag $nbt){ + + public function __construct(Chunk $chunk, CompoundTag $nbt){ parent::__construct($chunk, $nbt); $this->spawnToAll(); } - + public function spawnToAll(){ if($this->closed){ return; } - foreach($this->getLevel()->getChunkPlayers($this->chunk->getX(), $this->chunk->getZ()) as $player){ if($player->spawned === true){ $this->spawnTo($player); } } } + + protected function onChanged(){ + $this->spawnToAll(); + if($this->chunk !== null){ + $this->chunk->setChanged(); + $this->level->clearChunkCache($this->chunk->getX(), $this->chunk->getZ()); + } + } } diff --git a/src/devmine/levels/SimpleChunkManager.php b/src/devmine/levels/SimpleChunkManager.php deleted file mode 100644 index e104efa..0000000 --- a/src/devmine/levels/SimpleChunkManager.php +++ /dev/null @@ -1,249 +0,0 @@ -seed = $seed; - $this->waterHeight = $waterHeight; - } - - public function getWaterHeight() : int{ - return $this->waterHeight; - } - - /** - * Gets the raw block id. - * - * @param int $x - * @param int $y - * @param int $z - * - * @return int 0-255 - */ - public function getBlockIdAt(int $x, int $y, int $z) : int{ - if($chunk = $this->getChunk($x >> 4, $z >> 4)){ - return $chunk->getBlockId($x & 0xf, $y & 0x7f, $z & 0xf); - } - return 0; - } - - /** - * Sets the raw block id. - * - * @param int $x - * @param int $y - * @param int $z - * @param int $id 0-255 - */ - public function setBlockIdAt(int $x, int $y, int $z, int $id){ - if($chunk = $this->getChunk($x >> 4, $z >> 4)){ - $chunk->setBlockId($x & 0xf, $y & 0x7f, $z & 0xf, $id); - } - } - - /** - * Gets the raw block epilogos - * - * @param int $x - * @param int $y - * @param int $z - * - * @return int 0-15 - */ - public function getBlockDataAt(int $x, int $y, int $z) : int{ - if($chunk = $this->getChunk($x >> 4, $z >> 4)){ - return $chunk->getBlockData($x & 0xf, $y & 0x7f, $z & 0xf); - } - return 0; - } - - /** - * Sets the raw block epilogos. - * - * @param int $x - * @param int $y - * @param int $z - * @param int $data 0-15 - */ - public function setBlockDataAt(int $x, int $y, int $z, int $data){ - if($chunk = $this->getChunk($x >> 4, $z >> 4)){ - $chunk->setBlockData($x & 0xf, $y & 0x7f, $z & 0xf, $data); - } - } - - /** - * Gets the raw block light level - * - * @param int $x - * @param int $y - * @param int $z - * - * @return int 0-15 - */ - public function getBlockLightAt($x, $y, $z){ - if($chunk = $this->getChunk($x >> 4, $z >> 4)){ - return $chunk->getBlockLight($x & 0x0f, $y & 0x7f, $z & 0x0f); - } - return 0; - } - - /** - * Sets the raw block light level. - * - * @param int $x - * @param int $y - * @param int $z - * @param int $level 0-15 - */ - public function setBlockLightAt($x, $y, $z, $level){ - if($chunk = $this->getChunk($x >> 4, $z >> 4)){ - $chunk->setBlockLight($x & 0x0f, $y & 0x7f, $z & 0x0f, $level & 0x0f); - } - } - - /** - * Updates the light around the block - * - * @param $x - * @param $y - * @param $z - */ - public function updateBlockLight($x, $y, $z){ - $lightPropagationQueue = new \SplQueue(); - $lightRemovalQueue = new \SplQueue(); - $visited = []; - $removalVisited = []; - - $oldLevel = $this->getBlockLightAt($x, $y, $z); - $newLevel = (int) Block::$light[$this->getBlockIdAt($x, $y, $z)]; - - if($oldLevel !== $newLevel){ - $this->setBlockLightAt($x, $y, $z, $newLevel); - - if($newLevel < $oldLevel){ - $removalVisited[Level::blockHash($x, $y, $z)] = true; - $lightRemovalQueue->enqueue([new Vector3($x, $y, $z), $oldLevel]); - }else{ - $visited[Level::blockHash($x, $y, $z)] = true; - $lightPropagationQueue->enqueue(new Vector3($x, $y, $z)); - } - } - - while(!$lightRemovalQueue->isEmpty()){ - /** @var Vector3 $node */ - $val = $lightRemovalQueue->dequeue(); - $node = $val[0]; - $lightLevel = $val[1]; - - $this->computeRemoveBlockLight($node->x - 1, $node->y, $node->z, $lightLevel, $lightRemovalQueue, $lightPropagationQueue, $removalVisited, $visited); - $this->computeRemoveBlockLight($node->x + 1, $node->y, $node->z, $lightLevel, $lightRemovalQueue, $lightPropagationQueue, $removalVisited, $visited); - $this->computeRemoveBlockLight($node->x, $node->y - 1, $node->z, $lightLevel, $lightRemovalQueue, $lightPropagationQueue, $removalVisited, $visited); - $this->computeRemoveBlockLight($node->x, $node->y + 1, $node->z, $lightLevel, $lightRemovalQueue, $lightPropagationQueue, $removalVisited, $visited); - $this->computeRemoveBlockLight($node->x, $node->y, $node->z - 1, $lightLevel, $lightRemovalQueue, $lightPropagationQueue, $removalVisited, $visited); - $this->computeRemoveBlockLight($node->x, $node->y, $node->z + 1, $lightLevel, $lightRemovalQueue, $lightPropagationQueue, $removalVisited, $visited); - } - - while(!$lightPropagationQueue->isEmpty()){ - /** @var Vector3 $node */ - $node = $lightPropagationQueue->dequeue(); - - $lightLevel = $this->getBlockLightAt($node->x, $node->y, $node->z) - (int) Block::$lightFilter[$this->getBlockIdAt($node->x, $node->y, $node->z)]; - - if($lightLevel >= 1){ - $this->computeSpreadBlockLight($node->x - 1, $node->y, $node->z, $lightLevel, $lightPropagationQueue, $visited); - $this->computeSpreadBlockLight($node->x + 1, $node->y, $node->z, $lightLevel, $lightPropagationQueue, $visited); - $this->computeSpreadBlockLight($node->x, $node->y - 1, $node->z, $lightLevel, $lightPropagationQueue, $visited); - $this->computeSpreadBlockLight($node->x, $node->y + 1, $node->z, $lightLevel, $lightPropagationQueue, $visited); - $this->computeSpreadBlockLight($node->x, $node->y, $node->z - 1, $lightLevel, $lightPropagationQueue, $visited); - $this->computeSpreadBlockLight($node->x, $node->y, $node->z + 1, $lightLevel, $lightPropagationQueue, $visited); - } - } - } - - private function computeRemoveBlockLight($x, $y, $z, $currentLight, \SplQueue $queue, \SplQueue $spreadQueue, array &$visited, array &$spreadVisited){ - $current = $this->getBlockLightAt($x, $y, $z); - - if($current !== 0 and $current < $currentLight){ - $this->setBlockLightAt($x, $y, $z, 0); - - if(!isset($visited[$index = Level::blockHash($x, $y, $z)])){ - $visited[$index] = true; - if($current > 1){ - $queue->enqueue([new Vector3($x, $y, $z), $current]); - } - } - }elseif($current >= $currentLight){ - if(!isset($spreadVisited[$index = Level::blockHash($x, $y, $z)])){ - $spreadVisited[$index] = true; - $spreadQueue->enqueue(new Vector3($x, $y, $z)); - } - } - } - - private function computeSpreadBlockLight($x, $y, $z, $currentLight, \SplQueue $queue, array &$visited){ - $current = $this->getBlockLightAt($x, $y, $z); - - if($current < $currentLight){ - $this->setBlockLightAt($x, $y, $z, $currentLight); - - if(!isset($visited[$index = Level::blockHash($x, $y, $z)])){ - $visited[$index] = true; - if($currentLight > 1){ - $queue->enqueue(new Vector3($x, $y, $z)); - } - } - } - } - - /** - * @param int $chunkX - * @param int $chunkZ - * - * @return FullChunk|null - */ - public function getChunk(int $chunkX, int $chunkZ){ - return isset($this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)]) ? $this->chunks[$index] : null; - } - - /** - * @param int $chunkX - * @param int $chunkZ - * @param FullChunk $chunk - */ - public function setChunk(int $chunkX, int $chunkZ, FullChunk $chunk = null){ - if($chunk === null){ - unset($this->chunks[Level::chunkHash($chunkX, $chunkZ)]); - return; - } - $this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk; - } - - public function cleanChunks(){ - $this->chunks = []; - } - - /** - * Gets the level seed - * - * @return int - */ - public function getSeed(){ - return $this->seed; - } -} \ No newline at end of file diff --git a/src/devmine/levels/format/Chunk.php b/src/devmine/levels/format/Chunk.php deleted file mode 100644 index 6c58373..0000000 --- a/src/devmine/levels/format/Chunk.php +++ /dev/null @@ -1,39 +0,0 @@ -getChunk($x, $z, false); - if(!($chunk instanceof Chunk)){ - throw new ChunkException("Invalid Chunk sent"); - } - - if($this->getServer()->asyncChunkRequest){ - $task = new ChunkRequestTask($this->getLevel(), $chunk); - $this->getServer()->getScheduler()->scheduleAsyncTask($task); - }else{ - $solidentities = ""; - - if(count($chunk->getsolidentities()) > 0){ - $nbt = new NBT(NBT::LITTLE_ENDIAN); - $list = []; - foreach($chunk->getsolidentities() as $solidentity){ - if($solidentity instanceof Spawnable){ - $list[] = $solidentity->getSpawnCompound(); - } - } - $nbt->setData($list); - $solidentities = $nbt->write(); - } - - $extraData = new BinaryStream(); - $extraData->putLInt(count($chunk->getBlockExtraDataArray())); - foreach($chunk->getBlockExtraDataArray() as $key => $value){ - $extraData->putLInt($key); - $extraData->putLShort($value); - } - - $ordered = $chunk->getBlockIdArray() . - $chunk->getBlockDataArray() . - $chunk->getBlockSkyLightArray() . - $chunk->getBlockLightArray() . - pack("C*", ...$chunk->getHeightMapArray()) . - pack("N*", ...$chunk->getBiomeColorArray()) . - $extraData->getBuffer() . - $solidentities; - - $this->getLevel()->chunkRequestCallback($x, $z, $ordered, FullChunkDataPacket::ORDER_LAYERED); - } - - return null; - } - - /** - * @param $x - * @param $z - * - * @return RegionLoader - */ - protected function getRegion($x, $z){ - return isset($this->regions[$index = Level::chunkHash($x, $z)]) ? $this->regions[$index] : null; - } - - /** - * @param int $chunkX - * @param int $chunkZ - * @param bool $create - * - * @return Chunk - */ - public function getChunk($chunkX, $chunkZ, $create = false){ - return parent::getChunk($chunkX, $chunkZ, $create); - } - - public function setChunk($chunkX, $chunkZ, FullChunk $chunk){ - if(!($chunk instanceof Chunk)){ - throw new ChunkException("Invalid Chunk class"); - } - - $chunk->setProvider($this); - - self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); - $this->loadRegion($regionX, $regionZ); - - $chunk->setX($chunkX); - $chunk->setZ($chunkZ); - $this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk; - } - - public function getEmptyChunk($chunkX, $chunkZ){ - return Chunk::getEmptyChunk($chunkX, $chunkZ, $this); - } - - public static function createChunkSection($Y){ - return new ChunkSection(new CompoundTag("", [ - "Y" => new ByteTag("Y", $Y), - "Blocks" => new ByteArrayTag("Blocks", str_repeat("\x00", 4096)), - "Data" => new ByteArrayTag("Data", str_repeat("\x00", 2048)), - "SkyLight" => new ByteArrayTag("SkyLight", str_repeat("\xff", 2048)), - "BlockLight" => new ByteArrayTag("BlockLight", str_repeat("\x00", 2048)) - ])); - } - - public function isChunkGenerated($chunkX, $chunkZ){ - if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) !== null){ - return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32) and $this->getChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32, true)->isGenerated(); - } - - return false; - } - - protected function loadRegion($x, $z){ - if(isset($this->regions[$index = Level::chunkHash($x, $z)])){ - return true; - } - - $this->regions[$index] = new RegionLoader($this, $x, $z); - - return true; - } -} \ No newline at end of file diff --git a/src/devmine/levels/format/anvil/Chunk.php b/src/devmine/levels/format/anvil/Chunk.php deleted file mode 100644 index 01a075f..0000000 --- a/src/devmine/levels/format/anvil/Chunk.php +++ /dev/null @@ -1,351 +0,0 @@ -provider = $level; - $this->nbt = new CompoundTag("Level", []); - return; - } - - $this->nbt = $nbt; - - if(!isset($this->nbt->Entities) or !($this->nbt->Entities instanceof ListTag)){ - $this->nbt->Entities = new ListTag("Entities", []); - $this->nbt->Entities->setTagType(NBT::TAG_Compound); - } - - if(!isset($this->nbt->solidentityEntities) or !($this->nbt->solidentityEntities instanceof ListTag)){ - $this->nbt->solidentityEntities = new ListTag("solidentityEntities", []); - $this->nbt->solidentityEntities->setTagType(NBT::TAG_Compound); - } - - if(!isset($this->nbt->solidentityTicks) or !($this->nbt->solidentityTicks instanceof ListTag)){ - $this->nbt->solidentityTicks = new ListTag("solidentityTicks", []); - $this->nbt->solidentityTicks->setTagType(NBT::TAG_Compound); - } - - if(!isset($this->nbt->Sections) or !($this->nbt->Sections instanceof ListTag)){ - $this->nbt->Sections = new ListTag("Sections", []); - $this->nbt->Sections->setTagType(NBT::TAG_Compound); - } - - if(!isset($this->nbt->BiomeColors) or !($this->nbt->BiomeColors instanceof IntArrayTag)){ - $this->nbt->BiomeColors = new IntArrayTag("BiomeColors", array_fill(0, 256, 0)); - } - - if(!isset($this->nbt->HeightMap) or !($this->nbt->HeightMap instanceof IntArrayTag)){ - $this->nbt->HeightMap = new IntArrayTag("HeightMap", array_fill(0, 256, 0)); - } - - $sections = []; - foreach($this->nbt->Sections as $section){ - if($section instanceof CompoundTag){ - $y = (int) $section["Y"]; - if($y < 8){ - $sections[$y] = new ChunkSection($section); - } - } - } - for($y = 0; $y < 8; ++$y){ - if(!isset($sections[$y])){ - $sections[$y] = new EmptyChunkSection($y); - } - } - - $extraData = []; - - if(!isset($this->nbt->ExtraData) or !($this->nbt->ExtraData instanceof ByteArrayTag)){ - $this->nbt->ExtraData = new ByteArrayTag("ExtraData", Binary::writeInt(0)); - }else{ - $stream = new BinaryStream($this->nbt->ExtraData->getValue()); - $count = $stream->getInt(); - for($i = 0; $i < $count; ++$i){ - $key = $stream->getInt(); - $extraData[$key] = $stream->getShort(); - } - } - - parent::__construct($level, (int) $this->nbt["xPos"], (int) $this->nbt["zPos"], $sections, $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->solidentityEntities->getValue()); - - if(isset($this->nbt->Biomes)){ - $this->checkOldBiomes($this->nbt->Biomes->getValue()); - unset($this->nbt->Biomes); - } - - unset($this->nbt->Sections, $this->nbt->ExtraData); - } - - public function isLightPopulated(){ - return $this->nbt["LightPopulated"] > 0; - } - - public function setLightPopulated($value = 1){ - $this->nbt->LightPopulated = new ByteTag("LightPopulated", $value); - $this->hasChanged = true; - } - - /** - * @return bool - */ - public function isPopulated(){ - return $this->nbt["TerrainPopulated"] > 0; - } - - /** - * @param int $value - */ - public function setPopulated($value = 1){ - $this->nbt->TerrainPopulated = new ByteTag("TerrainPopulated", $value); - $this->hasChanged = true; - } - - /** - * @return bool - */ - public function isGenerated(){ - return $this->nbt["TerrainPopulated"] > 0 or (isset($this->nbt->TerrainGenerated) and $this->nbt["TerrainGenerated"] > 0); - } - - /** - * @param int $value - */ - public function setGenerated($value = 1){ - $this->nbt->TerrainGenerated = new ByteTag("TerrainGenerated", $value); - $this->hasChanged = true; - } - - /** - * @return CompoundTag - */ - public function getNBT(){ - return $this->nbt; - } - - /** - * @param string $data - * @param LevelProvider $provider - * - * @return Chunk - */ - public static function fromBinary($data, LevelProvider $provider = null){ - $nbt = new NBT(NBT::BIG_ENDIAN); - - try{ - $nbt->readCompressed($data, ZLIB_ENCODING_DEFLATE); - $chunk = $nbt->getData(); - - if(!isset($chunk->Level) or !($chunk->Level instanceof CompoundTag)){ - return null; - } - - return new Chunk($provider instanceof LevelProvider ? $provider : Anvil::class, $chunk->Level); - }catch(\Throwable $e){ - return null; - } - } - - /** - * @param string $data - * @param LevelProvider $provider - * - * @return Chunk - */ - public static function fromFastBinary($data, LevelProvider $provider = null){ - $nbt = new NBT(NBT::BIG_ENDIAN); - - try{ - $nbt->read($data); - $chunk = $nbt->getData(); - - if(!isset($chunk->Level) or !($chunk->Level instanceof CompoundTag)){ - return null; - } - - return new Chunk($provider instanceof LevelProvider ? $provider : Anvil::class, $chunk->Level); - }catch(\Throwable $e){ - return null; - } - } - - public function toFastBinary(){ - $nbt = clone $this->getNBT(); - - $nbt->xPos = new IntTag("xPos", $this->x); - $nbt->zPos = new IntTag("zPos", $this->z); - - $nbt->Sections = new ListTag("Sections", []); - $nbt->Sections->setTagType(NBT::TAG_Compound); - foreach($this->getSections() as $section){ - if($section instanceof EmptyChunkSection){ - continue; - } - $nbt->Sections[$section->getY()] = new CompoundTag(null, [ - "Y" => new ByteTag("Y", $section->getY()), - "Blocks" => new ByteArrayTag("Blocks", $section->getIdArray()), - "Data" => new ByteArrayTag("Data", $section->getDataArray()), - "BlockLight" => new ByteArrayTag("BlockLight", $section->getLightArray()), - "SkyLight" => new ByteArrayTag("SkyLight", $section->getSkyLightArray()) - ]); - } - - $nbt->BiomeColors = new IntArrayTag("BiomeColors", $this->getBiomeColorArray()); - - $nbt->HeightMap = new IntArrayTag("HeightMap", $this->getHeightMapArray()); - - $entities = []; - - foreach($this->getEntities() as $entity){ - if(!($entity instanceof Player) and !$entity->closed){ - $entity->saveNBT(); - $entities[] = $entity->namedtag; - } - } - - $nbt->Entities = new ListTag("Entities", $entities); - $nbt->Entities->setTagType(NBT::TAG_Compound); - - - $solidentities = []; - foreach($this->getsolidentities() as $solidentity){ - $solidentity->saveNBT(); - $solidentities[] = $solidentity->namedtag; - } - - $nbt->solidentityEntities = new ListTag("solidentityEntities", $solidentities); - $nbt->solidentityEntities->setTagType(NBT::TAG_Compound); - - $extraData = new BinaryStream(); - $extraData->putInt(count($this->getBlockExtraDataArray())); - foreach($this->getBlockExtraDataArray() as $key => $value){ - $extraData->putInt($key); - $extraData->putShort($value); - } - - $nbt->ExtraData = new ByteArrayTag("ExtraData", $extraData->getBuffer()); - - $writer = new NBT(NBT::BIG_ENDIAN); - $nbt->setName("Level"); - $writer->setData(new CompoundTag("", ["Level" => $nbt])); - - return $writer->write(); - } - - public function toBinary(){ - $nbt = clone $this->getNBT(); - - $nbt->xPos = new IntTag("xPos", $this->x); - $nbt->zPos = new IntTag("zPos", $this->z); - - $nbt->Sections = new ListTag("Sections", []); - $nbt->Sections->setTagType(NBT::TAG_Compound); - foreach($this->getSections() as $section){ - if($section instanceof EmptyChunkSection){ - continue; - } - $nbt->Sections[$section->getY()] = new CompoundTag(null, [ - "Y" => new ByteTag("Y", $section->getY()), - "Blocks" => new ByteArrayTag("Blocks", $section->getIdArray()), - "Data" => new ByteArrayTag("Data", $section->getDataArray()), - "BlockLight" => new ByteArrayTag("BlockLight", $section->getLightArray()), - "SkyLight" => new ByteArrayTag("SkyLight", $section->getSkyLightArray()) - ]); - } - - $nbt->BiomeColors = new IntArrayTag("BiomeColors", $this->getBiomeColorArray()); - - $nbt->HeightMap = new IntArrayTag("HeightMap", $this->getHeightMapArray()); - - $entities = []; - - foreach($this->getEntities() as $entity){ - if(!($entity instanceof Player) and !$entity->closed){ - $entity->saveNBT(); - $entities[] = $entity->namedtag; - } - } - - $nbt->Entities = new ListTag("Entities", $entities); - $nbt->Entities->setTagType(NBT::TAG_Compound); - - - $solidentities = []; - foreach($this->getsolidentities() as $solidentity){ - $solidentity->saveNBT(); - $solidentities[] = $solidentity->namedtag; - } - - $nbt->solidentityEntities = new ListTag("solidentityEntities", $solidentities); - $nbt->solidentityEntities->setTagType(NBT::TAG_Compound); - - $extraData = new BinaryStream(); - $extraData->putInt(count($this->getBlockExtraDataArray())); - foreach($this->getBlockExtraDataArray() as $key => $value){ - $extraData->putInt($key); - $extraData->putShort($value); - } - - $nbt->ExtraData = new ByteArrayTag("ExtraData", $extraData->getBuffer()); - - $writer = new NBT(NBT::BIG_ENDIAN); - $nbt->setName("Level"); - $writer->setData(new CompoundTag("", ["Level" => $nbt])); - - return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL); - } - - /** - * @param int $chunkX - * @param int $chunkZ - * @param LevelProvider $provider - * - * @return Chunk - */ - public static function getEmptyChunk($chunkX, $chunkZ, LevelProvider $provider = null){ - try{ - $chunk = new Chunk($provider instanceof LevelProvider ? $provider : Anvil::class, null); - $chunk->x = $chunkX; - $chunk->z = $chunkZ; - - for($y = 0; $y < 8; ++$y){ - $chunk->sections[$y] = new EmptyChunkSection($y); - } - - $chunk->heightMap = array_fill(0, 256, 0); - $chunk->biomeColors = array_fill(0, 256, 0); - - $chunk->nbt->V = new ByteTag("V", 1); - $chunk->nbt->InhabitedTime = new LongTag("InhabitedTime", 0); - $chunk->nbt->TerrainGenerated = new ByteTag("TerrainGenerated", 0); - $chunk->nbt->TerrainPopulated = new ByteTag("TerrainPopulated", 0); - $chunk->nbt->LightPopulated = new ByteTag("LightPopulated", 0); - - return $chunk; - }catch(\Throwable $e){ - return null; - } - } -} \ No newline at end of file diff --git a/src/devmine/levels/format/anvil/ChunkRequestTask.php b/src/devmine/levels/format/anvil/ChunkRequestTask.php deleted file mode 100644 index c713679..0000000 --- a/src/devmine/levels/format/anvil/ChunkRequestTask.php +++ /dev/null @@ -1,74 +0,0 @@ -levelId = $level->getId(); - - $this->chunk = $chunk->toFastBinary(); - $this->chunkX = $chunk->getX(); - $this->chunkZ = $chunk->getZ(); - - $solidentities = ""; - $nbt = new NBT(NBT::LITTLE_ENDIAN); - foreach($chunk->getsolidentities() as $solidentity){ - if($solidentity instanceof Spawnable){ - $nbt->setData($solidentity->getSpawnCompound()); - $solidentities .= $nbt->write(); - } - } - - $this->solidentities = $solidentities; - } - - public function onRun(){ - - $chunk = Chunk::fromFastBinary($this->chunk); - $extraData = new BinaryStream(); - $extraData->putLInt(count($chunk->getBlockExtraDataArray())); - foreach($chunk->getBlockExtraDataArray() as $key => $value){ - $extraData->putLInt($key); - $extraData->putLShort($value); - } - - $ordered = $chunk->getBlockIdArray() . - $chunk->getBlockDataArray() . - $chunk->getBlockSkyLightArray() . - $chunk->getBlockLightArray() . - pack("C*", ...$chunk->getHeightMapArray()) . - pack("N*", ...$chunk->getBiomeColorArray()) . - $extraData->getBuffer() . - $this->solidentities; - - $this->setResult($ordered, false); - } - - public function onCompletion(Server $server){ - $level = $server->getLevel($this->levelId); - if($level instanceof Level and $this->hasResult()){ - $level->chunkRequestCallback($this->chunkX, $this->chunkZ, $this->getResult(), FullChunkDataPacket::ORDER_LAYERED); - } - } - -} \ No newline at end of file diff --git a/src/devmine/levels/format/anvil/ChunkSection.php b/src/devmine/levels/format/anvil/ChunkSection.php deleted file mode 100644 index cfe118f..0000000 --- a/src/devmine/levels/format/anvil/ChunkSection.php +++ /dev/null @@ -1,215 +0,0 @@ -y = (int) $nbt["Y"]; - $this->blocks = (string) $nbt["Blocks"]; - $this->data = (string) $nbt["Data"]; - $this->blockLight = (string) $nbt["BlockLight"]; - $this->skyLight = (string) $nbt["SkyLight"]; - } - - public function getY(){ - return $this->y; - } - - public function getBlockId($x, $y, $z){ - return ord($this->blocks{($y << 8) + ($z << 4) + $x}); - } - - public function setBlockId($x, $y, $z, $id){ - $this->blocks{($y << 8) + ($z << 4) + $x} = chr($id); - } - - public function getBlockData($x, $y, $z){ - $m = ord($this->data{($y << 7) + ($z << 3) + ($x >> 1)}); - if(($x & 1) === 0){ - return $m & 0x0F; - }else{ - return $m >> 4; - } - } - - public function setBlockData($x, $y, $z, $data){ - $i = ($y << 7) + ($z << 3) + ($x >> 1); - $old_m = ord($this->data{$i}); - if(($x & 1) === 0){ - $this->data{$i} = chr(($old_m & 0xf0) | ($data & 0x0f)); - }else{ - $this->data{$i} = chr((($data & 0x0f) << 4) | ($old_m & 0x0f)); - } - } - - public function getBlock($x, $y, $z, &$blockId, &$meta = null){ - $full = $this->getFullBlock($x, $y, $z); - $blockId = $full >> 4; - $meta = $full & 0x0f; - } - - public function getFullBlock($x, $y, $z){ - $i = ($y << 8) + ($z << 4) + $x; - if(($x & 1) === 0){ - return (ord($this->blocks{$i}) << 4) | (ord($this->data{$i >> 1}) & 0x0F); - }else{ - return (ord($this->blocks{$i}) << 4) | (ord($this->data{$i >> 1}) >> 4); - } - } - - public function setBlock($x, $y, $z, $blockId = null, $meta = null){ - $i = ($y << 8) + ($z << 4) + $x; - - $changed = false; - - if($blockId !== null){ - $blockId = chr($blockId); - if($this->blocks{$i} !== $blockId){ - $this->blocks{$i} = $blockId; - $changed = true; - } - } - - if($meta !== null){ - $i >>= 1; - $old_m = ord($this->data{$i}); - if(($x & 1) === 0){ - $this->data{$i} = chr(($old_m & 0xf0) | ($meta & 0x0f)); - if(($old_m & 0x0f) !== $meta){ - $changed = true; - } - }else{ - $this->data{$i} = chr((($meta & 0x0f) << 4) | ($old_m & 0x0f)); - if((($old_m & 0xf0) >> 4) !== $meta){ - $changed = true; - } - } - } - - return $changed; - } - - public function getBlockSkyLight($x, $y, $z){ - $sl = ord($this->skyLight{($y << 7) + ($z << 3) + ($x >> 1)}); - if(($x & 1) === 0){ - return $sl & 0x0F; - }else{ - return $sl >> 4; - } - } - - public function setBlockSkyLight($x, $y, $z, $level){ - $i = ($y << 7) + ($z << 3) + ($x >> 1); - $old_sl = ord($this->skyLight{$i}); - if(($x & 1) === 0){ - $this->skyLight{$i} = chr(($old_sl & 0xf0) | ($level & 0x0f)); - }else{ - $this->skyLight{$i} = chr((($level & 0x0f) << 4) | ($old_sl & 0x0f)); - } - } - - public function getBlockLight($x, $y, $z){ - $l = ord($this->blockLight{($y << 7) + ($z << 3) + ($x >> 1)}); - if(($x & 1) === 0){ - return $l & 0x0F; - }else{ - return $l >> 4; - } - } - - public function setBlockLight($x, $y, $z, $level){ - $i = ($y << 7) + ($z << 3) + ($x >> 1); - $old_l = ord($this->blockLight{$i}); - if(($x & 1) === 0){ - $this->blockLight{$i} = chr(($old_l & 0xf0) | ($level & 0x0f)); - }else{ - $this->blockLight{$i} = chr((($level & 0x0f) << 4) | ($old_l & 0x0f)); - } - } - - public function getBlockIdColumn($x, $z){ - $i = ($z << 4) + $x; - $column = ""; - for($y = 0; $y < 16; ++$y){ - $column .= $this->blocks{($y << 8) + $i}; - } - - return $column; - } - - public function getBlockDataColumn($x, $z){ - $i = ($z << 3) + ($x >> 1); - $column = ""; - if(($x & 1) === 0){ - for($y = 0; $y < 16; $y += 2){ - $column .= ($this->data{($y << 7) + $i} & "\x0f") | chr((ord($this->data{(($y + 1) << 7) + $i}) & 0x0f) << 4); - } - }else{ - for($y = 0; $y < 16; $y += 2){ - $column .= chr((ord($this->data{($y << 7) + $i}) & 0xf0) >> 4) | ($this->data{(($y + 1) << 7) + $i} & "\xf0"); - } - } - - return $column; - } - - public function getBlockSkyLightColumn($x, $z){ - $i = ($z << 3) + ($x >> 1); - $column = ""; - if(($x & 1) === 0){ - for($y = 0; $y < 16; $y += 2){ - $column .= ($this->skyLight{($y << 7) + $i} & "\x0f") | chr((ord($this->skyLight{(($y + 1) << 7) + $i}) & 0x0f) << 4); - } - }else{ - for($y = 0; $y < 16; $y += 2){ - $column .= chr((ord($this->skyLight{($y << 7) + $i}) & 0xf0) >> 4) | ($this->skyLight{(($y + 1) << 7) + $i} & "\xf0"); - } - } - - return $column; - } - - public function getBlockLightColumn($x, $z){ - $i = ($z << 3) + ($x >> 1); - $column = ""; - if(($x & 1) === 0){ - for($y = 0; $y < 16; $y += 2){ - $column .= ($this->blockLight{($y << 7) + $i} & "\x0f") | chr((ord($this->blockLight{(($y + 1) << 7) + $i}) & 0x0f) << 4); - } - }else{ - for($y = 0; $y < 16; $y += 2){ - $column .= chr((ord($this->blockLight{($y << 7) + $i}) & 0xf0) >> 4) | ($this->blockLight{(($y + 1) << 7) + $i} & "\xf0"); - } - } - - return $column; - } - - public function getIdArray(){ - return $this->blocks; - } - - public function getDataArray(){ - return $this->data; - } - - public function getSkyLightArray(){ - return $this->skyLight; - } - - public function getLightArray(){ - return $this->blockLight; - } - -} \ No newline at end of file diff --git a/src/devmine/levels/format/anvil/RegionLoader.php b/src/devmine/levels/format/anvil/RegionLoader.php deleted file mode 100644 index dab5310..0000000 --- a/src/devmine/levels/format/anvil/RegionLoader.php +++ /dev/null @@ -1,34 +0,0 @@ -x = $regionX; - $this->z = $regionZ; - $this->levelProvider = $level; - $this->filePath = $this->levelProvider->getPath() . "region/r.$regionX.$regionZ.mca"; - $exists = file_exists($this->filePath); - touch($this->filePath); - $this->filePointer = fopen($this->filePath, "r+b"); - stream_set_read_buffer($this->filePointer, 1024 * 16); //16KB - stream_set_write_buffer($this->filePointer, 1024 * 16); //16KB - if(!$exists){ - $this->createBlank(); - }else{ - $this->loadLocationTable(); - } - - $this->lastUsed = time(); - } - - protected function unserializeChunk($data){ - return Chunk::fromBinary($data, $this->levelProvider); - } -} \ No newline at end of file diff --git a/src/devmine/levels/format/generic/BaseChunk.php b/src/devmine/levels/format/generic/BaseChunk.php deleted file mode 100644 index 52fd038..0000000 --- a/src/devmine/levels/format/generic/BaseChunk.php +++ /dev/null @@ -1,250 +0,0 @@ -provider = $provider; - $this->x = (int) $x; - $this->z = (int) $z; - foreach($sections as $Y => $section){ - if($section instanceof ChunkSection){ - $this->sections[$Y] = $section; - }else{ - throw new ChunkException("Received invalid ChunkSection instance"); - } - - if($Y >= self::SECTION_COUNT){ - throw new ChunkException("Invalid amount of chunks"); - } - } - - if(count($biomeColors) === 256){ - $this->biomeColors = $biomeColors; - }else{ - $this->biomeColors = array_fill(0, 256, Binary::readInt("\xff\x00\x00\x00")); - } - - if(count($heightMap) === 256){ - $this->heightMap = $heightMap; - }else{ - $this->heightMap = array_fill(0, 256, 127); - } - - $this->NBTsolidentities = $solidentities; - $this->NBTentities = $entities; - } - - public function getBlock($x, $y, $z, &$blockId, &$meta = null){ - $full = $this->sections[$y >> 4]->getFullBlock($x, $y & 0x0f, $z); - $blockId = $full >> 4; - $meta = $full & 0x0f; - } - - public function getFullBlock($x, $y, $z){ - return isset($this->sections[$y >> 4]) ? $this->sections[$y >> 4]->getFullBlock($x, $y & 0x0f, $z) : 0; - } - - public function setBlock($x, $y, $z, $blockId = null, $meta = null){ - try{ - $this->hasChanged = true; - return $this->sections[$y >> 4]->setBlock($x, $y & 0x0f, $z, $blockId & 0xff, $meta & 0x0f); - }catch(ChunkException $e){ - $level = $this->getProvider(); - $this->setInternalSection($Y = $y >> 4, $level::createChunkSection($Y)); - return $this->sections[$y >> 4]->setBlock($x, $y & 0x0f, $z, $blockId & 0xff, $meta & 0x0f); - } - } - - public function getBlockId($x, $y, $z){ - if(isset($this->sections[$y >> 4])) return $this->sections[$y >> 4]->getBlockId($x, $y & 0x0f, $z); - else return 0; - } - - public function setBlockId($x, $y, $z, $id){ - try{ - $this->sections[$y >> 4]->setBlockId($x, $y & 0x0f, $z, $id); - $this->hasChanged = true; - }catch(ChunkException $e){ - $level = $this->getProvider(); - $this->setInternalSection($Y = $y >> 4, $level::createChunkSection($Y)); - $this->setBlockId($x, $y, $z, $id); - } - } - - public function getBlockData($x, $y, $z){ - return $this->sections[$y >> 4]->getBlockData($x, $y & 0x0f, $z); - } - - public function setBlockData($x, $y, $z, $data){ - try{ - $this->sections[$y >> 4]->setBlockData($x, $y & 0x0f, $z, $data); - $this->hasChanged = true; - }catch(ChunkException $e){ - $level = $this->getProvider(); - $this->setInternalSection($Y = $y >> 4, $level::createChunkSection($Y)); - $this->setBlockData($x, $y, $z, $data); - } - } - - public function getBlockSkyLight($x, $y, $z){ - return $this->sections[$y >> 4]->getBlockSkyLight($x, $y & 0x0f, $z); - } - - public function setBlockSkyLight($x, $y, $z, $data){ - try{ - $this->sections[$y >> 4]->setBlockSkyLight($x, $y & 0x0f, $z, $data); - $this->hasChanged = true; - }catch(ChunkException $e){ - $level = $this->getProvider(); - $this->setInternalSection($Y = $y >> 4, $level::createChunkSection($Y)); - $this->setBlockSkyLight($x, $y, $z, $data); - } - } - - public function getBlockLight($x, $y, $z){ - return $this->sections[$y >> 4]->getBlockLight($x, $y & 0x0f, $z); - } - - public function setBlockLight($x, $y, $z, $data){ - try{ - $this->sections[$y >> 4]->setBlockLight($x, $y & 0x0f, $z, $data); - $this->hasChanged = true; - }catch(ChunkException $e){ - $level = $this->getProvider(); - $this->setInternalSection($Y = $y >> 4, $level::createChunkSection($Y)); - $this->setBlockLight($x, $y, $z, $data); - } - } - - public function getBlockIdColumn($x, $z){ - $column = ""; - for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){ - $column .= $this->sections[$y]->getBlockIdColumn($x, $z); - } - - return $column; - } - - public function getBlockDataColumn($x, $z){ - $column = ""; - for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){ - $column .= $this->sections[$y]->getBlockDataColumn($x, $z); - } - - return $column; - } - - public function getBlockSkyLightColumn($x, $z){ - $column = ""; - for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){ - $column .= $this->sections[$y]->getBlockSkyLightColumn($x, $z); - } - - return $column; - } - - public function getBlockLightColumn($x, $z){ - $column = ""; - for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){ - $column .= $this->sections[$y]->getBlockLightColumn($x, $z); - } - - return $column; - } - - public function isSectionEmpty($fY){ - return $this->sections[(int) $fY] instanceof EmptyChunkSection; - } - - public function getSection($fY){ - return $this->sections[(int) $fY]; - } - - public function setSection($fY, ChunkSection $section){ - if(substr_count($section->getIdArray(), "\x00") === 4096 and substr_count($section->getDataArray(), "\x00") === 2048){ - $this->sections[(int) $fY] = new EmptyChunkSection($fY); - }else{ - $this->sections[(int) $fY] = $section; - } - $this->hasChanged = true; - } - - private function setInternalSection($fY, ChunkSection $section){ - $this->sections[(int) $fY] = $section; - $this->hasChanged = true; - } - - public function load($generate = true){ - return $this->getProvider() === null ? false : $this->getProvider()->getChunk($this->getX(), $this->getZ(), true) instanceof Chunk; - } - - public function getBlockIdArray(){ - $blocks = ""; - for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){ - $blocks .= $this->sections[$y]->getIdArray(); - } - - return $blocks; - } - - public function getBlockDataArray(){ - $data = ""; - for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){ - $data .= $this->sections[$y]->getDataArray(); - } - - return $data; - } - - public function getBlockSkyLightArray(){ - $skyLight = ""; - for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){ - $skyLight .= $this->sections[$y]->getSkyLightArray(); - } - - return $skyLight; - } - - public function getBlockLightArray(){ - $blockLight = ""; - for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){ - $blockLight .= $this->sections[$y]->getLightArray(); - } - - return $blockLight; - } - - /** - * @return ChunkSection[] - */ - public function getSections(){ - return $this->sections; - } - -} \ No newline at end of file diff --git a/src/devmine/levels/format/generic/BaseFullChunk.php b/src/devmine/levels/format/generic/BaseFullChunk.php deleted file mode 100644 index 3945238..0000000 --- a/src/devmine/levels/format/generic/BaseFullChunk.php +++ /dev/null @@ -1,447 +0,0 @@ -provider = $provider; - $this->x = (int) $x; - $this->z = (int) $z; - - $this->blocks = $blocks; - $this->data = $data; - $this->skyLight = $skyLight; - $this->blockLight = $blockLight; - - if(count($biomeColors) === 256){ - $this->biomeColors = $biomeColors; - }else{ - $this->biomeColors = array_fill(0, 256, 0); - } - - if(count($heightMap) === 256){ - $this->heightMap = $heightMap; - }else{ - $this->heightMap = array_fill(0, 256, 127); - } - - $this->extraData = $extraData; - - $this->NBTsolidentities = $solidentities; - $this->NBTentities = $entities; - } - - protected function checkOldBiomes($data){ - if(strlen($data) !== 256){ - return; - } - - for($x = 0; $x < 16; ++$x){ - for($z = 0; $z < 16; ++$z){ - $biome = Biome::getBiome(ord($data{($z << 4) + $x})); - $this->setBiomeId($x, $z, $biome->getId()); - $c = $biome->getColor(); - $this->setBiomeColor($x, $z, $c >> 16, ($c >> 8) & 0xff, $c & 0xff); - } - } - } - - public function initChunk(){ - if($this->getProvider() instanceof LevelProvider and !$this->isInit){ - $changed = false; - if($this->NBTentities !== null){ - $this->getProvider()->getLevel()->timings->syncChunkLoadEntitiesTimer->startTiming(); - foreach($this->NBTentities as $nbt){ - if($nbt instanceof CompoundTag){ - if(!isset($nbt->id)){ - $this->setChanged(); - continue; - } - - if(($nbt["Pos"][0] >> 4) !== $this->x or ($nbt["Pos"][2] >> 4) !== $this->z){ - $changed = true; - continue; //Fixes entities allocated in wrong chunks. - } - - if(($entity = Entity::createEntity($nbt["id"], $this, $nbt)) instanceof Entity){ - $entity->spawnToAll(); - }else{ - $changed = true; - continue; - } - } - } - $this->getProvider()->getLevel()->timings->syncChunkLoadEntitiesTimer->stopTiming(); - - $this->getProvider()->getLevel()->timings->syncChunkLoadsolidentityEntitiesTimer->startTiming(); - foreach($this->NBTsolidentities as $nbt){ - if($nbt instanceof CompoundTag){ - if(!isset($nbt->id)){ - $changed = true; - continue; - } - - if(($nbt["x"] >> 4) !== $this->x or ($nbt["z"] >> 4) !== $this->z){ - $changed = true; - continue; //Fixes solidentities allocated in wrong chunks. - } - - if(solidentity::createsolidentity($nbt["id"], $this, $nbt) === null){ - $changed = true; - continue; - } - } - } - - $this->getProvider()->getLevel()->timings->syncChunkLoadsolidentityEntitiesTimer->stopTiming(); - - $this->NBTentities = null; - $this->NBTsolidentities = null; - } - - $this->setChanged($changed); - - $this->isInit = true; - } - } - - public function getX(){ - return $this->x; - } - - public function getZ(){ - return $this->z; - } - - public function setX($x){ - $this->x = $x; - } - - public function setZ($z){ - $this->z = $z; - } - - /** - * @return LevelProvider - * - * @deprecated - */ - public function getLevel(){ - return $this->getProvider(); - } - - /** - * @return LevelProvider - */ - public function getProvider(){ - return $this->provider; - } - - public function setProvider(LevelProvider $provider){ - $this->provider = $provider; - } - - public function getBiomeId($x, $z){ - return ($this->biomeColors[($z << 4) + $x] & 0xFF000000) >> 24; - } - - public function setBiomeId($x, $z, $biomeId){ - $this->hasChanged = true; - $this->biomeColors[($z << 4) + $x] = ($this->biomeColors[($z << 4) + $x] & 0xFFFFFF) | ($biomeId << 24); - } - - public function getBiomeColor($x, $z){ - $color = $this->biomeColors[($z << 4) + $x] & 0xFFFFFF; - - return [$color >> 16, ($color >> 8) & 0xFF, $color & 0xFF]; - } - - public function setBiomeColor($x, $z, $R, $G, $B){ - $this->hasChanged = true; - $this->biomeColors[($z << 4) + $x] = ($this->biomeColors[($z << 4) + $x] & 0xFF000000) | (($R & 0xFF) << 16) | (($G & 0xFF) << 8) | ($B & 0xFF); - } - - public function getHeightMap($x, $z){ - return $this->heightMap[($z << 4) + $x]; - } - - public function setHeightMap($x, $z, $value){ - $this->heightMap[($z << 4) + $x] = $value; - } - - public function recalculateHeightMap(){ - for($z = 0; $z < 16; ++$z){ - for($x = 0; $x < 16; ++$x){ - $this->setHeightMap($x, $z, $this->getHighestBlockAt($x, $z, false)); - } - } - } - - public function getBlockExtraData($x, $y, $z){ - if(isset($this->extraData[$index = Level::chunkBlockHash($x, $y, $z)])){ - return $this->extraData[$index]; - } - - return 0; - } - - public function setBlockExtraData($x, $y, $z, $data){ - if($data === 0){ - unset($this->extraData[Level::chunkBlockHash($x, $y, $z)]); - }else{ - $this->extraData[Level::chunkBlockHash($x, $y, $z)] = $data; - } - - $this->setChanged(true); - } - - public function populateSkyLight(){ - for($z = 0; $z < 16; ++$z){ - for($x = 0; $x < 16; ++$x){ - $top = $this->getHeightMap($x, $z); - for($y = 127; $y > $top; --$y){ - $this->setBlockSkyLight($x, $y, $z, 15); - } - - for($y = $top; $y >= 0; --$y){ - if(Block::$solid[$this->getBlockId($x, $y, $z)]){ - break; - } - - $this->setBlockSkyLight($x, $y, $z, 15); - } - - $this->setHeightMap($x, $z, $this->getHighestBlockAt($x, $z, false)); - } - } - } - - public function getHighestBlockAt($x, $z, $cache = true){ - if($cache){ - $h = $this->getHeightMap($x, $z); - - if($h !== 0 and $h !== 127){ - return $h; - } - } - - $column = $this->getBlockIdColumn($x, $z); - for($y = 127; $y >= 0; --$y){ - if($column{$y} !== "\x00"){ - $this->setHeightMap($x, $z, $y); - return $y; - } - } - - return 0; - } - - public function addEntity(Entity $entity){ - $this->entities[$entity->getId()] = $entity; - if(!($entity instanceof Player) and $this->isInit){ - $this->hasChanged = true; - } - } - - public function removeEntity(Entity $entity){ - unset($this->entities[$entity->getId()]); - if(!($entity instanceof Player) and $this->isInit){ - $this->hasChanged = true; - } - } - - public function addsolidentity(solidentity $solidentity){ - $this->solidentities[$solidentity->getId()] = $solidentity; - if(isset($this->solidentityList[$index = (($solidentity->z & 0x0f) << 12) | (($solidentity->x & 0x0f) << 8) | ($solidentity->y & 0xff)]) and $this->solidentityList[$index] !== $solidentity){ - $this->solidentityList[$index]->close(); - } - $this->solidentityList[$index] = $solidentity; - if($this->isInit){ - $this->hasChanged = true; - } - } - - public function removesolidentity(solidentity $solidentity){ - unset($this->solidentities[$solidentity->getId()]); - unset($this->solidentityList[(($solidentity->z & 0x0f) << 12) | (($solidentity->x & 0x0f) << 8) | ($solidentity->y & 0xff)]); - if($this->isInit){ - $this->hasChanged = true; - } - } - - public function getEntities(){ - return $this->entities; - } - - public function getsolidentities(){ - return $this->solidentities; - } - - public function getBlockExtraDataArray(){ - return $this->extraData; - } - - public function getsolidentity($x, $y, $z){ - $index = ($z << 12) | ($x << 8) | $y; - return isset($this->solidentityList[$index]) ? $this->solidentityList[$index] : null; - } - - public function isLoaded(){ - return $this->getProvider() === null ? false : $this->getProvider()->isChunkLoaded($this->getX(), $this->getZ()); - } - - public function load($generate = true){ - return $this->getProvider() === null ? false : $this->getProvider()->getChunk($this->getX(), $this->getZ(), true) instanceof FullChunk; - } - - public function unload($save = true, $safe = true){ - $level = $this->getProvider(); - if($level === null){ - return true; - } - if($save === true and $this->hasChanged){ - $level->saveChunk($this->getX(), $this->getZ()); - } - if($safe === true){ - foreach($this->getEntities() as $entity){ - if($entity instanceof Player){ - return false; - } - } - } - - foreach($this->getEntities() as $entity){ - if($entity instanceof Player){ - continue; - } - $entity->close(); - } - foreach($this->getsolidentities() as $solidentity){ - $solidentity->close(); - } - $this->provider = null; - return true; - } - - public function getBlockIdArray(){ - return $this->blocks; - } - - public function getBlockDataArray(){ - return $this->data; - } - - public function getBlockSkyLightArray(){ - return $this->skyLight; - } - - public function getBlockLightArray(){ - return $this->blockLight; - } - - public function getBiomeIdArray(){ - $ids = ""; - foreach($this->biomeColors as $d){ - $ids .= chr(($d & 0xFF000000) >> 24); - } - return $ids; - } - - public function getBiomeColorArray(){ - return $this->biomeColors; - } - - public function getHeightMapArray(){ - return $this->heightMap; - } - - public function hasChanged(){ - return $this->hasChanged; - } - - public function setChanged($changed = true){ - $this->hasChanged = (bool) $changed; - } - - public static function fromFastBinary($data, LevelProvider $provider = null){ - return static::fromBinary($data, $provider); - } - - public function toFastBinary(){ - return $this->toBinary(); - } - - public function isLightPopulated(){ - return true; - } - - public function setLightPopulated($value = 1){ - - } - -} diff --git a/src/devmine/levels/format/generic/EmptyChunkSection.php b/src/devmine/levels/format/generic/EmptyChunkSection.php deleted file mode 100644 index ea69550..0000000 --- a/src/devmine/levels/format/generic/EmptyChunkSection.php +++ /dev/null @@ -1,101 +0,0 @@ -y = $y; - } - - final public function getY(){ - return $this->y; - } - - final public function getBlockId($x, $y, $z){ - return 0; - } - - final public function getBlockIdColumn($x, $z){ - return "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - } - - final public function getBlockDataColumn($x, $z){ - return "\x00\x00\x00\x00\x00\x00\x00\x00"; - } - - final public function getBlockSkyLightColumn($x, $z){ - return "\xff\xff\xff\xff\xff\xff\xff\xff"; - } - - final public function getBlockLightColumn($x, $z){ - return "\x00\x00\x00\x00\x00\x00\x00\x00"; - } - - final public function getFullBlock($x, $y, $z){ - return 0; - } - - final public function getBlock($x, $y, $z, &$id = null, &$meta = null){ - $id = 0; - $meta = 0; - } - - final public function setBlock($x, $y, $z, $id = null, $meta = null){ - throw new ChunkException("Tried to modify an empty Chunk"); - } - - public function getIdArray(){ - return str_repeat("\x00", 4096); - } - - public function getDataArray(){ - return str_repeat("\x00", 2048); - } - - public function getSkyLightArray(){ - return str_repeat("\xff", 2048); - } - - public function getLightArray(){ - return str_repeat("\x00", 2048); - } - - final public function setBlockId($x, $y, $z, $id){ - throw new ChunkException("Tried to modify an empty Chunk"); - } - - final public function getBlockData($x, $y, $z){ - return 0; - } - - final public function setBlockData($x, $y, $z, $data){ - throw new ChunkException("Tried to modify an empty Chunk"); - } - - final public function getBlockLight($x, $y, $z){ - return 0; - } - - final public function setBlockLight($x, $y, $z, $level){ - throw new ChunkException("Tried to modify an empty Chunk"); - } - - final public function getBlockSkyLight($x, $y, $z){ - return 15; - } - - final public function setBlockSkyLight($x, $y, $z, $level){ - throw new ChunkException("Tried to modify an empty Chunk"); - } -} \ No newline at end of file diff --git a/src/devmine/levels/format/mcregion/Chunk.php b/src/devmine/levels/format/mcregion/Chunk.php deleted file mode 100644 index 65b08d6..0000000 --- a/src/devmine/levels/format/mcregion/Chunk.php +++ /dev/null @@ -1,452 +0,0 @@ -provider = $level; - $this->nbt = new CompoundTag("Level", []); - return; - } - - $this->nbt = $nbt; - - if(isset($this->nbt->Entities) and $this->nbt->Entities instanceof ListTag){ - $this->nbt->Entities->setTagType(NBT::TAG_Compound); - }else{ - $this->nbt->Entities = new ListTag("Entities", []); - $this->nbt->Entities->setTagType(NBT::TAG_Compound); - } - - if(isset($this->nbt->solidentityEntities) and $this->nbt->solidentityEntities instanceof ListTag){ - $this->nbt->solidentityEntities->setTagType(NBT::TAG_Compound); - }else{ - $this->nbt->solidentityEntities = new ListTag("solidentityEntities", []); - $this->nbt->solidentityEntities->setTagType(NBT::TAG_Compound); - } - - if(isset($this->nbt->solidentityTicks) and $this->nbt->solidentityTicks instanceof ListTag){ - $this->nbt->solidentityTicks->setTagType(NBT::TAG_Compound); - }else{ - $this->nbt->solidentityTicks = new ListTag("solidentityTicks", []); - $this->nbt->solidentityTicks->setTagType(NBT::TAG_Compound); - } - - if(!isset($this->nbt->BiomeColors) or !($this->nbt->BiomeColors instanceof IntArrayTag)){ - $this->nbt->BiomeColors = new IntArrayTag("BiomeColors", array_fill(0, 256, 0)); - } - - if(!isset($this->nbt->HeightMap) or !($this->nbt->HeightMap instanceof IntArrayTag)){ - $this->nbt->HeightMap = new IntArrayTag("HeightMap", array_fill(0, 256, 0)); - } - - if(!isset($this->nbt->Blocks)){ - $this->nbt->Blocks = new ByteArrayTag("Blocks", str_repeat("\x00", 32768)); - } - - if(!isset($this->nbt->Data)){ - $this->nbt->Data = new ByteArrayTag("Data", $half = str_repeat("\x00", 16384)); - $this->nbt->SkyLight = new ByteArrayTag("SkyLight", $half); - $this->nbt->BlockLight = new ByteArrayTag("BlockLight", $half); - } - - $extraData = []; - - if(!isset($this->nbt->ExtraData) or !($this->nbt->ExtraData instanceof ByteArrayTag)){ - $this->nbt->ExtraData = new ByteArrayTag("ExtraData", Binary::writeInt(0)); - }else{ - $stream = new BinaryStream($this->nbt->ExtraData->getValue()); - $count = $stream->getInt(); - for($i = 0; $i < $count; ++$i){ - $key = $stream->getInt(); - $extraData[$key] = $stream->getShort(); - } - } - - parent::__construct($level, $this->nbt["xPos"], $this->nbt["zPos"], $this->nbt->Blocks->getValue(), $this->nbt->Data->getValue(), $this->nbt->SkyLight->getValue(), $this->nbt->BlockLight->getValue(), $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->solidentityEntities->getValue(), $extraData); - - if(isset($this->nbt->Biomes)){ - $this->checkOldBiomes($this->nbt->Biomes->getValue()); - unset($this->nbt->Biomes); - } - - unset($this->nbt->Blocks); - unset($this->nbt->Data); - unset($this->nbt->SkyLight); - unset($this->nbt->BlockLight); - unset($this->nbt->BiomeColors); - unset($this->nbt->HeightMap); - unset($this->nbt->Biomes); - } - - public function getBlockId($x, $y, $z){ - if(isset($this->blocks{($x << 11) | ($z << 7) | $y})) return ord($this->blocks{($x << 11) | ($z << 7) | $y}); - else return 0; - } - - public function setBlockId($x, $y, $z, $id){ - $this->blocks{($x << 11) | ($z << 7) | $y} = chr($id); - $this->hasChanged = true; - } - - public function getBlockData($x, $y, $z){ - $m = ord($this->data{($x << 10) | ($z << 6) | ($y >> 1)}); - if(($y & 1) === 0){ - return $m & 0x0F; - }else{ - return $m >> 4; - } - } - - public function setBlockData($x, $y, $z, $data){ - $i = ($x << 10) | ($z << 6) | ($y >> 1); - $old_m = ord($this->data{$i}); - if(($y & 1) === 0){ - $this->data{$i} = chr(($old_m & 0xf0) | ($data & 0x0f)); - }else{ - $this->data{$i} = chr((($data & 0x0f) << 4) | ($old_m & 0x0f)); - } - $this->hasChanged = true; - } - - public function getFullBlock($x, $y, $z){ - $i = ($x << 11) | ($z << 7) | $y; - if(($y & 1) === 0){ - return (ord($this->blocks{$i}) << 4) | (ord($this->data{$i >> 1}) & 0x0F); - }else{ - return (ord($this->blocks{$i}) << 4) | (ord($this->data{$i >> 1}) >> 4); - } - } - - public function getBlock($x, $y, $z, &$blockId, &$meta = null){ - $full = $this->getFullBlock($x, $y, $z); - $blockId = $full >> 4; - $meta = $full & 0x0f; - } - - public function setBlock($x, $y, $z, $blockId = null, $meta = null){ - $i = ($x << 11) | ($z << 7) | $y; - - $changed = false; - - if($blockId !== null){ - $blockId = chr($blockId); - if($this->blocks{$i} !== $blockId){ - $this->blocks{$i} = $blockId; - $changed = true; - } - } - - if($meta !== null){ - $i >>= 1; - $old_m = ord($this->data{$i}); - if(($y & 1) === 0){ - $this->data{$i} = chr(($old_m & 0xf0) | ($meta & 0x0f)); - if(($old_m & 0x0f) !== $meta){ - $changed = true; - } - }else{ - $this->data{$i} = chr((($meta & 0x0f) << 4) | ($old_m & 0x0f)); - if((($old_m & 0xf0) >> 4) !== $meta){ - $changed = true; - } - } - } - - if($changed){ - $this->hasChanged = true; - } - - return $changed; - } - - public function getBlockSkyLight($x, $y, $z){ - $sl = ord($this->skyLight{($x << 10) | ($z << 6) | ($y >> 1)}); - if(($y & 1) === 0){ - return $sl & 0x0F; - }else{ - return $sl >> 4; - } - } - - public function setBlockSkyLight($x, $y, $z, $level){ - $i = ($x << 10) | ($z << 6) | ($y >> 1); - $old_sl = ord($this->skyLight{$i}); - if(($y & 1) === 0){ - $this->skyLight{$i} = chr(($old_sl & 0xf0) | ($level & 0x0f)); - }else{ - $this->skyLight{$i} = chr((($level & 0x0f) << 4) | ($old_sl & 0x0f)); - } - $this->hasChanged = true; - } - - public function getBlockLight($x, $y, $z){ - $l = ord($this->blockLight{($x << 10) | ($z << 6) | ($y >> 1)}); - if(($y & 1) === 0){ - return $l & 0x0F; - }else{ - return $l >> 4; - } - } - - public function setBlockLight($x, $y, $z, $level){ - $i = ($x << 10) | ($z << 6) | ($y >> 1); - $old_l = ord($this->blockLight{$i}); - if(($y & 1) === 0){ - $this->blockLight{$i} = chr(($old_l & 0xf0) | ($level & 0x0f)); - }else{ - $this->blockLight{$i} = chr((($level & 0x0f) << 4) | ($old_l & 0x0f)); - } - $this->hasChanged = true; - } - - public function getBlockIdColumn($x, $z){ - return substr($this->blocks, ($x << 11) + ($z << 7), 128); - } - - public function getBlockDataColumn($x, $z){ - return substr($this->data, ($x << 10) + ($z << 6), 64); - } - - public function getBlockSkyLightColumn($x, $z){ - return substr($this->skyLight, ($x << 10) + ($z << 6), 64); - } - - public function getBlockLightColumn($x, $z){ - return substr($this->blockLight, ($x << 10) + ($z << 6), 64); - } - - public function isLightPopulated(){ - return $this->nbt["LightPopulated"] > 0; - } - - public function setLightPopulated($value = 1){ - $this->nbt->LightPopulated = new ByteTag("LightPopulated", $value ? 1 : 0); - $this->hasChanged = true; - } - - /** - * @return bool - */ - public function isPopulated(){ - return isset($this->nbt->TerrainPopulated) and $this->nbt->TerrainPopulated->getValue() > 0; - } - - /** - * @param int $value - */ - public function setPopulated($value = 1){ - $this->nbt->TerrainPopulated = new ByteTag("TerrainPopulated", $value ? 1 : 0); - $this->hasChanged = true; - } - - /** - * @return bool - */ - public function isGenerated(){ - if(isset($this->nbt->TerrainGenerated)){ - return $this->nbt->TerrainGenerated->getValue() > 0; - }elseif(isset($this->nbt->TerrainPopulated)){ - return $this->nbt->TerrainPopulated->getValue() > 0; - } - return false; - } - - /** - * @param int $value - */ - public function setGenerated($value = 1){ - $this->nbt->TerrainGenerated = new ByteTag("TerrainGenerated", (int) $value); - $this->hasChanged = true; - } - - /** - * @param string $data - * @param LevelProvider $provider - * - * @return Chunk - */ - public static function fromBinary($data, LevelProvider $provider = null){ - $nbt = new NBT(NBT::BIG_ENDIAN); - - try{ - $nbt->readCompressed($data, ZLIB_ENCODING_DEFLATE); - $chunk = $nbt->getData(); - - if(!isset($chunk->Level) or !($chunk->Level instanceof CompoundTag)){ - return null; - } - - return new Chunk($provider instanceof LevelProvider ? $provider : McRegion::class, $chunk->Level); - }catch(\Throwable $e){ - return null; - } - } - - public static function fromFastBinary($data, LevelProvider $provider = null){ - - try{ - $offset = 0; - - $chunk = new Chunk($provider instanceof LevelProvider ? $provider : McRegion::class, null); - $chunk->provider = $provider; - $chunk->x = Binary::readInt(substr($data, $offset, 4)); - $offset += 4; - $chunk->z = Binary::readInt(substr($data, $offset, 4)); - $offset += 4; - - $chunk->blocks = substr($data, $offset, 32768); - $offset += 32768; - $chunk->data = substr($data, $offset, 16384); - $offset += 16384; - $chunk->skyLight = substr($data, $offset, 16384); - $offset += 16384; - $chunk->blockLight = substr($data, $offset, 16384); - $offset += 16384; - - $chunk->heightMap = array_values(unpack("C*", substr($data, $offset, 256))); - $offset += 256; - $chunk->biomeColors = array_values(unpack("N*", substr($data, $offset, 1024))); - $offset += 1024; - - $flags = ord($data{$offset++}); - - $chunk->nbt->TerrainGenerated = new ByteTag("TerrainGenerated", $flags & 0b1); - $chunk->nbt->TerrainPopulated = new ByteTag("TerrainPopulated", ($flags >> 1) & 0b1); - $chunk->nbt->LightPopulated = new ByteTag("LightPopulated", ($flags >> 2) & 0b1); - - return $chunk; - }catch(\Throwable $e){ - return null; - } - } - - public function toFastBinary(){ - return - Binary::writeInt($this->x) . - Binary::writeInt($this->z) . - $this->getBlockIdArray() . - $this->getBlockDataArray() . - $this->getBlockSkyLightArray() . - $this->getBlockLightArray() . - pack("C*", ...$this->getHeightMapArray()) . - pack("N*", ...$this->getBiomeColorArray()) . - chr(($this->isLightPopulated() ? 1 << 2 : 0) + ($this->isPopulated() ? 1 << 1 : 0) + ($this->isGenerated() ? 1 : 0)); - } - - public function toBinary(){ - $nbt = clone $this->getNBT(); - - $nbt->xPos = new IntTag("xPos", $this->x); - $nbt->zPos = new IntTag("zPos", $this->z); - - if($this->isGenerated()){ - $nbt->Blocks = new ByteArrayTag("Blocks", $this->getBlockIdArray()); - $nbt->Data = new ByteArrayTag("Data", $this->getBlockDataArray()); - $nbt->SkyLight = new ByteArrayTag("SkyLight", $this->getBlockSkyLightArray()); - $nbt->BlockLight = new ByteArrayTag("BlockLight", $this->getBlockLightArray()); - - $nbt->BiomeColors = new IntArrayTag("BiomeColors", $this->getBiomeColorArray()); - - $nbt->HeightMap = new IntArrayTag("HeightMap", $this->getHeightMapArray()); - } - - $entities = []; - - foreach($this->getEntities() as $entity){ - if(!($entity instanceof Player) and !$entity->closed){ - $entity->saveNBT(); - $entities[] = $entity->namedtag; - } - } - - $nbt->Entities = new ListTag("Entities", $entities); - $nbt->Entities->setTagType(NBT::TAG_Compound); - - - $solidentities = []; - foreach($this->getsolidentities() as $solidentity){ - $solidentity->saveNBT(); - $solidentities[] = $solidentity->namedtag; - } - - $nbt->solidentityEntities = new ListTag("solidentityEntities", $solidentities); - $nbt->solidentityEntities->setTagType(NBT::TAG_Compound); - - $extraData = new BinaryStream(); - $extraData->putInt(count($this->getBlockExtraDataArray())); - foreach($this->getBlockExtraDataArray() as $key => $value){ - $extraData->putInt($key); - $extraData->putShort($value); - } - - $nbt->ExtraData = new ByteArrayTag("ExtraData", $extraData->getBuffer()); - - $writer = new NBT(NBT::BIG_ENDIAN); - $nbt->setName("Level"); - $writer->setData(new CompoundTag("", ["Level" => $nbt])); - - return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL); - } - - /** - * @return CompoundTag - */ - public function getNBT(){ - return $this->nbt; - } - - /** - * @param int $chunkX - * @param int $chunkZ - * @param LevelProvider $provider - * - * @return Chunk - */ - public static function getEmptyChunk($chunkX, $chunkZ, LevelProvider $provider = null){ - try{ - $chunk = new Chunk($provider instanceof LevelProvider ? $provider : McRegion::class, null); - $chunk->x = $chunkX; - $chunk->z = $chunkZ; - - $chunk->data = str_repeat("\x00", 16384); - $chunk->blocks = $chunk->data . $chunk->data; - $chunk->skyLight = str_repeat("\xff", 16384); - $chunk->blockLight = $chunk->data; - - $chunk->heightMap = array_fill(0, 256, 0); - $chunk->biomeColors = array_fill(0, 256, 0); - - $chunk->nbt->V = new ByteTag("V", 1); - $chunk->nbt->InhabitedTime = new LongTag("InhabitedTime", 0); - $chunk->nbt->TerrainGenerated = new ByteTag("TerrainGenerated", 0); - $chunk->nbt->TerrainPopulated = new ByteTag("TerrainPopulated", 0); - $chunk->nbt->LightPopulated = new ByteTag("LightPopulated", 0); - - return $chunk; - }catch(\Throwable $e){ - return null; - } - } -} \ No newline at end of file diff --git a/src/devmine/levels/format/mcregion/ChunkRequestTask.php b/src/devmine/levels/format/mcregion/ChunkRequestTask.php deleted file mode 100644 index 16182fd..0000000 --- a/src/devmine/levels/format/mcregion/ChunkRequestTask.php +++ /dev/null @@ -1,73 +0,0 @@ -levelId = $level->getId(); - - $this->chunk = $chunk->toFastBinary(); - $this->chunkX = $chunk->getX(); - $this->chunkZ = $chunk->getZ(); - - $solidentities = ""; - $nbt = new NBT(NBT::LITTLE_ENDIAN); - foreach($chunk->getsolidentities() as $solidentity){ - if($solidentity instanceof Spawnable){ - $nbt->setData($solidentity->getSpawnCompound()); - $solidentities .= $nbt->write(); - } - } - - $this->solidentities = $solidentities; - } - - public function onRun(){ - - $chunk = Chunk::fromFastBinary($this->chunk); - $extraData = new BinaryStream(); - $extraData->putLInt(count($chunk->getBlockExtraDataArray())); - foreach($chunk->getBlockExtraDataArray() as $key => $value){ - $extraData->putLInt($key); - $extraData->putLShort($value); - } - - $ordered = $chunk->getBlockIdArray() . - $chunk->getBlockDataArray() . - $chunk->getBlockSkyLightArray() . - $chunk->getBlockLightArray() . - pack("C*", ...$chunk->getHeightMapArray()) . - pack("N*", ...$chunk->getBiomeColorArray()) . - $extraData->getBuffer() . - $this->solidentities; - - $this->setResult($ordered, false); - } - - public function onCompletion(Server $server){ - $level = $server->getLevel($this->levelId); - if($level instanceof Level and $this->hasResult()){ - $level->chunkRequestCallback($this->chunkX, $this->chunkZ, $this->getResult()); - } - } - -} \ No newline at end of file diff --git a/src/devmine/levels/format/mcregion/McRegion.php b/src/devmine/levels/format/mcregion/McRegion.php deleted file mode 100644 index fca7823..0000000 --- a/src/devmine/levels/format/mcregion/McRegion.php +++ /dev/null @@ -1,315 +0,0 @@ - new ByteTag("hardcore", 0), - "initialized" => new ByteTag("initialized", 1), - "GameType" => new IntTag("GameType", 0), - "generatorVersion" => new IntTag("generatorVersion", 1), //2 in MCPE - "SpawnX" => new IntTag("SpawnX", 128), - "SpawnY" => new IntTag("SpawnY", 70), - "SpawnZ" => new IntTag("SpawnZ", 128), - "version" => new IntTag("version", 19133), - "DayTime" => new IntTag("DayTime", 0), - "LastPlayed" => new LongTag("LastPlayed", microtime(true) * 1000), - "RandomSeed" => new LongTag("RandomSeed", $seed), - "SizeOnDisk" => new LongTag("SizeOnDisk", 0), - "Time" => new LongTag("Time", 0), - "generatorName" => new StringTag("generatorName", Generator::getGeneratorName($generator)), - "generatorOptions" => new StringTag("generatorOptions", isset($options["preset"]) ? $options["preset"] : ""), - "LevelName" => new StringTag("LevelName", $name), - "GameRules" => new CompoundTag("GameRules", []) - ]); - $nbt = new NBT(NBT::BIG_ENDIAN); - $nbt->setData(new CompoundTag("", [ - "Data" => $levelData - ])); - $buffer = $nbt->writeCompressed(); - file_put_contents($path . "level.dat", $buffer); - } - - public static function getRegionIndex($chunkX, $chunkZ, &$x, &$z){ - $x = $chunkX >> 5; - $z = $chunkZ >> 5; - } - - public function requestChunkTask($x, $z){ - $chunk = $this->getChunk($x, $z, false); - if(!($chunk instanceof Chunk)){ - throw new ChunkException("Invalid Chunk sent"); - } - - if($this->getServer()->asyncChunkRequest){ - $task = new ChunkRequestTask($this->getLevel(), $chunk); - $this->getServer()->getScheduler()->scheduleAsyncTask($task); - }else{ - $solidentities = ""; - - if(count($chunk->getsolidentities()) > 0){ - $nbt = new NBT(NBT::LITTLE_ENDIAN); - $list = []; - foreach($chunk->getsolidentities() as $solidentity){ - if($solidentity instanceof Spawnable){ - $list[] = $solidentity->getSpawnCompound(); - } - } - $nbt->setData($list); - $solidentities = $nbt->write(); - } - - $extraData = new BinaryStream(); - $extraData->putLInt(count($chunk->getBlockExtraDataArray())); - foreach($chunk->getBlockExtraDataArray() as $key => $value){ - $extraData->putLInt($key); - $extraData->putLShort($value); - } - - $ordered = $chunk->getBlockIdArray() . - $chunk->getBlockDataArray() . - $chunk->getBlockSkyLightArray() . - $chunk->getBlockLightArray() . - pack("C*", ...$chunk->getHeightMapArray()) . - pack("N*", ...$chunk->getBiomeColorArray()) . - $extraData->getBuffer() . - $solidentities; - - $this->getLevel()->chunkRequestCallback($x, $z, $ordered); - } - - return null; - } - - public function unloadChunks(){ - foreach($this->chunks as $chunk){ - $this->unloadChunk($chunk->getX(), $chunk->getZ(), false); - } - $this->chunks = []; - } - - public function getGenerator(){ - return $this->levelData["generatorName"]; - } - - public function getGeneratorOptions(){ - return ["preset" => $this->levelData["generatorOptions"]]; - } - - public function getLoadedChunks(){ - return $this->chunks; - } - - public function isChunkLoaded($x, $z){ - return isset($this->chunks[Level::chunkHash($x, $z)]); - } - - public function saveChunks(){ - foreach($this->chunks as $chunk){ - $this->saveChunk($chunk->getX(), $chunk->getZ()); - } - } - - public function doGarbageCollection(){ - $limit = time() - 300; - foreach($this->regions as $index => $region){ - if($region->lastUsed <= $limit){ - $region->close(); - unset($this->regions[$index]); - } - } - } - - public function loadChunk($chunkX, $chunkZ, $create = false){ - $index = Level::chunkHash($chunkX, $chunkZ); - if(isset($this->chunks[$index])){ - return true; - } - $regionX = $regionZ = null; - self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); - $this->loadRegion($regionX, $regionZ); - $this->level->timings->syncChunkLoadDataTimer->startTiming(); - $chunk = $this->getRegion($regionX, $regionZ)->readChunk($chunkX - $regionX * 32, $chunkZ - $regionZ * 32); - if($chunk === null and $create){ - $chunk = $this->getEmptyChunk($chunkX, $chunkZ); - } - $this->level->timings->syncChunkLoadDataTimer->stopTiming(); - - if($chunk !== null){ - $this->chunks[$index] = $chunk; - return true; - }else{ - return false; - } - } - - public function getEmptyChunk($chunkX, $chunkZ){ - return Chunk::getEmptyChunk($chunkX, $chunkZ, $this); - } - - public function unloadChunk($x, $z, $safe = true){ - $chunk = isset($this->chunks[$index = Level::chunkHash($x, $z)]) ? $this->chunks[$index] : null; - if($chunk instanceof FullChunk and $chunk->unload(false, $safe)){ - unset($this->chunks[$index]); - return true; - } - - return false; - } - - public function saveChunk($x, $z){ - if($this->isChunkLoaded($x, $z)){ - $this->getRegion($x >> 5, $z >> 5)->writeChunk($this->getChunk($x, $z)); - - return true; - } - - return false; - } - - /** - * @param $x - * @param $z - * - * @return RegionLoader - */ - protected function getRegion($x, $z){ - return isset($this->regions[$index = Level::chunkHash($x, $z)]) ? $this->regions[$index] : null; - } - - /** - * @param int $chunkX - * @param int $chunkZ - * @param bool $create - * - * @return Chunk - */ - public function getChunk($chunkX, $chunkZ, $create = false){ - $index = Level::chunkHash($chunkX, $chunkZ); - if(isset($this->chunks[$index])){ - return $this->chunks[$index]; - }else{ - $this->loadChunk($chunkX, $chunkZ, $create); - - return isset($this->chunks[$index]) ? $this->chunks[$index] : null; - } - } - - public function setChunk($chunkX, $chunkZ, FullChunk $chunk){ - if(!($chunk instanceof Chunk)){ - throw new ChunkException("Invalid Chunk class"); - } - - $chunk->setProvider($this); - - self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); - $this->loadRegion($regionX, $regionZ); - - $chunk->setX($chunkX); - $chunk->setZ($chunkZ); - - - if(isset($this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)]) and $this->chunks[$index] !== $chunk){ - $this->unloadChunk($chunkX, $chunkZ, false); - } - - $this->chunks[$index] = $chunk; - } - - public static function createChunkSection($Y){ - return null; - } - - public function isChunkGenerated($chunkX, $chunkZ){ - if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) !== null){ - return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32) and $this->getChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32, true)->isGenerated(); - } - - return false; - } - - public function isChunkPopulated($chunkX, $chunkZ){ - $chunk = $this->getChunk($chunkX, $chunkZ); - if($chunk !== null){ - return $chunk->isPopulated(); - }else{ - return false; - } - } - - protected function loadRegion($x, $z){ - if(!isset($this->regions[$index = Level::chunkHash($x, $z)])){ - $this->regions[$index] = new RegionLoader($this, $x, $z); - } - } - - public function close(){ - $this->unloadChunks(); - foreach($this->regions as $index => $region){ - $region->close(); - unset($this->regions[$index]); - } - $this->level = null; - } -} \ No newline at end of file diff --git a/src/devmine/levels/generator/Void.php b/src/devmine/levels/generator/Void.php deleted file mode 100644 index 5643a94..0000000 --- a/src/devmine/levels/generator/Void.php +++ /dev/null @@ -1,91 +0,0 @@ -options = $settings; - } - - public function init(ChunkManager $level, Random $random){ - $this->level = $level; - $this->random = $random; - } - - public function generateChunk($chunkX, $chunkZ){ - $this->chunk = clone $this->level->getChunk($chunkX, $chunkZ); - $this->chunk->setGenerated(); - $c = Biome::getBiome(1)->getColor(); - $R = $c >> 16; - $G = ($c >> 8) & 0xff; - $B = $c & 0xff; - - for($Z = 0; $Z < 16; ++$Z){ - for($X = 0; $X < 16; ++$X){ - $this->chunk->setBiomeId($X, $Z, 1); - $this->chunk->setBiomeColor($X, $Z, $R, $G, $B); - for($y = 0; $y < 128; ++$y){ - $this->chunk->setBlockId($X, $y, $Z, Block::AIR); - } - } - } - - $this->chunk->setBlockId(8, 64, 8, Block::GRASS); - - $chunk = clone $this->chunk; - $chunk->setX($chunkX); - $chunk->setZ($chunkZ); - $this->level->setChunk($chunkX, $chunkZ, $chunk); - } - - public function populateChunk($chunkX, $chunkZ){ - - } - - public function getSpawn(){ - return new Vector3(128, 72, 128); - } - -} diff --git a/src/devmine/levels/generator/hell/HellBiome.php b/src/devmine/levels/generator/hell/HellBiome.php deleted file mode 100644 index 164ca77..0000000 --- a/src/devmine/levels/generator/hell/HellBiome.php +++ /dev/null @@ -1,18 +0,0 @@ -level->getSeed(); - $hash *= $hash + 223; - - $xNoise = $hash >> 20 & 3; - $zNoise = $hash >> 22 & 3; - - if($xNoise == 3){ - $xNoise = 1; - } - if($zNoise == 3){ - $zNoise = 1; - } - - return $this->selector->pickBiome($x + $xNoise - 1, $z + $zNoise - 1); - } - - - public function init(ChunkManager $level, Random $random){ - $this->level = $level; - $this->random = $random; - $this->random->setSeed($this->level->getSeed()); - $this->noiseSeaFloor = new Simplex($this->random, 1, 1 / 8, 1 / 64); - $this->noiseLand = new Simplex($this->random, 2, 1 / 8, 1 / 512); - $this->noiseMountains = new Simplex($this->random, 4, 1, 1 / 500); - $this->noiseBaseGround = new Simplex($this->random, 4, 1 / 4, 1 / 64); - $this->noiseRiver = new Simplex($this->random, 2, 1, 1 / 512); - $this->random->setSeed($this->level->getSeed()); - $this->selector = new BiomeSelector($this->random, function($temperature, $rainfall){ - if($rainfall < 0.25){ - if($temperature < 0.7){ - return Biome::OCEAN; - }elseif($temperature < 0.85){ - return Biome::RIVER; - }else{ - return Biome::SWAMP; - } - }elseif($rainfall < 0.60){ - if($temperature < 0.25){ - return Biome::ICE_PLAINS; - }elseif($temperature < 0.75){ - return Biome::PLAINS; - }else{ - return Biome::DESERT; - } - }elseif($rainfall < 0.80){ - if($temperature < 0.25){ - return Biome::TAIGA; - }elseif($temperature < 0.75){ - return Biome::FOREST; - }else{ - return Biome::BIRCH_FOREST; - } - }else{ - if($temperature < 0.25){ - return Biome::MOUNTAINS; - }elseif($temperature < 0.70){ - return Biome::SMALL_MOUNTAINS; - }else{ - return Biome::RIVER; - } - } - }, Biome::getBiome(Biome::OCEAN)); - - $this->heightOffset = $random->nextRange(-5, 3); - - $this->selector->addBiome(Biome::getBiome(Biome::OCEAN)); - $this->selector->addBiome(Biome::getBiome(Biome::PLAINS)); - $this->selector->addBiome(Biome::getBiome(Biome::DESERT)); - $this->selector->addBiome(Biome::getBiome(Biome::MOUNTAINS)); - $this->selector->addBiome(Biome::getBiome(Biome::FOREST)); - $this->selector->addBiome(Biome::getBiome(Biome::TAIGA)); - $this->selector->addBiome(Biome::getBiome(Biome::SWAMP)); - $this->selector->addBiome(Biome::getBiome(Biome::RIVER)); - $this->selector->addBiome(Biome::getBiome(Biome::ICE_PLAINS)); - $this->selector->addBiome(Biome::getBiome(Biome::SMALL_MOUNTAINS)); - $this->selector->addBiome(Biome::getBiome(Biome::BIRCH_FOREST)); - - $this->selector->recalculate(); - - $cover = new GroundCover(); - $this->generationPopulators[] = $cover;; - - $caves = new Caves(); - $this->populators[] = $caves; - - $ores = new Ore(); - $ores->setOreTypes([ - new OreType(new CoalOre(), 20, 16, 0, 128), - new OreType(new IronOre(), 20, 8, 0, 64), - new OreType(new RedstoneOre(), 8, 7, 0, 16), - new OreType(new LapisOre(), 1, 6, 0, 32), - new OreType(new GoldOre(), 2, 8, 0, 32), - new OreType(new DiamondOre(), 1, 7, 0, 16), - new OreType(new Dirt(), 20, 32, 0, 128), - new OreType(new Gravel(), 10, 16, 0, 128) - ]); - $this->populators[] = $ores; - } - - - public function generateChunk($chunkX, $chunkZ){ - $this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed()); - - $seaFloorNoise = Generator::getFastNoise2D($this->noiseSeaFloor, 16, 16, 4, $chunkX * 16, 0, $chunkZ * 16); - $landNoise = Generator::getFastNoise2D($this->noiseLand, 16, 16, 4, $chunkX * 16, 0, $chunkZ * 16); - $mountainNoise = Generator::getFastNoise2D($this->noiseMountains, 16, 16, 4, $chunkX * 16, 0, $chunkZ * 16); - $baseNoise = Generator::getFastNoise2D($this->noiseBaseGround, 16, 16, 4, $chunkX * 16, 0, $chunkZ * 16); - $riverNoise = Generator::getFastNoise2D($this->noiseRiver, 16, 16, 4, $chunkX * 16, 0, $chunkZ * 16); - - $chunk = $this->level->getChunk($chunkX, $chunkZ); - - for($genx = 0; $genx < 16; $genx++){ - for($genz = 0; $genz < 16; $genz++){ - $canBaseGround = false; - $canRiver = true; - - //using a quadratic function which smooth the world - //y = (2.956x)^2 - 0.6, (0 <= x <= 2) - $landHeightNoise = $landNoise[$genx][$genz] + 1; - $landHeightNoise *= 2.956; - $landHeightNoise = $landHeightNoise * $landHeightNoise; - $landHeightNoise = $landHeightNoise - 0.6; - $landHeightNoise = $landHeightNoise > 0 ? $landHeightNoise : 0; - - //generate mountains - $mountainHeightGenerate = $mountainNoise[$genx][$genz] - 0.2; - $mountainHeightGenerate = $mountainHeightGenerate > 0 ? $mountainHeightGenerate : 0; - $mountainGenerate = (int) ($this->mountainHeight * $mountainHeightGenerate); - - $landHeightGenerate = (int) ($this->landHeightRange * $landHeightNoise); - if($landHeightGenerate > $this->landHeightRange){ - if($landHeightGenerate > $this->landHeightRange){ - $canBaseGround = true; - } - $landHeightGenerate = $this->landHeightRange; - } - - $genyHeight = $this->seaFloorHeight + $landHeightGenerate; - $genyHeight += $mountainGenerate; - - //prepare for generate ocean, desert, and land - if($genyHeight < $this->beathStartHeight){ - if($genyHeight < $this->beathStartHeight - 5){ - $genyHeight += (int) ($this->seaFloorGenerateRange * $seaFloorNoise[$genx][$genz]); - } - $biome = Biome::getBiome(Biome::OCEAN); - if($genyHeight < $this->seaFloorHeight - $this->seaFloorGenerateRange){ - $genyHeight = $this->seaFloorHeight; - } - $canRiver = false; - }else if($genyHeight <= $this->beathStopHeight && $genyHeight >= $this->beathStartHeight){ - //todo: there is no beach biome, use desert temporarily - $biome = Biome::getBiome(Biome::DESERT); - }else{ - $biome = $this->pickBiome($chunkX * 16 + $genx, $chunkZ * 16 + $genz); - if($canBaseGround){ - $baseGroundHeight = (int) ($this->landHeightRange * $landHeightNoise) - $this->landHeightRange; - $baseGroundHeight2 = (int) ($this->basegroundHeight * ($baseNoise[$genx][$genz] + 1)); - if($baseGroundHeight2 > $baseGroundHeight) $baseGroundHeight2 = $baseGroundHeight; - if($baseGroundHeight2 > $mountainGenerate) - $baseGroundHeight2 = $baseGroundHeight2 - $mountainGenerate; - else $baseGroundHeight2 = 0; - $genyHeight += $baseGroundHeight2; - } - } - if($canRiver && $genyHeight <= $this->seaHeight - 5){ - $canRiver = false; - } - //generate river - if($canRiver){ - $riverGenerate = $riverNoise[$genx][$genz]; - if($riverGenerate > -0.25 && $riverGenerate < 0.25){ - $riverGenerate = $riverGenerate > 0 ? $riverGenerate : -$riverGenerate; - $riverGenerate = 0.25 - $riverGenerate; - //y=x^2 * 4 - 0.0000001 - $riverGenerate = $riverGenerate * $riverGenerate * 4; - //smooth again - $riverGenerate = $riverGenerate - 0.0000001; - $riverGenerate = $riverGenerate > 0 ? $riverGenerate : 0; - $genyHeight -= $riverGenerate * 64; - if($genyHeight < $this->seaHeight){ - $biome = Biome::getBiome(Biome::RIVER); - //to generate river floor - if($genyHeight <= $this->seaHeight - 8){ - $genyHeight1 = $this->seaHeight - 9 + (int) ($this->basegroundHeight * ($baseNoise[$genx][$genz] + 1)); - $genyHeight2 = $genyHeight < $this->seaHeight - 7 ? $this->seaHeight - 7 : $genyHeight; - $genyHeight = $genyHeight1 > $genyHeight2 ? $genyHeight1 : $genyHeight2; - } - } - } - } - $chunk->setBiomeId($genx, $genz, $biome->getId()); - //biome color - //todo: smooth chunk color - $biomeColor = $biome->getColor(); - $chunk->setBiomeColor($genx, $genz, ($biomeColor >> 16), ($biomeColor >> 8) & 0xff, ($biomeColor & 0xff)); - //generating - $generateHeight = $genyHeight > $this->seaHeight ? $genyHeight : $this->seaHeight; - for($geny = 0; $geny <= $generateHeight; $geny++){ - if($geny <= $this->bedrockDepth && ($geny == 0 or $this->random->nextRange(1, 5) == 1)){ - $chunk->setBlockId($genx, $geny, $genz, Block::BEDROCK); - }elseif($geny > $genyHeight){ - if(($biome->getId() == Biome::ICE_PLAINS or $biome->getId() == Biome::TAIGA) and $geny == $this->seaHeight){ - $chunk->setBlockId($genx, $geny, $genz, Block::ICE); - }else{ - $chunk->setBlockId($genx, $geny, $genz, Block::STILL_WATER); - } - }else{ - $chunk->setBlockId($genx, $geny, $genz, Block::STONE); - } - } - } - } - - //populator chunk - foreach($this->generationPopulators as $populator){ - $populator->populate($this->level, $chunkX, $chunkZ, $this->random); - } - - } - - - public function populateChunk($chunkX, $chunkZ){ - $this->random->setSeed(0xdeadbeef ^ ($chunkX << 8) ^ $chunkZ ^ $this->level->getSeed()); - foreach($this->populators as $populator){ - $populator->populate($this->level, $chunkX, $chunkZ, $this->random); - } - - $chunk = $this->level->getChunk($chunkX, $chunkZ); - $biome = Biome::getBiome($chunk->getBiomeId(7, 7)); - $biome->populateChunk($this->level, $chunkX, $chunkZ, $this->random); - } - - public function getSpawn(){ - return new Vector3(127.5, 128, 127.5); - } -} diff --git a/src/devmine/levels/generator/normal/biome/NormalBiome.php b/src/devmine/levels/generator/normal/biome/NormalBiome.php deleted file mode 100644 index 60d4c04..0000000 --- a/src/devmine/levels/generator/normal/biome/NormalBiome.php +++ /dev/null @@ -1,14 +0,0 @@ -grassColor; - } -} diff --git a/src/devmine/levels/generator/normal/biome/OceanBiome.php b/src/devmine/levels/generator/normal/biome/OceanBiome.php deleted file mode 100644 index 6ead842..0000000 --- a/src/devmine/levels/generator/normal/biome/OceanBiome.php +++ /dev/null @@ -1,32 +0,0 @@ -setBaseAmount(6); - $tallGrass = new TallGrass(); - $tallGrass->setBaseAmount(5); - - $this->addPopulator($sugarcane); - $this->addPopulator($tallGrass); - - $this->setElevation(46, 68); - - $this->temperature = 0.5; - $this->rainfall = 0.5; - } - - public function getName() : string{ - return "Ocean"; - } -} diff --git a/src/devmine/levels/generator/normal/biome/PlainBiome.php b/src/devmine/levels/generator/normal/biome/PlainBiome.php deleted file mode 100644 index cf7cd6e..0000000 --- a/src/devmine/levels/generator/normal/biome/PlainBiome.php +++ /dev/null @@ -1,55 +0,0 @@ -setBaseAmount(6); - $tallGrass = new TallGrass(); - $tallGrass->setBaseAmount(25); - $waterPit = new WaterPit(); - $waterPit->setBaseAmount(9999); - $lilyPad = new LilyPad(); - $lilyPad->setBaseAmount(8); - - $flower = new Flower(); - $flower->setBaseAmount(2); - $flower->addType([Block::DANDELION, 0]); - $flower->addType([Block::RED_FLOWER, FlowerBlock::TYPE_POPPY]); - $flower->addType([Block::RED_FLOWER, FlowerBlock::TYPE_AZURE_BLUET]); - $flower->addType([Block::RED_FLOWER, FlowerBlock::TYPE_RED_TULIP]); - $flower->addType([Block::RED_FLOWER, FlowerBlock::TYPE_ORANGE_TULIP]); - $flower->addType([Block::RED_FLOWER, FlowerBlock::TYPE_WHITE_TULIP]); - $flower->addType([Block::RED_FLOWER, FlowerBlock::TYPE_PINK_TULIP]); - $flower->addType([Block::RED_FLOWER, FlowerBlock::TYPE_OXEYE_DAISY]); - - $this->addPopulator($sugarcane); - $this->addPopulator($tallGrass); - $this->addPopulator($flower); - $this->addPopulator($waterPit); - $this->addPopulator($lilyPad); - - $this->setElevation(61, 68); - - $this->temperature = 0.8; - $this->rainfall = 0.4; - } - - public function getName() : string{ - return "Plains"; - } -} diff --git a/src/devmine/levels/generator/normal/biome/RiverBiome.php b/src/devmine/levels/generator/normal/biome/RiverBiome.php deleted file mode 100644 index 89f7f68..0000000 --- a/src/devmine/levels/generator/normal/biome/RiverBiome.php +++ /dev/null @@ -1,32 +0,0 @@ -setBaseAmount(6); - $tallGrass = new TallGrass(); - $tallGrass->setBaseAmount(5); - - $this->addPopulator($sugarcane); - $this->addPopulator($tallGrass); - - $this->setElevation(58, 62); - - $this->temperature = 0.5; - $this->rainfall = 0.7; - } - - public function getName() : string{ - return "River"; - } -} diff --git a/src/devmine/levels/generator/normal/biome/SandyBiome.php b/src/devmine/levels/generator/normal/biome/SandyBiome.php deleted file mode 100644 index 7c5f881..0000000 --- a/src/devmine/levels/generator/normal/biome/SandyBiome.php +++ /dev/null @@ -1,71 +0,0 @@ -setBaseAmount(6); - $deadBush = new DeadBush(); - $deadBush->setBaseAmount(2); - - $this->addPopulator($cactus); - $this->addPopulator($deadBush); - - $this->setElevation(63, 81); - - $this->temperature = 0.05; - $this->rainfall = 0.8; - $this->setGroundCover([ - Block::get(Block::SAND, 0), - Block::get(Block::SAND, 0), - Block::get(Block::SAND, 0), - Block::get(Block::SAND, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - Block::get(Block::SANDSTONE, 0), - ]); - } - - public function getName() : string{ - return "Sandy"; - } -} diff --git a/src/devmine/levels/generator/normal/biome/SwampBiome.php b/src/devmine/levels/generator/normal/biome/SwampBiome.php deleted file mode 100644 index 167ec5f..0000000 --- a/src/devmine/levels/generator/normal/biome/SwampBiome.php +++ /dev/null @@ -1,40 +0,0 @@ -setBaseAmount(8); - $flower->addType([Block::RED_FLOWER, FlowerBlock::TYPE_BLUE_ORCHID]); - - $this->addPopulator($flower); - - $lilypad = new LilyPad(); - $lilypad->setBaseAmount(4); - $this->addPopulator($lilypad); - - $this->setElevation(62, 63); - - $this->temperature = 0.8; - $this->rainfall = 0.9; - } - - public function getName() : string{ - return "Swamp"; - } - - public function getColor(){ - return 0x6a7039; - } -} \ No newline at end of file diff --git a/src/devmine/levels/generator/normal/biome/TaigaBiome.php b/src/devmine/levels/generator/normal/biome/TaigaBiome.php deleted file mode 100644 index 62e11c7..0000000 --- a/src/devmine/levels/generator/normal/biome/TaigaBiome.php +++ /dev/null @@ -1,43 +0,0 @@ -setBaseAmount(10); - $this->addPopulator($trees); - - $mossStone = new MossStone(); - $mossStone->setBaseAmount(1); - - $this->addPopulator($mossStone); - - $this->setElevation(63, 81); - - $this->temperature = 0.05; - $this->rainfall = 0.8; - - $this->setGroundCover([ - Block::get(Block::PODZOL, 0), - Block::get(Block::PODZOL, 0), - Block::get(Block::MOSS_STONE, 0), - Block::get(Block::MOSS_STONE, 0), - Block::get(Block::MOSS_STONE, 0), - ]); - } - - public function getName() : string{ - return "Taiga"; - } -} diff --git a/src/devmine/levels/generator/normal/biome/WateryBiome.php b/src/devmine/levels/generator/normal/biome/WateryBiome.php deleted file mode 100644 index 3775563..0000000 --- a/src/devmine/levels/generator/normal/biome/WateryBiome.php +++ /dev/null @@ -1,9 +0,0 @@ -trunkBlock = Block::WOOD2; - $this->leafBlock = Block::LEAVES2; - $this->leafType = Leaves2::ACACIA; - $this->type = Wood2::ACACIA; - $this->treeHeight = 8; - } - - /*public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ - }*/ - //TODO: rewrite -} \ No newline at end of file diff --git a/src/devmine/levels/generator/object/BigTree.php b/src/devmine/levels/generator/object/BigTree.php deleted file mode 100644 index 3efab57..0000000 --- a/src/devmine/levels/generator/object/BigTree.php +++ /dev/null @@ -1,184 +0,0 @@ - true, - Block::LEAVES => true, - Block::SAPLING => true - ]; - - /** @var Random */ - private $random; - private $trunkHeightMultiplier = 0.618; - private $trunkHeight; - private $leafAmount = 1; - private $leafDistanceLimit = 5; - private $widthScale = 1; - private $branchSlope = 0.381; - - private $totalHeight; - private $baseHeight = 5; - - public function canPlaceObject(ChunkManager $level, $x, $y, $z, Random $random){ - if(!parent::canPlaceObject($level, $x, $y, $z, $random) or $level->getBlockIdAt($x, $y, $z) == Block::WATER or $level->getBlockIdAt($x, $y, $z) == Block::STILL_WATER){ - return false; - } - $base = new Vector3($x, $y, $z); - $this->totalHeight = $this->baseHeight + $random->nextBoundedInt(12); - $availableSpace = $this->getAvailableBlockSpace($level, $base, $base->add(0, $this->totalHeight - 1, 0)); - if($availableSpace > $this->baseHeight or $availableSpace == -1){ - if($availableSpace != -1){ - $this->totalHeight = $availableSpace; - } - return true; - } - return false; - } - - public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ - $this->random = $random; - $this->trunkHeight = (int) ($this->totalHeight * $this->trunkHeightMultiplier); - $leaves = $this->getLeafGroupPoints($level, $x, $y, $z); - foreach($leaves as $leaf){ - /** @var Vector3 $leafGroup */ - $leafGroup = $leaf[0]; - $groupX = $leafGroup->getX(); - $groupY = $leafGroup->getY(); - $groupZ = $leafGroup->getZ(); - for($yy = $groupY; $yy < $groupY + $this->leafDistanceLimit; ++$yy){ - $this->generateGroupLayer($level, $groupX, $yy, $groupZ, $this->getLeafGroupLayerSize($yy - $groupY)); - } - } - $trunk = new VectorIterator($level, new Vector3($x, $y -1, $z), new Vector3($x, $y + $this->trunkHeight, $z)); - while($trunk->valid()){ - $trunk->next(); - $pos = $trunk->current(); - $level->setBlockIdAt($pos->x, $pos->y, $pos->z, Block::LOG); - } - $this->generateBranches($level, $x, $y, $z, $leaves); - } - - private function getLeafGroupPoints(ChunkManager $level, $x, $y, $z){ - $amount = $this->leafAmount * $this->totalHeight / 13; - $groupsPerLayer = (int) (1.382 + $amount * $amount); - - if($groupsPerLayer == 0){ - $groupsPerLayer = 1; - } - - $trunkTopY = $y + $this->trunkHeight; - $groups = []; - $groupY = $y + $this->totalHeight - $this->leafDistanceLimit; - $groups[] = [new Vector3($x, $groupY, $z), $trunkTopY]; - - for($currentLayer = (int) ($this->totalHeight - $this->leafDistanceLimit); $currentLayer >= 0; $currentLayer--){ - $layerSize = $this->getRoughLayerSize($currentLayer); - - if($layerSize < 0){ - $groupY--; - continue; - } - - for($count = 0; $count < $groupsPerLayer; $count++){ - $scale = $this->widthScale * $layerSize * ($this->random->nextFloat() + 0.328); - $randomOffset = Vector2::createRandomDirection($this->random)->multiply($scale); - $groupX = (int) ($randomOffset->getX() + $x + 0.5); - $groupZ = (int) ($randomOffset->getY() + $z + 0.5); - $group = new Vector3($groupX, $groupY, $groupZ); - if($this->getAvailableBlockSpace($level, $group, $group->add(0, $this->leafDistanceLimit, 0)) != -1){ - continue; - } - $xOff = (int) ($x - $groupX); - $zOff = (int) ($z - $groupZ); - $horizontalDistanceToTrunk = sqrt($xOff * $xOff + $zOff * $zOff); - $verticalDistanceToTrunk = $horizontalDistanceToTrunk * $this->branchSlope; - $yDiff = (int) ($groupY - $verticalDistanceToTrunk); - if($yDiff > $trunkTopY){ - $base = $trunkTopY; - }else{ - $base = $yDiff; - } - if($this->getAvailableBlockSpace($level, new Vector3($x, $base, $z), $group) == -1){ - $groups[] = [$group, $base]; - } - } - $groupY--; - } - return $groups; - } - - private function getLeafGroupLayerSize(int $y){ - if($y >= 0 and $y < $this->leafDistanceLimit){ - return (int) (($y != ($this->leafDistanceLimit - 1)) ? 3 : 2); - } - return -1; - } - - private function generateGroupLayer(ChunkManager $level, int $x, int $y, int $z, int $size){ - for($xx = $x - $size; $xx <= $x + $size; $xx++){ - for($zz = $z - $size; $zz <= $z + $size; $zz++){ - $sizeX = abs($x - $xx) + 0.5; - $sizeZ = abs($z - $zz) + 0.5; - if(($sizeX * $sizeX + $sizeZ * $sizeZ) <= ($size * $size)){ - if(isset($this->overridable[$level->getBlockIdAt($xx, $y, $zz)])){ - $level->setBlockIdAt($xx, $y, $zz, Block::LEAVES); - } - } - } - } - } - - private function getRoughLayerSize(int $layer) : float { - $halfHeight = $this->totalHeight / 2; - if($layer < ($this->totalHeight / 3)){ - return -1; - }elseif($layer == $halfHeight){ - return $halfHeight / 4; - }elseif($layer >= $this->totalHeight or $layer <= 0){ - return 0; - }else{ - return sqrt($halfHeight * $halfHeight - ($layer - $halfHeight) * ($layer - $halfHeight)) / 2; - } - } - - private function generateBranches(ChunkManager $level, int $x, int $y, int $z, array $groups){ - foreach($groups as $group){ - $baseY = $group[1]; - if(($baseY - $y) >= ($this->totalHeight * 0.2)){ - $base = new Vector3($x, $baseY, $z); - $branch = new VectorIterator($level, $base, $group[0]); - while($branch->valid()){ - $branch->next(); - $pos = $branch->current(); - $level->setBlockIdAt((int) $pos->x, (int) $pos->y, (int) $pos->z, Block::LOG); - $level->updateBlockLight((int) $pos->x, (int) $pos->y, (int) $pos->z); - } - } - } - } - - private function getAvailableBlockSpace(ChunkManager $level, Vector3 $from, Vector3 $to){ - $count = 0; - $iter = new VectorIterator($level, $from, $to); - while($iter->valid()){ - $iter->next(); - $pos = $iter->current(); - if(!isset($this->overridable[$level->getBlockIdAt($pos->x, $pos->y, $pos->z)])){ - return $count; - } - $count++; - } - return -1; - } -} \ No newline at end of file diff --git a/src/devmine/levels/generator/object/DarkOakTree.php b/src/devmine/levels/generator/object/DarkOakTree.php deleted file mode 100644 index 8873125..0000000 --- a/src/devmine/levels/generator/object/DarkOakTree.php +++ /dev/null @@ -1,19 +0,0 @@ -trunkBlock = Block::WOOD2; - $this->leafBlock = Block::LEAVES2; - $this->leafType = Leaves2::DARK_OAK; - $this->type = Wood2::DARK_OAK; - $this->treeHeight = 8; - } -} \ No newline at end of file diff --git a/src/devmine/levels/generator/object/NetherOreTop.php b/src/devmine/levels/generator/object/NetherOreTop.php deleted file mode 100644 index e0172a8..0000000 --- a/src/devmine/levels/generator/object/NetherOreTop.php +++ /dev/null @@ -1,82 +0,0 @@ -type = $type; - $this->random = $random; - } - - public function getType(){ - return $this->type; - } - - public function canPlaceObject(ChunkManager $level, $x, $y, $z){ - return ($level->getBlockIdAt($x, $y, $z) === 0); - } - - public function placeObject(ChunkManager $level, $x, $y, $z){ - $clusterSize = (int) $this->type->clusterSize; - $angle = $this->random->nextFloat() * M_PI; - $offset = VectorMath::getDirection2D($angle)->multiply($clusterSize)->divide(8); - $x1 = $x + 8 + $offset->x; - $x2 = $x + 8 - $offset->x; - $z1 = $z + 8 + $offset->y; - $z2 = $z + 8 - $offset->y; - $y1 = $y + $this->random->nextBoundedInt(3) + 2; - $y2 = $y + $this->random->nextBoundedInt(3) + 2; - - for($count = 0; $count <= $clusterSize; ++$count){ - $seedX = $x1 + ($x2 - $x1) * $count / $clusterSize; - $seedY = $y1 + ($y2 - $y1) * $count / $clusterSize; - $seedZ = $z1 + ($z2 - $z1) * $count / $clusterSize; - $size = ((sin($count * (M_PI / $clusterSize)) + 1) * $this->random->nextFloat() * $clusterSize / 16 + 1) / 2; - - $startX = (int) ($seedX - $size); - $startY = (int) ($seedY - $size); - $startZ = (int) ($seedZ - $size); - $endX = (int) ($seedX + $size); - $endY = (int) ($seedY + $size); - $endZ = (int) ($seedZ + $size); - //echo "ORE: $startX, $startY, $startZ,, $endX, $endY, $endZ\n"; - for($x = $startX; $x <= $endX; ++$x){ - $sizeX = ($x + 0.5 - $seedX) / $size; - $sizeX *= $sizeX; - - if($sizeX < 1){ - for($y = $startY; $y <= $endY; ++$y){ - $sizeY = ($y + 0.5 - $seedY) / $size; - $sizeY *= $sizeY; - - if($y > 0 and ($sizeX + $sizeY) < 1){ - for($z = $startZ; $z <= $endZ; ++$z){ - $sizeZ = ($z + 0.5 - $seedZ) / $size; - $sizeZ *= $sizeZ; - - if(($sizeX + $sizeY + $sizeZ) < 1 and $level->getBlockIdAt($x, $y, $z) === 0){ - $level->setBlockIdAt($x, $y, $z, $this->type->material->getId()); - if($this->type->material->getDamage() !== 0){ - $level->setBlockDataAt($x, $y, $z, $this->type->material->getDamage()); - } - $level->updateBlockLight($x, $y, $z); - //echo "Placed to $x, $y, $z\n"; - } - } - } - } - } - } - } - } - -} \ No newline at end of file diff --git a/src/devmine/levels/generator/object/Ore.php b/src/devmine/levels/generator/object/Ore.php deleted file mode 100644 index be7e887..0000000 --- a/src/devmine/levels/generator/object/Ore.php +++ /dev/null @@ -1,79 +0,0 @@ -type = $type; - $this->random = $random; - } - - public function getType(){ - return $this->type; - } - - public function canPlaceObject(ChunkManager $level, $x, $y, $z){ - return (($level->getBlockIdAt($x, $y, $z) === 1) or ($level->getBlockIdAt($x, $y, $z) === 87)); - } - - public function placeObject(ChunkManager $level, $x, $y, $z){ - $clusterSize = (int) $this->type->clusterSize; - $angle = $this->random->nextFloat() * M_PI; - $offset = VectorMath::getDirection2D($angle)->multiply($clusterSize)->divide(8); - $x1 = $x + 8 + $offset->x; - $x2 = $x + 8 - $offset->x; - $z1 = $z + 8 + $offset->y; - $z2 = $z + 8 - $offset->y; - $y1 = $y + $this->random->nextBoundedInt(3) + 2; - $y2 = $y + $this->random->nextBoundedInt(3) + 2; - for($count = 0; $count <= $clusterSize; ++$count){ - $seedX = $x1 + ($x2 - $x1) * $count / $clusterSize; - $seedY = $y1 + ($y2 - $y1) * $count / $clusterSize; - $seedZ = $z1 + ($z2 - $z1) * $count / $clusterSize; - $size = ((sin($count * (M_PI / $clusterSize)) + 1) * $this->random->nextFloat() * $clusterSize / 16 + 1) / 2; - - $startX = (int) ($seedX - $size); - $startY = (int) ($seedY - $size); - $startZ = (int) ($seedZ - $size); - $endX = (int) ($seedX + $size); - $endY = (int) ($seedY + $size); - $endZ = (int) ($seedZ + $size); - - for($x = $startX; $x <= $endX; ++$x){ - $sizeX = ($x + 0.5 - $seedX) / $size; - $sizeX *= $sizeX; - - if($sizeX < 1){ - for($y = $startY; $y <= $endY; ++$y){ - $sizeY = ($y + 0.5 - $seedY) / $size; - $sizeY *= $sizeY; - - if($y > 0 and ($sizeX + $sizeY) < 1){ - for($z = $startZ; $z <= $endZ; ++$z){ - $sizeZ = ($z + 0.5 - $seedZ) / $size; - $sizeZ *= $sizeZ; - - if(($sizeX + $sizeY + $sizeZ) < 1 and (($level->getBlockIdAt($x, $y, $z) === 1) or ($level->getBlockIdAt($x, $y, $z) === 87)) ){ - $level->setBlockIdAt($x, $y, $z, $this->type->material->getId()); - if($this->type->material->getDamage() !== 0){ - $level->setBlockDataAt($x, $y, $z, $this->type->material->getDamage()); - } - } - } - } - } - } - } - } - } - -} \ No newline at end of file diff --git a/src/devmine/levels/generator/populator/Cactus.php b/src/devmine/levels/generator/populator/Cactus.php deleted file mode 100644 index a08e8e6..0000000 --- a/src/devmine/levels/generator/populator/Cactus.php +++ /dev/null @@ -1,65 +0,0 @@ -randomAmount = $amount; - } - - public function setBaseAmount($amount){ - $this->baseAmount = $amount; - } - - public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ - $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; - for($i = 0; $i < $amount; ++$i){ - $x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15); - $z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15); - $y = $this->getHighestWorkableBlock($x, $z); - $tallRand = $random->nextRange(0, 17); - $yMax = $y + 1 + (int) ($tallRand > 10) + (int) ($tallRand > 15); - - if($y !== -1){ - for(; $y < 127 and $y < $yMax; $y++){ - if($this->canCactusStay($x, $y, $z)){ - $this->level->setBlockIdAt($x, $y, $z, Block::CACTUS); - $this->level->setBlockDataAt($x, $y, $z, 1); - } - } - } - } - } - - private function canCactusStay($x, $y, $z){ - $b = $this->level->getBlockIdAt($x, $y, $z); - $below = $this->level->getBlockIdAt($x, $y - 1, $z); - foreach(array($this->level->getBlockIdAt($x + 1, $y, $z), $this->level->getBlockIdAt($x - 1, $y, $z), $this->level->getBlockIdAt($x, $y, $z + 1), $this->level->getBlockIdAt($x, $y, $z - 1)) as $adjacent){ - if($adjacent !== Block::AIR) return false; - } - return ($b === Block::AIR) and ($below === Block::SAND or $below === Block::CACTUS); - } - - private function getHighestWorkableBlock($x, $z){ - for($y = 127; $y >= 0; --$y){ - $b = $this->level->getBlockIdAt($x, $y, $z); - if($b !== Block::AIR and $b !== Block::LEAVES and $b !== Block::LEAVES2 and $b !== Block::SNOW_LAYER){ - break; - } - } - - return $y === 0 ? -1 : ++$y; - } -} diff --git a/src/devmine/levels/generator/populator/Caves.php b/src/devmine/levels/generator/populator/Caves.php deleted file mode 100644 index 5a10ec5..0000000 --- a/src/devmine/levels/generator/populator/Caves.php +++ /dev/null @@ -1,84 +0,0 @@ -cavesSimplex != null){ - return; - } - $this->cavesSimplex = new Simplex($random, 4.1, 15, 1 / 200); - //实在太密啦啦啦 - } - - - public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ - $this->initPopulate($random); - $chunk = $level->getChunk($chunkX, $chunkZ); - $cavesGenerate = Generator::getFastNoise3D($this->cavesSimplex, 16, 128, 16, 4, 4, 4, $chunkX * 16, 0, $chunkZ * 16); - for($x = 0; $x < 16; $x++){ - for($z = 0; $z < 16; $z++){ - - $biome = Biome::getBiome($chunk->getBiomeId($x, $z)); - $hasWater = false; - $highest = true; - if($biome instanceof WateryBiome){ - $hasWater = true; - $highest = false; - } - for($y = 127; $y >= 20; $y--){ - if($chunk->getBlockId($x, $y, $z) == Block::AIR){ - continue; - } - if($chunk->getBlockId($x, $y, $z) == Block::WATER or $chunk->getBlockId($x, $y, $z) == Block::STILL_WATER){ - $hasWater = true; - $highest = false; - continue; - } - if($hasWater){ - $y -= 5; - $hasWater = false; - continue; - } - if($cavesGenerate[$x][$z][$y] > 0.35){ - if($y > 20){ - $chunk->setBlockId($x, $y, $z, Block::AIR); - $highest = $chunk->getHighestBlockAt($x, $z); - /*int light = y < highest ? (highest - y < 10 ? highest - y : 1) : 10; - chunk.setBlockSkyLight(x, y, z, light); - int bl = 0; - if (y < 25) { - bl = (25 - y) * 2; - } - chunk.setBlockLight(x, y, z, bl);*/ - }else{ - //LAVA - $chunk->setBlockId($x, $y, $z, Block::STILL_LAVA); - $chunk->setBlockLight($x, $y + 1, $z, 15); - } - - }elseif($highest){ - if($chunk->getBlockId($x, $y, $z) == Block::DIRT){ - $chunk->setBlockId($x, $y, $z, Block::GRASS); - } - $highest = false; - } - } - } - } - } -} diff --git a/src/devmine/levels/generator/populator/DeadBush.php b/src/devmine/levels/generator/populator/DeadBush.php deleted file mode 100644 index c29b8e4..0000000 --- a/src/devmine/levels/generator/populator/DeadBush.php +++ /dev/null @@ -1,55 +0,0 @@ -randomAmount = $amount; - } - - public function setBaseAmount($amount){ - $this->baseAmount = $amount; - } - - public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ - $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; - for($i = 0; $i < $amount; ++$i){ - $x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15); - $z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15); - $y = $this->getHighestWorkableBlock($x, $z); - - if($y !== -1 and $this->canDeadBushStay($x, $y, $z)){ - $this->level->setBlockIdAt($x, $y, $z, Block::DEAD_BUSH); - $this->level->setBlockDataAt($x, $y, $z, 1); - } - } - } - - private function canDeadBushStay($x, $y, $z){ - $b = $this->level->getBlockIdAt($x, $y, $z); - return ($b === Block::AIR or $b === Block::SNOW_LAYER) and $this->level->getBlockIdAt($x, $y - 1, $z) === Block::SAND; - } - - private function getHighestWorkableBlock($x, $z){ - for($y = 127; $y >= 0; --$y){ - $b = $this->level->getBlockIdAt($x, $y, $z); - if($b !== Block::AIR and $b !== Block::LEAVES and $b !== Block::LEAVES2 and $b !== Block::SNOW_LAYER){ - break; - } - } - - return $y === 0 ? -1 : ++$y; - } -} diff --git a/src/devmine/levels/generator/populator/Flower.php b/src/devmine/levels/generator/populator/Flower.php deleted file mode 100644 index 9d896c5..0000000 --- a/src/devmine/levels/generator/populator/Flower.php +++ /dev/null @@ -1,73 +0,0 @@ -randomAmount = $amount; - } - - public function setBaseAmount($amount){ - $this->baseAmount = $amount; - } - - public function addType($type){ - $this->flowerTypes[] = $type; - } - - public function getTypes(){ - return $this->flowerTypes; - } - - public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ - $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; - - if(count($this->flowerTypes) === 0){ - $this->addType([Block::DANDELION, 0]); - $this->addType([Block::RED_FLOWER, FlowerBlock::TYPE_POPPY]); - } - - $endNum = count($this->flowerTypes) - 1; - - for($i = 0; $i < $amount; ++$i){ - $x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15); - $z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15); - $y = $this->getHighestWorkableBlock($x, $z); - if($y !== -1 and $this->canFlowerStay($x, $y, $z)){ - $type = mt_rand(0, $endNum); - $this->level->setBlockIdAt($x, $y, $z, $this->flowerTypes[$type][0]); - $this->level->setBlockDataAt($x, $y, $z, $this->flowerTypes[$type][1]); - } - } - } - - private function canFlowerStay($x, $y, $z){ - $b = $this->level->getBlockIdAt($x, $y, $z); - return ($b === Block::AIR or $b === Block::SNOW_LAYER) and $this->level->getBlockIdAt($x, $y - 1, $z) === Block::GRASS; - } - - private function getHighestWorkableBlock($x, $z){ - for($y = 127; $y >= 0; --$y){ - $b = $this->level->getBlockIdAt($x, $y, $z); - if($b !== Block::AIR and $b !== Block::LEAVES and $b !== Block::LEAVES2 and $b !== Block::SNOW_LAYER){ - break; - } - } - return $y === 0 ? -1 : ++$y; - } -} \ No newline at end of file diff --git a/src/devmine/levels/generator/populator/GroundFire.php b/src/devmine/levels/generator/populator/GroundFire.php deleted file mode 100644 index 4a2eb0d..0000000 --- a/src/devmine/levels/generator/populator/GroundFire.php +++ /dev/null @@ -1,56 +0,0 @@ -randomAmount = $amount; - } - - public function setBaseAmount($amount){ - $this->baseAmount = $amount; - } - - public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ - $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; - for($i = 0; $i < $amount; ++$i){ - $x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15); - $z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15); - $y = $this->getHighestWorkableBlock($x, $z); - //echo "Fire to $x, $y, $z\n"; - if($y !== -1 and $this->canGroundFireStay($x, $y, $z)){ - $this->level->setBlockIdAt($x, $y, $z, Block::FIRE); - $this->level->updateBlockLight($x, $y, $z); - } - } - } - - private function canGroundFireStay($x, $y, $z){ - $b = $this->level->getBlockIdAt($x, $y, $z); - return ($b === Block::AIR or $b === Block::SNOW_LAYER) and $this->level->getBlockIdAt($x, $y - 1, $z) === 87; - } - - private function getHighestWorkableBlock($x, $z){ - for($y = 0; $y <= 127; ++$y){ - $b = $this->level->getBlockIdAt($x, $y, $z); - if($b == Block::AIR){ - break; - } - } - - return $y === 0 ? -1 : $y; - } -} \ No newline at end of file diff --git a/src/devmine/levels/generator/populator/LilyPad.php b/src/devmine/levels/generator/populator/LilyPad.php deleted file mode 100644 index efda075..0000000 --- a/src/devmine/levels/generator/populator/LilyPad.php +++ /dev/null @@ -1,55 +0,0 @@ -randomAmount = $amount; - } - - public function setBaseAmount($amount){ - $this->baseAmount = $amount; - } - - public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ - $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; - for($i = 0; $i < $amount; ++$i){ - $x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15); - $z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15); - $y = $this->getHighestWorkableBlock($x, $z); - - if($y !== -1 and $this->canLilyPadStay($x, $y, $z)){ - $this->level->setBlockIdAt($x, $y, $z, Block::WATER_LILY); - $this->level->setBlockDataAt($x, $y, $z, 1); - } - } - } - - private function canLilyPadStay($x, $y, $z){ - $b = $this->level->getBlockIdAt($x, $y, $z); - return ($b === Block::AIR or $b === Block::SNOW_LAYER) and $this->level->getBlockIdAt($x, $y - 1, $z) === Block::STILL_WATER; - } - - private function getHighestWorkableBlock($x, $z){ - for($y = 127; $y >= 0; --$y){ - $b = $this->level->getBlockIdAt($x, $y, $z); - if($b !== Block::AIR and $b !== Block::LEAVES and $b !== Block::LEAVES2 and $b !== Block::SNOW_LAYER){ - break; - } - } - - return $y === 0 ? -1 : ++$y; - } -} diff --git a/src/devmine/levels/generator/populator/MossStone.php b/src/devmine/levels/generator/populator/MossStone.php deleted file mode 100644 index 242a215..0000000 --- a/src/devmine/levels/generator/populator/MossStone.php +++ /dev/null @@ -1,55 +0,0 @@ -randomAmount = $amount; - } - - public function setBaseAmount($amount){ - $this->baseAmount = $amount; - } - - public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ - $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; - for($i = 0; $i < $amount; ++$i){ - $x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15); - $z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15); - $y = $this->getHighestWorkableBlock($x, $z); - - if($y !== -1 and $this->canMossStoneStay($x, $y, $z)){ - $this->level->setBlockIdAt($x, $y, $z, Block::MOSS_STONE); - $this->level->setBlockDataAt($x, $y, $z, 1); - } - } - } - - private function canMossStoneStay($x, $y, $z){ - $b = $this->level->getBlockIdAt($x, $y, $z); - return ($b === Block::AIR or $b === Block::SNOW_LAYER) and $this->level->getBlockIdAt($x, $y - 1, $z) === Block::PODZOL; - } - - private function getHighestWorkableBlock($x, $z){ - for($y = 127; $y >= 0; --$y){ - $b = $this->level->getBlockIdAt($x, $y, $z); - if($b !== Block::AIR and $b !== Block::LEAVES and $b !== Block::LEAVES2 and $b !== Block::SNOW_LAYER){ - break; - } - } - - return $y === 0 ? -1 : ++$y; - } -} diff --git a/src/devmine/levels/generator/populator/NetherGlowStone.php b/src/devmine/levels/generator/populator/NetherGlowStone.php deleted file mode 100644 index 1fc14e8..0000000 --- a/src/devmine/levels/generator/populator/NetherGlowStone.php +++ /dev/null @@ -1,41 +0,0 @@ -level = $level; - $type = new OreType(new Glowstone(), 1, 20, 128, 10); - $ore = new ObjectOre($random, $type); - for($i = 0; $i < $ore->type->clusterCount; ++$i){ - $x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15); - $z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15); - $y = $this->getHighestWorkableBlock($x, $z); - $ore->placeObject($level, $x, $y, $z); - } - } - - private function getHighestWorkableBlock($x, $z){ - for($y = 127; $y >= 0; --$y){ - $b = $this->level->getBlockIdAt($x, $y, $z); - if($b == 0){ - break; - } - } - - return $y === 0 ? -1 : ++$y; - } - -} \ No newline at end of file diff --git a/src/devmine/levels/generator/populator/NetherLava.php b/src/devmine/levels/generator/populator/NetherLava.php deleted file mode 100644 index ef3b7e6..0000000 --- a/src/devmine/levels/generator/populator/NetherLava.php +++ /dev/null @@ -1,273 +0,0 @@ -randomAmount = $amount; - } - - public function setBaseAmount($amount){ - $this->baseAmount = $amount; - } - - public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ - if(mt_rand(0, 100) < 5){ - $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; - for($i = 0; $i < $amount; ++$i){ - $x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15); - $z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15); - $y = $this->getHighestWorkableBlock($x, $z); - if($y !== -1 and $this->canNetherLavaStay($x, $y, $z)){ - $this->level->setBlockIdAt($x, $y, $z, Block::LAVA); - $this->level->updateBlockLight($x, $y, $z); - $this->lavaSpread($x, $y, $z); - } - } - } - } - - private function getFlowDecay($x1, $y1, $z1, $x2, $y2, $z2){ - if($this->level->getBlockIdAt($x1, $y1, $z1) !== $this->level->getBlockIdAt($x2, $y2, $z2)){ - return -1; - }else{ - return $this->level->getBlockDataAt($x2, $y2, $z2); - } - } - - private function lavaSpread($x, $y, $z){ - if($this->level->getChunk($x >> 4, $z >> 4) == null){ - return; - } - $decay = $this->getFlowDecay($x, $y, $z, $x, $y, $z); - $multiplier = 2; - - if($decay > 0){ - $smallestFlowDecay = -100; - $smallestFlowDecay = $this->getSmallestFlowDecay($x, $y, $z, $x, $y, $z - 1, $smallestFlowDecay); - $smallestFlowDecay = $this->getSmallestFlowDecay($x, $y, $z, $x, $y, $z + 1, $smallestFlowDecay); - $smallestFlowDecay = $this->getSmallestFlowDecay($x, $y, $z, $x - 1, $y, $z, $smallestFlowDecay); - $smallestFlowDecay = $this->getSmallestFlowDecay($x, $y, $z, $x + 1, $y, $z, $smallestFlowDecay); - - $k = $smallestFlowDecay + $multiplier; - - if($k >= 8 or $smallestFlowDecay < 0){ - $k = -1; - } - - if(($topFlowDecay = $this->getFlowDecay($x, $y, $z, $x, $y + 1, $z)) >= 0){ - if($topFlowDecay >= 8){ - $k = $topFlowDecay; - }else{ - $k = $topFlowDecay | 0x08; - } - } - - if($decay < 8 and $k < 8 and $k > 1 and mt_rand(0, 4) !== 0){ - $k = $decay; - } - - if($k !== $decay){ - $decay = $k; - if($decay < 0){ - $this->level->setBlockIdAt($x, $y, $z, 0); - }else{ - $this->level->setBlockIdAt($x, $y, $z, Block::LAVA); - $this->level->setBlockDataAt($x, $y, $z, $decay); - $this->level->updateBlockLight($x, $y, $z); - $this->lavaSpread($x, $y, $z); - return; - } - } - } - - if($this->canFlowInto($x, $y - 1, $z)){ - if($decay >= 8){ - $this->flowIntoBlock($x, $y - 1, $z, $decay); - }else{ - $this->flowIntoBlock($x, $y - 1, $z, $decay | 0x08); - } - }elseif($decay >= 0 and ($decay === 0 or !$this->canFlowInto($x, $y - 1, $z))){ - $flags = $this->getOptimalFlowDirections($x, $y, $z); - - $l = $decay + $multiplier; - - if($decay >= 8){ - $l = 1; - } - - if($l >= 8){ - return; - } - - if($flags[0]){ - $this->flowIntoBlock($x - 1, $y, $z, $l); - } - - if($flags[1]){ - $this->flowIntoBlock($x + 1, $y, $z, $l); - } - - if($flags[2]){ - $this->flowIntoBlock($x, $y, $z - 1, $l); - } - - if($flags[3]){ - $this->flowIntoBlock($x, $y, $z + 1, $l); - } - } - } - - private function flowIntoBlock($x, $y, $z, $newFlowDecay){ - if($this->level->getBlockIdAt($x, $y, $z) === Block::AIR){ - $this->level->setBlockIdAt($x, $y, $z, Block::LAVA); - $this->level->setBlockDataAt($x, $y, $z, $newFlowDecay); - $this->level->updateBlockLight($x, $y, $z); - $this->lavaSpread($x, $y, $z); - } - } - - private function canFlowInto($x, $y, $z){ - $id = $this->level->getBlockIdAt($x, $y, $z); - if($id === Block::AIR or $id === Block::LAVA or $id === Block::STILL_LAVA){ - return true; - } - return false; - } - - private function calculateFlowCost($xx, $yy, $zz, $accumulatedCost, $previousDirection){ - $cost = 1000; - - for($j = 0; $j < 4; ++$j){ - if( - ($j === 0 and $previousDirection === 1) or - ($j === 1 and $previousDirection === 0) or - ($j === 2 and $previousDirection === 3) or - ($j === 3 and $previousDirection === 2) - ){ - $x = $xx; - $y = $yy; - $z = $zz; - - if($j === 0){ - --$x; - }elseif($j === 1){ - ++$x; - }elseif($j === 2){ - --$z; - }elseif($j === 3){ - ++$z; - } - - if(!$this->canFlowInto($x, $y, $z)){ - continue; - }elseif($this->canFlowInto($x, $y, $z) and $this->level->getBlockDataAt($x, $y, $z) === 0){ - continue; - }elseif($this->canFlowInto($x, $y - 1, $z)){ - return $accumulatedCost; - } - - if($accumulatedCost >= 4){ - continue; - } - - $realCost = $this->calculateFlowCost($x, $y, $z, $accumulatedCost + 1, $j); - - if($realCost < $cost){ - $cost = $realCost; - } - } - } - - return $cost; - } - - private function getOptimalFlowDirections($xx, $yy, $zz){ - $flowCost = [0, 0, 0, 0]; - $isOptimalFlowDirection = [0, 0, 0, 0]; - for($j = 0; $j < 4; ++$j){ - $flowCost[$j] = 1000; - - $x = $xx; - $y = $yy; - $z = $zz; - - if($j === 0){ - --$x; - }elseif($j === 1){ - ++$x; - }elseif($j === 2){ - --$z; - }elseif($j === 3){ - ++$z; - } - - if(!$this->canFlowInto($x, $y, $z)){ - continue; - }elseif($this->canFlowInto($x, $y, $z) and $this->level->getBlockDataAt($x, $y, $z) === 0){ - continue; - }elseif($this->canFlowInto($x, $y - 1, $z)){ - $flowCost[$j] = 0; - }else{ - $flowCost[$j] = $this->calculateFlowCost($x, $y, $z, 1, $j); - } - } - - $minCost = $flowCost[0]; - - for($i = 1; $i < 4; ++$i){ - if($flowCost[$i] < $minCost){ - $minCost = $flowCost[$i]; - } - } - - for($i = 0; $i < 4; ++$i){ - $isOptimalFlowDirection[$i] = ($flowCost[$i] === $minCost); - } - - return $isOptimalFlowDirection; - } - - private function getSmallestFlowDecay($x1, $y1, $z1, $x2, $y2, $z2, $decay){ - $blockDecay = $this->getFlowDecay($x1, $y1, $z1, $x2, $y2, $z2); - - if($blockDecay < 0){ - return $decay; - }elseif($blockDecay === 0){ - //Nothing to do! - }elseif($blockDecay >= 8){ - $blockDecay = 0; - } - - return ($decay >= 0 && $blockDecay >= $decay) ? $decay : $blockDecay; - } - - - private function canNetherLavaStay($x, $y, $z){ - $b = $this->level->getBlockIdAt($x, $y, $z); - return $b === Block::AIR; - } - - private function getHighestWorkableBlock($x, $z){ - for($y = 127; $y >= 0; --$y){ - $b = $this->level->getBlockIdAt($x, $y, $z); - if($b == Block::AIR){ - break; - } - } - - return $y === 0 ? -1 : $y; - } -} \ No newline at end of file diff --git a/src/devmine/levels/generator/populator/NetherOre.php b/src/devmine/levels/generator/populator/NetherOre.php deleted file mode 100644 index 75e4a15..0000000 --- a/src/devmine/levels/generator/populator/NetherOre.php +++ /dev/null @@ -1,31 +0,0 @@ -oreTypes as $type){ - $ore = new ObjectOre($random, $type); - for($i = 0; $i < $ore->type->clusterCount; ++$i){ - $x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15); - $y = $random->nextRange($ore->type->minHeight, $ore->type->maxHeight); - $z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15); - if($ore->canPlaceObject($level, $x, $y, $z)){ - $ore->placeObject($level, $x, $y, $z); - } - } - } - } - - public function setOreTypes(array $types){ - $this->oreTypes = $types; - } -} \ No newline at end of file diff --git a/src/devmine/levels/generator/populator/Sugarcane.php b/src/devmine/levels/generator/populator/Sugarcane.php deleted file mode 100644 index 21ce985..0000000 --- a/src/devmine/levels/generator/populator/Sugarcane.php +++ /dev/null @@ -1,69 +0,0 @@ -randomAmount = $amount; - } - - public function setBaseAmount($amount){ - $this->baseAmount = $amount; - } - - public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ - $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; - for($i = 0; $i < $amount; ++$i){ - $x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15); - $z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15); - - $y = $this->getHighestWorkableBlock($x, $z); - $tallRand = $random->nextRange(0, 17); - $yMax = $y + 2 + (int) ($tallRand > 10) + (int) ($tallRand > 15); - if($y !== -1){ - for(; $y < 127 and $y < $yMax; $y++){ - if($this->canSugarcaneStay($x, $y, $z)){ - $this->level->setBlockIdAt($x, $y, $z, Block::SUGARCANE_BLOCK); - $this->level->setBlockDataAt($x, $y, $z, 1); - } - } - } - } - } - - private function canSugarcaneStay($x, $y, $z){ - $b = $this->level->getBlockIdAt($x, $y, $z); - $below = $this->level->getBlockIdAt($x, $y - 1, $z); - $water = false; - foreach(array($this->level->getBlockIdAt($x + 1, $y - 1, $z), $this->level->getBlockIdAt($x - 1, $y - 1, $z), $this->level->getBlockIdAt($x, $y - 1, $z + 1), $this->level->getBlockIdAt($x, $y - 1, $z - 1)) as $adjacent){ - if($adjacent === Block::WATER or $adjacent === Block::STILL_WATER){ - $water = true; - break; - } - } - return ($b === Block::AIR) and ((($below === Block::SAND or $below === Block::GRASS) and $water) or ($below === Block::SUGARCANE_BLOCK)); - } - - private function getHighestWorkableBlock($x, $z){ - for($y = 127; $y >= 0; --$y){ - $b = $this->level->getBlockIdAt($x, $y, $z); - if($b !== Block::AIR and $b !== Block::LEAVES and $b !== Block::LEAVES2){ - break; - } - } - - return $y === 0 ? -1 : ++$y; - } -} diff --git a/src/devmine/levels/generator/populator/WaterPit.php b/src/devmine/levels/generator/populator/WaterPit.php deleted file mode 100644 index ac908c7..0000000 --- a/src/devmine/levels/generator/populator/WaterPit.php +++ /dev/null @@ -1,54 +0,0 @@ -randomAmount = $amount; - } - - public function setBaseAmount($amount){ - $this->baseAmount = $amount; - } - - public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ - $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; - for($i = 0; $i < $amount; ++$i){ - $x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15); - $z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15); - $y = $this->getHighestWorkableBlock($x, $z); - - if($y !== -1 and $this->canWaterPitStay($x, $y, $z)){ - $this->level->setBlockIdAt($x, $y, $z, Block::STILL_WATER); - $this->level->setBlockDataAt($x, $y, $z , 8); - } - } - } - - private function canWaterPitStay($x, $y, $z){ - $b = $this->level->getBlockIdAt($x, $y, $z); - return ($b === Block::AIR or $b === Block::GRASS) and $this->level->getBlockIdAt($x, $y, $z) === Block::DIRT; - } - - private function getHighestWorkableBlock($x, $z){ - for($y = 61; $y >= 0; --$y){ - $b = $this->level->getBlockIdAt($x, $y, $z); - if($b !== Block::AIR and $b !== Block::LEAVES and $b !== Block::LEAVES2 and $b !== Block::SNOW_LAYER){ - break; - } - } - - return $y === 0 ? -1 : ++$y; - } -} diff --git a/src/devmine/levels/particle/LargeExplodeParticle.php b/src/devmine/levels/particle/LargeExplodeParticle.php deleted file mode 100644 index 6142337..0000000 --- a/src/devmine/levels/particle/LargeExplodeParticle.php +++ /dev/null @@ -1,13 +0,0 @@ -evid = LevelEventPacket::EVENT_PARTICLE_SPLASH; - $pk->x = $this->x; - $pk->y = $this->y; - $pk->z = $this->z; - $pk->data = $this->data; - return $pk; - } -} \ No newline at end of file diff --git a/src/devmine/levels/particle/WhiteSmokeParticle.php b/src/devmine/levels/particle/WhiteSmokeParticle.php deleted file mode 100644 index f657e1a..0000000 --- a/src/devmine/levels/particle/WhiteSmokeParticle.php +++ /dev/null @@ -1,13 +0,0 @@ -instrument = $instrument; - $this->pitch = $pitch; - } - - public function encode(){ - $pk = new BlockEventPacket(); - $pk->x = $this->x; - $pk->y = $this->y; - $pk->z = $this->z; - $pk->case1 = $this->instrument; - $pk->case2 = $this->pitch; - - return $pk; - } -} diff --git a/src/devmine/levels/sound/SpellSound.php b/src/devmine/levels/sound/SpellSound.php deleted file mode 100644 index 9fae3e4..0000000 --- a/src/devmine/levels/sound/SpellSound.php +++ /dev/null @@ -1,31 +0,0 @@ -x, $pos->y, $pos->z); - $this->id = (int) LevelEventPacket::EVENT_SOUND_SPELL; - $this->color = ($r << 16 | $g << 8 | $b) & 0xffffff; - } - - public function encode(){ - $pk = new LevelEventPacket; - $pk->evid = $this->id; - $pk->x = $this->x; - $pk->y = $this->y; - $pk->z = $this->z; - $pk->data = $this->color; - - return $pk; - } -} \ No newline at end of file diff --git a/src/devmine/levels/sound/TNTPrimeSound.php b/src/devmine/levels/sound/TNTPrimeSound.php deleted file mode 100644 index 05c593f..0000000 --- a/src/devmine/levels/sound/TNTPrimeSound.php +++ /dev/null @@ -1,17 +0,0 @@ -level = $level; - $this->weatherNow = self::SUNNY; - $this->duration = $duration; - $this->lastUpdate = $level->getServer()->getTick(); - $this->temporalVector = new Vector3(0, 0, 0); - } - - public function canCalculate() : bool{ - return $this->canCalculate; - } - - public function setCanCalculate(bool $canCalc){ - $this->canCalculate = $canCalc; - } - - public function calcWeather($currentTick){ - if($this->canCalculate()){ - $tickDiff = $currentTick - $this->lastUpdate; - $this->duration -= $tickDiff; - if($this->duration <= 0){ - //0晴天1下雨2雷雨3阴天雷 - if($this->weatherNow == self::SUNNY){ - $weather = $this->randomWeatherData[array_rand($this->randomWeatherData)]; - $duration = mt_rand(min($this->level->getServer()->weatherRandomDurationMin, $this->level->getServer()->weatherRandomDurationMax), max($this->level->getServer()->weatherRandomDurationMin, $this->level->getServer()->weatherRandomDurationMax));; - $this->level->getServer()->getPluginManager()->callEvent($ev = new WeatherChangeEvent($this->level, $weather, $duration)); - if(!$ev->isCancelled()){ - $this->weatherNow = $ev->getWeather(); - $this->strength1 = mt_rand(90000, 110000); - $this->strength2 = mt_rand(30000, 40000); - $this->duration = $ev->getDuration(); - $this->changeWeather($this->weatherNow, $this->strength1, $this->strength2); - } - }else{ - $weather = self::SUNNY; - $duration = mt_rand(min($this->level->getServer()->weatherRandomDurationMin, $this->level->getServer()->weatherRandomDurationMax), max($this->level->getServer()->weatherRandomDurationMin, $this->level->getServer()->weatherRandomDurationMax)); - $this->level->getServer()->getPluginManager()->callEvent($ev = new WeatherChangeEvent($this->level, $weather, $duration)); - if(!$ev->isCancelled()){ - $this->weatherNow = $ev->getWeather(); - $this->strength1 = 0; - $this->strength2 = 0; - $this->duration = $ev->getDuration(); - $this->changeWeather($this->weatherNow, $this->strength1, $this->strength2); - } - } - } - if(($this->weatherNow > 0) and ($this->level->getServer()->lightningTime > 0) and is_int($this->duration / $this->level->getServer()->lightningTime)){ - $players = $this->level->getPlayers(); - if(count($players) > 0){ - $p = $players[array_rand($players)]; - $x = $p->x + mt_rand(-64, 64); - $z = $p->z + mt_rand(-64, 64); - $y = $this->level->getHighestBlockAt($x, $z); - $this->level->spawnLightning($this->temporalVector->setComponents($x, $y, $z)); - } - /*foreach($this->level->getPlayers() as $p){ - if(mt_rand(0, 1) == 1){ - $x = $p->getX() + rand(-100, 100); - $y = $p->getY() + rand(20, 50); - $z = $p->getZ() + rand(-100, 100); - $this->level->sendLighting($x, $y, $z, $p); - } - }*/ - } - } - $this->lastUpdate = $currentTick; - } - - public function setWeather(int $wea, int $duration = 12000){ - $this->level->getServer()->getPluginManager()->callEvent($ev = new WeatherChangeEvent($this->level, $wea, $duration)); - if(!$ev->isCancelled()){ - $this->weatherNow = $ev->getWeather();; - $this->strength1 = mt_rand(90000, 110000); - $this->strength2 = mt_rand(30000, 40000); - $this->duration = $ev->getDuration(); - $this->changeWeather($wea, $this->strength1, $this->strength2); - } - } - - public function getRandomWeatherData() : array{ - return $this->randomWeatherData; - } - - public function setRandomWeatherData(array $randomWeatherData){ - $this->randomWeatherData = $randomWeatherData; - } - - public function getWeather() : int{ - return $this->weatherNow; - } - - public static function getWeatherFromString($weather){ - if(is_int($weather)){ - if($weather <= 3){ - return $weather; - } - return self::SUNNY; - } - switch(strtolower($weather)){ - case "clear": - case "sunny": - case "fine": - return self::SUNNY; - case "rain": - case "rainy": - return self::RAINY; - case "thunder": - return self::THUNDER; - case "rain_thunder": - case "rainy_thunder": - return self::RAINY_THUNDER; - default: - return self::SUNNY; - } - } - - /** - * @return bool - */ - public function isSunny() : bool{ - if($this->getWeather() == self::SUNNY){ - return true; - }else{ - return false; - } - } - - /** - * @return bool - */ - public function isRainy() : bool{ - if($this->getWeather() == self::RAINY){ - return true; - }else{ - return false; - } - } - - /** - * @return bool - */ - public function isRainyThunder() : bool{ - if($this->getWeather() == self::RAINY_THUNDER){ - return true; - }else{ - return false; - } - } - - /** - * @return bool - */ - public function isThunder() : bool{ - if($this->getWeather() == self::THUNDER){ - return true; - }else{ - return false; - } - } - - public function getStrength() : array{ - return [$this->strength1, $this->strength2]; - } - - public function sendWeather(Player $p){ - $pk1 = new LevelEventPacket; - $pk1->evid = LevelEventPacket::EVENT_STOP_RAIN; - $pk1->data = $this->strength1; - $pk2 = new LevelEventPacket; - $pk2->evid = LevelEventPacket::EVENT_STOP_THUNDER; - $pk2->data = $this->strength2; - $p->dataPacket($pk1); - $p->dataPacket($pk2); - if($p->weatherData[0] != $this->weatherNow){ - if($this->weatherNow == 1){ - $pk = new LevelEventPacket; - $pk->evid = LevelEventPacket::EVENT_START_RAIN; - $pk->data = $this->strength1; - $p->dataPacket($pk); - }elseif($this->weatherNow == 2){ - $pk = new LevelEventPacket; - $pk->evid = LevelEventPacket::EVENT_START_RAIN; - $pk->data = $this->strength1; - $p->dataPacket($pk); - $pk = new LevelEventPacket; - $pk->evid = LevelEventPacket::EVENT_START_THUNDER; - $pk->data = $this->strength2; - $p->dataPacket($pk); - }elseif($this->weatherNow == 3){ - $pk = new LevelEventPacket; - $pk->evid = LevelEventPacket::EVENT_START_THUNDER; - $pk->data = $this->strength2; - $p->dataPacket($pk); - } - $p->weatherData = [$this->weatherNow, $this->strength1, $this->strength2]; - } - } - - public function changeWeather(int $wea, int $strength1, int $strength2){ - $pk1 = new LevelEventPacket; - $pk1->evid = LevelEventPacket::EVENT_STOP_RAIN; - $pk1->data = $this->strength1; - $pk2 = new LevelEventPacket; - $pk2->evid = LevelEventPacket::EVENT_STOP_THUNDER; - $pk2->data = $this->strength2; - foreach($this->level->getPlayers() as $p){ - if($p->weatherData[0] != $wea){ - $p->dataPacket($pk1); - $p->dataPacket($pk2); - if($wea == 1){ - $pk = new LevelEventPacket; - $pk->evid = LevelEventPacket::EVENT_START_RAIN; - $pk->data = $strength1; - $p->dataPacket($pk); - }elseif($wea == 2){ - $pk = new LevelEventPacket; - $pk->evid = LevelEventPacket::EVENT_START_RAIN; - $pk->data = $strength1; - $p->dataPacket($pk); - $pk = new LevelEventPacket; - $pk->evid = LevelEventPacket::EVENT_START_THUNDER; - $pk->data = $strength2; - $p->dataPacket($pk); - }elseif($wea == 3){ - $pk = new LevelEventPacket; - $pk->evid = LevelEventPacket::EVENT_START_THUNDER; - $pk->data = $strength2; - $p->dataPacket($pk); - } - $p->weatherData = [$wea, $strength1, $strength2]; - } - } - } - -} \ No newline at end of file diff --git a/src/devmine/levels/weather/WeatherManager.php b/src/devmine/levels/weather/WeatherManager.php deleted file mode 100644 index b9750f2..0000000 --- a/src/devmine/levels/weather/WeatherManager.php +++ /dev/null @@ -1,40 +0,0 @@ -getName()] = $level; - return true; - } - - public static function unregisterLevel(Level $level){ - if(isset(self::$registeredLevel[$level->getName()])) { - unset(self::$registeredLevel[$level->getName()]); - return true; - } - return false; - } - - public static function updateWeather(){ - foreach(self::$registeredLevel as $level) { - $level->getWeather()->calcWeather($level->getServer()->getTick()); - } - } - - public static function isRegistered(Level $level){ - if(isset(self::$registeredLevel[$level->getName()])) return true; - return false; - } - -} \ No newline at end of file diff --git a/src/devmine/pluginfeatures/FolderPluginLoader.php b/src/devmine/pluginfeatures/FolderPluginLoader.php deleted file mode 100644 index ddbbb4f..0000000 --- a/src/devmine/pluginfeatures/FolderPluginLoader.php +++ /dev/null @@ -1,127 +0,0 @@ -server = $server; - } - - /** - * Loads the plugin contained in $file - * - * @param string $file - * - * @return Plugin - */ - public function loadPlugin($file){ - if(is_dir($file) and file_exists($file . "/plugin.yml") and file_exists($file . "/src/")){ - if(($description = $this->getPluginDescription($file)) instanceof PluginDescription){ - MainLogger::getLogger()->info(TextFormat::LIGHT_PURPLE."Loading source plugin " . $description->getFullName()); - $dataFolder = dirname($file) . DIRECTORY_SEPARATOR . $description->getName(); - if(file_exists($dataFolder) and !is_dir($dataFolder)){ - trigger_error("Projected dataFolder '" . $dataFolder . "' for " . $description->getName() . " exists and is not a directory", E_USER_WARNING); - - return null; - } - - - $className = $description->getMain(); - $this->server->getLoader()->addPath($file . "/src"); - - if(class_exists($className, true)){ - $plugin = new $className(); - $this->initPlugin($plugin, $description, $dataFolder, $file); - - return $plugin; - }else{ - trigger_error("Couldn't load source plugin " . $description->getName() . ": main class not found", E_USER_WARNING); - - return null; - } - } - } - - return null; - } - - /** - * Gets the PluginDescription from the file - * - * @param string $file - * - * @return PluginDescription - */ - public function getPluginDescription($file){ - if(is_dir($file) and file_exists($file . "/plugin.yml")){ - $yaml = @file_get_contents($file . "/plugin.yml"); - if($yaml != ""){ - return new PluginDescription($yaml); - } - } - - return null; - } - - /** - * Returns the filename patterns that this loader accepts - * - * @return array - */ - public function getPluginFilters(){ - return "/[^\\.]/"; - } - - /** - * @param PluginBase $plugin - * @param PluginDescription $description - * @param string $dataFolder - * @param string $file - */ - private function initPlugin(PluginBase $plugin, PluginDescription $description, $dataFolder, $file){ - $plugin->init($this, $this->server, $description, $dataFolder, $file); - $plugin->onLoad(); - } - - /** - * @param Plugin $plugin - */ - public function enablePlugin(Plugin $plugin){ - if($plugin instanceof PluginBase and !$plugin->isEnabled()){ - MainLogger::getLogger()->info("Enabling " . $plugin->getDescription()->getFullName()); - - $plugin->setEnabled(true); - - Server::getInstance()->getPluginManager()->callEvent(new PluginEnableEvent($plugin)); - } - } - - /** - * @param Plugin $plugin - */ - public function disablePlugin(Plugin $plugin){ - if($plugin instanceof PluginBase and $plugin->isEnabled()){ - MainLogger::getLogger()->info("Disabling " . $plugin->getDescription()->getFullName()); - - Server::getInstance()->getPluginManager()->callEvent(new PluginDisableEvent($plugin)); - - $plugin->setEnabled(false); - } - } -} diff --git a/src/devmine/server/Achievement.php b/src/devmine/server/Achievement.php index 51dcffe..dd057d4 100644 --- a/src/devmine/server/Achievement.php +++ b/src/devmine/server/Achievement.php @@ -4,7 +4,7 @@ namespace devmine\server; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\utilities\main\TextFormat; /** diff --git a/src/devmine/server/CompatibleClassLoader.php b/src/devmine/server/CompatibleClassLoader.php deleted file mode 100644 index 7ba7f42..0000000 --- a/src/devmine/server/CompatibleClassLoader.php +++ /dev/null @@ -1,15 +0,0 @@ -addPath(array_shift($paths)); - } -} \ No newline at end of file diff --git a/src/devmine/server/CrashDump.php b/src/devmine/server/CrashDump.php index a0f4eb5..395a22e 100644 --- a/src/devmine/server/CrashDump.php +++ b/src/devmine/server/CrashDump.php @@ -1,11 +1,12 @@ addLine(); $this->addLine("Loaded plugins:"); $this->data["plugins"] = []; @@ -102,9 +103,9 @@ private function extraData(){ $this->data["parameters"] = (array) $arguments; $this->data["server.properties"] = @file_get_contents($this->server->getDataPath() . "server.properties"); $this->data["server.properties"] = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $this->data["server.properties"]); - $this->data["devmine.yml"] = @file_get_contents($this->server->getDataPath() . "devmine.yml"); + $this->data["DevMine.yml"] = @file_get_contents($this->server->getDataPath() . "DevMine.yml"); }else{ - $this->data["devmine.yml"] = ""; + $this->data["DevMine.yml"] = ""; $this->data["server.properties"] = ""; $this->data["parameters"] = []; } @@ -167,7 +168,7 @@ private function baseCrash(){ $this->addLine("Line: " . $error["line"]); $this->addLine("Type: " . $error["type"]); - if(strpos($error["file"], "src/devmine/") === false and strpos($error["file"], "src/raklib/") === false and strpos($error["file"], "src/synapse/") === false and file_exists($error["fullFile"])){ + if(strpos($error["file"], "src/DevMine/") === false and strpos($error["file"], "src/raklib/") === false and file_exists($error["fullFile"])){ $this->addLine(); $this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN"); $this->data["plugin"] = true; @@ -176,7 +177,7 @@ private function baseCrash(){ $file = $reflection->getProperty("file"); $file->setAccessible(true); foreach($this->server->getPluginManager()->getPlugins() as $plugin){ - $filePath = \devmine\cleanPath($file->getValue($plugin)); + $filePath = \DevMine\cleanPath($file->getValue($plugin)); if(strpos($error["file"], $filePath) === 0){ $this->data["plugin"] = $plugin->getName(); $this->addLine("BAD PLUGIN : " . $plugin->getDescription()->getFullName()); @@ -211,15 +212,15 @@ private function generalData(){ $version = new VersionString(); $this->data["general"] = []; $this->data["general"]["protocol"] = Info::CURRENT_PROTOCOL; - $this->data["general"]["api"] = \devmine\API_VERSION; - $this->data["general"]["git"] = \devmine\GIT_COMMIT; + $this->data["general"]["api"] = \DevMine\API_VERSION; + $this->data["general"]["git"] = \DevMine\GIT_COMMIT; $this->data["general"]["raklib"] = RakLib::VERSION; $this->data["general"]["uname"] = php_uname("a"); $this->data["general"]["php"] = phpversion(); $this->data["general"]["zend"] = zend_version(); $this->data["general"]["php_os"] = PHP_OS; $this->data["general"]["os"] = Utils::getOS(); - $this->addLine("devmine version: " . \devmine\GIT_COMMIT . " [Protocol " . Info::CURRENT_PROTOCOL . "; API " . API_VERSION . "]"); + $this->addLine("DevMine version: " . \DevMine\GIT_COMMIT . " [Protocol " . Info::CURRENT_PROTOCOL . "; API " . API_VERSION . "]"); $this->addLine("uname -a: " . php_uname("a")); $this->addLine("PHP version: " . phpversion()); $this->addLine("Zend version: " . zend_version()); diff --git a/src/devmine/server/DevMine.php b/src/devmine/server/DevMine.php index d7a2652..1c4c38e 100644 --- a/src/devmine/server/DevMine.php +++ b/src/devmine/server/DevMine.php @@ -47,7 +47,7 @@ function dummy(){ } } -namespace devmine\server { +namespace DevMine { use devmine\utilities\main\Binary; use devmine\utilities\main\MainLogger; use devmine\utilities\main\ServerKiller; @@ -55,18 +55,25 @@ function dummy(){ use devmine\utilities\main\Utils; use devmine\utilities\installer\Installer; - const VERSION = "git"; - const API_VERSION = "2.0.0"; //So the only plugin change is the "use" statements - const CODENAME = "Beta"; - const MINECRAFT_VERSION = "v0.15.0 alpha"; - const MINECRAFT_VERSION_NETWORK = "0.15.0"; - const devmine_API_VERSION = '2.0.0'; //So the only plugin change is the "use" statements - + const VERSION = ""; //will be set by CI to a git hash + const API_VERSION = "3.0.0"; + const CODENAME = "Crystal"; + + //This method should no longer be used, removing soon + /*const MINECRAFT_VERSION = "v1.0.0"; + const MINECRAFT_VERSION_NETWORK = "1.0.0";*/ + + /* + * Startup code. Do not look at it, it may harm you. + * Most of them are hacks to fix date-related bugs, or basic functions used after this + * This is the only non-class based file on this project. + * Enjoy it as much as I did writing it. I don't want to do it again. + */ if(\Phar::running(true) !== ""){ - @define('devmine\PATH', \Phar::running(true) . "/"); + @define('DevMine\PATH', \Phar::running(true) . "/"); }else{ - @define('devmine\PATH', \getcwd() . DIRECTORY_SEPARATOR); + @define('DevMine\PATH', \getcwd() . DIRECTORY_SEPARATOR); } if(version_compare("7.0", PHP_VERSION) > 0){ @@ -82,14 +89,14 @@ function dummy(){ } if(!class_exists("ClassLoader", false)){ - require_once(\devmine\PATH . "src/spl/ClassLoader.php"); - require_once(\devmine\PATH . "src/spl/BaseClassLoader.php"); - require_once(\devmine\PATH . "src/devmine/server/CompatibleClassLoader.php"); + require_once(\DevMine\PATH . "src/spl/ClassLoader.php"); + require_once(\DevMine\PATH . "src/spl/BaseClassLoader.php"); + require_once(\DevMine\PATH . "src/devmine/CompatibleClassLoader.php"); } $autoloader = new CompatibleClassLoader(); - $autoloader->addPath(\devmine\PATH . "src"); - $autoloader->addPath(\devmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl"); + $autoloader->addPath(\DevMine\PATH . "src"); + $autoloader->addPath(\DevMine\PATH . "src" . DIRECTORY_SEPARATOR . "spl"); $autoloader->register(true); @@ -103,25 +110,25 @@ function dummy(){ ini_set("default_charset", "utf-8"); ini_set("memory_limit", -1); - define('devmine\START_TIME', microtime(true)); + define('DevMine\START_TIME', microtime(true)); $opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-profiler"]); - define('devmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR); - define('devmine\pluginfeatures_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR); + define('DevMine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR); + define('devmine\consumer\plugin_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR); Terminal::init(); - define('devmine\ANSI', Terminal::hasFormattingCodes()); + define('DevMine\ANSI', Terminal::hasFormattingCodes()); - if(!file_exists(\devmine\DATA)){ - mkdir(\devmine\DATA, 0777, true); + if(!file_exists(\DevMine\DATA)){ + mkdir(\DevMine\DATA, 0777, true); } //Logger has a dependency on timezone, so we'll set it to UTC until we can get the actual timezone. date_default_timezone_set("UTC"); - $logger = new MainLogger(\devmine\DATA . "server.log", \devmine\ANSI); + $logger = new MainLogger(\DevMine\DATA . "server.log", \DevMine\ANSI); if(!ini_get("date.timezone")){ if(($timezone = detect_system_timezone()) and date_default_timezone_set($timezone)){ @@ -132,7 +139,7 @@ function dummy(){ //If system timezone detection fails or timezone is an invalid value. if($response = Utils::getURL("http://ip-api.com/json") and $ip_geolocation_data = json_decode($response, true) - and $ip_geolocation_data['status'] != 'fail' + and $ip_geolocation_data['status'] !== 'fail' and date_default_timezone_set($ip_geolocation_data['timezone']) ){ //Again, for redundancy. @@ -355,13 +362,13 @@ function getTrace($start = 1, $trace = null){ } function cleanPath($path){ - return rtrim(str_replace(["\\", ".php", "phar://", rtrim(str_replace(["\\", "phar://"], ["/", ""], \devmine\PATH), "/"), rtrim(str_replace(["\\", "phar://"], ["/", ""], \devmine\pluginfeatures_PATH), "/")], ["/", "", "", "", ""], $path), "/"); + return rtrim(str_replace(["\\", ".php", "phar://", rtrim(str_replace(["\\", "phar://"], ["/", ""], \DevMine\PATH), "/"), rtrim(str_replace(["\\", "phar://"], ["/", ""], \devmine\consumer\plugin_PATH), "/")], ["/", "", "", "", ""], $path), "/"); } $errors = 0; if(php_sapi_name() !== "cli"){ - $logger->critical("You must run devmine-MP using the CLI."); + $logger->critical("You must run DevMine-MP using the CLI."); ++$errors; } @@ -383,15 +390,24 @@ function cleanPath($path){ //$logger->notice("Couldn't find the uopz extension. Some functions may be limited"); } - if(extension_loaded("devmine")){ - if(version_compare(phpversion("devmine"), "0.0.1") < 0){ - $logger->critical("You have the native devmine extension, but your version is lower than 0.0.1."); + if(extension_loaded("DevMine")){ + if(version_compare(phpversion("DevMine"), "0.0.1") < 0){ + $logger->critical("You have the native DevMine extension, but your version is lower than 0.0.1."); ++$errors; - }elseif(version_compare(phpversion("devmine"), "0.0.4") > 0){ - $logger->critical("You have the native devmine extension, but your version is higher than 0.0.4."); + }elseif(version_compare(phpversion("DevMine"), "0.0.4") > 0){ + $logger->critical("You have the native DevMine extension, but your version is higher than 0.0.4."); ++$errors; } } + + if(extension_loaded("xdebug")){ + $logger->warning(" + + + You are running DevMine with xdebug enabled. This has a major impact on performance. + + "); + } if(!extension_loaded("curl")){ $logger->critical("Unable to find the cURL extension."); @@ -414,34 +430,30 @@ function cleanPath($path){ } if($errors > 0){ - $logger->critical("Please use the installer provided on the homepage, or recompile PHP again."); + $logger->critical("Please update your PHP from itxtech.org/DevMine/get/, or recompile PHP again."); $logger->shutdown(); $logger->join(); exit(1); //Exit with error } - if(file_exists(\devmine\PATH . ".git/refs/heads/master")){ //Found Git information! - define('devmine\GIT_COMMIT', strtolower(trim(file_get_contents(\devmine\PATH . ".git/refs/heads/master")))); + if(file_exists(\DevMine\PATH . ".git/refs/heads/master")){ //Found Git information! + define('DevMine\GIT_COMMIT', strtolower(trim(file_get_contents(\DevMine\PATH . ".git/refs/heads/master")))); }else{ - define('devmine\GIT_COMMIT', "0000000000000000000000000000000000000000"); + define('DevMine\GIT_COMMIT', "0000000000000000000000000000000000000000"); } @define("ENDIANNESS", (pack("d", 1) === "\77\360\0\0\0\0\0\0" ? Binary::BIG_ENDIAN : Binary::LITTLE_ENDIAN)); @define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1); - @ini_set("opcache.mmap_base", bin2hex(Utils::getRandomBytes(8, false))); //Fix OPCache address errors + @ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors $lang = "unknown"; - if(!file_exists(\devmine\DATA . "server.properties") and !isset($opts["no-wizard"])){ + if(!file_exists(\DevMine\DATA . "server.properties") and !isset($opts["no-wizard"])){ $inst = new Installer(); $lang = $inst->getDefaultLang(); } - /*if(\Phar::running(true) === ""){ - $logger->warning("Non-packaged devmine-MP installation detected, do not use on production."); - }*/ - ThreadManager::init(); - $server = new Server($autoloader, $logger, \devmine\PATH, \devmine\DATA, \devmine\pluginfeatures_PATH, $lang); + $server = new Server($autoloader, $logger, \DevMine\PATH, \DevMine\DATA, \devmine\consumer\plugin_PATH, $lang); $logger->info("Stopping other threads"); @@ -450,13 +462,14 @@ function cleanPath($path){ $thread->quit(); } - $killer = new ServerKiller(8); - $killer->start(); - $logger->shutdown(); $logger->join(); - echo "Server has stopped" . Terminal::$FORMAT_RESET . "\n"; + //echo "Server has stopped" . Terminal::$FORMAT_RESET . "\n"; + + $logger->info(Utils::getThreadCount() . " threads has stopped");//add threads count + + $logger->info("Server has stopped"); exit(0); diff --git a/src/devmine/server/MemoryManager.php b/src/devmine/server/MemoryManager.php index 53ee8a2..020f4f0 100644 --- a/src/devmine/server/MemoryManager.php +++ b/src/devmine/server/MemoryManager.php @@ -4,8 +4,8 @@ namespace devmine\server; -use devmine\server\events\server\LowMemoryEvent; -use devmine\server\events\Timings; +use devmine\events\server\LowMemoryEvent; +use devmine\events\Timings; use devmine\server\tasks\GarbageCollectionTask; use devmine\utilities\main\Utils; diff --git a/src/devmine/server/Server.php b/src/devmine/server/Server.php index 839b968..e199a38 100644 --- a/src/devmine/server/Server.php +++ b/src/devmine/server/Server.php @@ -14,7 +14,10 @@ use devmine\creatures\entities\Attribute; use devmine\creatures\entities\Bat; use devmine\creatures\entities\Blaze; +//use devmine\creatures\entities\BlazeFireball; +//use devmine\creatures\entities\BlueWitherSkull; use devmine\creatures\entities\Boat; +//use devmine\creatures\entities\Camera; use devmine\creatures\entities\CaveSpider; use devmine\creatures\entities\Chicken; use devmine\creatures\entities\Cow; @@ -22,15 +25,22 @@ use devmine\creatures\entities\Effect; use devmine\creatures\entities\Egg; use devmine\creatures\entities\Enderman; + +//use devmine\creatures\entities\EnderDragon; + +//use devmine\creatures\entities\ElderGuardian; use devmine\creatures\entities\Entity; use devmine\creatures\entities\FallingSand; use devmine\creatures\entities\FishingHook; use devmine\creatures\entities\Ghast; +//use devmine\creatures\entities\GhastFireball; +//use devmine\creatures\entities\Guardian; use devmine\creatures\entities\Human; use devmine\creatures\entities\Husk; use devmine\creatures\entities\IronGolem; use devmine\creatures\entities\Item as DroppedItem; use devmine\creatures\entities\LavaSlime; +//use devmine\creatures\entities\LeashKnot; use devmine\creatures\entities\Lightning; use devmine\creatures\entities\Minecart; use devmine\creatures\entities\MinecartChest; @@ -56,19 +66,20 @@ use devmine\creatures\entities\ThrownPotion; use devmine\creatures\entities\Villager; use devmine\creatures\entities\Witch; +//use devmine\creatures\entities\Wither; +//use devmine\creatures\entities\WitherSkeleton; use devmine\creatures\entities\Wolf; use devmine\creatures\entities\XPOrb; use devmine\creatures\entities\Zombie; use devmine\creatures\entities\ZombieVillager; -use devmine\creatures\entities\ai\AIHolder; -use devmine\server\events\HandlerList; -use devmine\server\events\level\LevelInitEvent; -use devmine\server\events\level\LevelLoadEvent; -use devmine\server\events\server\QueryRegenerateEvent; -use devmine\server\events\server\ServerCommandEvent; -use devmine\server\events\Timings; -use devmine\server\events\TimingsHandler; -use devmine\server\events\TranslationContainer; +use devmine\events\HandlerList; +use devmine\events\level\LevelInitEvent; +use devmine\events\level\LevelLoadEvent; +use devmine\events\server\QueryRegenerateEvent; +use devmine\events\server\ServerCommandEvent; +use devmine\events\Timings; +use devmine\events\TimingsHandler; +use devmine\events\TranslationContainer; use devmine\inventory\layout\CraftingManager; use devmine\inventory\layout\InventoryType; use devmine\inventory\layout\Recipe; @@ -78,21 +89,20 @@ use devmine\inventory\items\enchantment\EnchantmentLevelTable; use devmine\inventory\items\Item; use devmine\utilities\languages\BaseLang; -use devmine\levels\format\anvil\Anvil; -use devmine\levels\format\leveldb\LevelDB; -use devmine\levels\format\LevelProviderManager; -use devmine\levels\format\mcregion\McRegion; -use devmine\levels\generator\biome\Biome; -use devmine\levels\generator\Flat; -use devmine\levels\generator\Void; -use devmine\levels\generator\Generator; -use devmine\levels\generator\hell\Nether; -use devmine\levels\generator\normal\Normal; -use devmine\levels\generator\normal\Normal2; -use devmine\levels\Level; -use devmine\server\epilogos\EntityepilogosStore; -use devmine\server\epilogos\LevelepilogosStore; -use devmine\server\epilogos\PlayerepilogosStore; +use devmine\worlds\format\region\Anvil; +use devmine\worlds\format\leveldb\LevelDB; +use devmine\worlds\format\LevelProviderManager; +use devmine\worlds\format\region\McRegion; +use devmine\worlds\format\region\PMAnvil; +use devmine\worlds\generator\biome\Biome; +use devmine\worlds\generator\Flat; +use devmine\worlds\generator\Generator; +use devmine\worlds\generator\hell\Nether; +use devmine\worlds\generator\normal\Normal; +use devmine\worlds\Level; +use devmine\server\meta\EntityMetadataStore; +use devmine\server\meta\LevelMetadataStore; +use devmine\server\meta\PlayerMetadataStore; use devmine\creatures\player\NBT; use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\CompoundTag; @@ -105,6 +115,7 @@ use devmine\creatures\player\tag\StringTag; use devmine\server\network\CompressBatchedTask; use devmine\server\network\Network; +use devmine\server\network\protocol\Info; use devmine\server\network\protocol\BatchPacket; use devmine\server\network\protocol\CraftingDataPacket; use devmine\server\network\protocol\DataPacket; @@ -114,19 +125,19 @@ use devmine\server\network\rcon\RCON; use devmine\server\network\SourceInterface; use devmine\server\network\upnp\UPnP; -use devmine\server\permissions\BanList; -use devmine\server\permissions\DefaultPermissions; -use devmine\pluginfeatures\FolderPluginLoader; -use devmine\pluginfeatures\PharPluginLoader; -use devmine\pluginfeatures\Plugin; -use devmine\pluginfeatures\PluginLoadOrder; -use devmine\pluginfeatures\PluginManager; -use devmine\pluginfeatures\ScriptPluginLoader; +use devmine\server\perms\BanList; +use devmine\server\perms\DefaultPermissions; +use devmine\consumer\plugin\PharPluginLoader; +use devmine\consumer\plugin\Plugin; +use devmine\consumer\plugin\PluginLoadOrder; +use devmine\consumer\plugin\PluginManager; +use devmine\consumer\plugin\ScriptPluginLoader; use devmine\server\tasks\CallbackTask; use devmine\server\tasks\DServerTask; use devmine\server\tasks\FileWriteTask; use devmine\server\tasks\SendUsageTask; use devmine\server\tasks\ServerScheduler; +use devmine\inventory\solidentity\Beacon; use devmine\inventory\solidentity\BrewingStand; use devmine\inventory\solidentity\Cauldron; use devmine\inventory\solidentity\Chest; @@ -136,12 +147,12 @@ use devmine\inventory\solidentity\EnchantTable; use devmine\inventory\solidentity\FlowerPot; use devmine\inventory\solidentity\Furnace; +use devmine\inventory\solidentity\Hopper; use devmine\inventory\solidentity\ItemFrame; use devmine\inventory\solidentity\MobSpawner; use devmine\inventory\solidentity\Sign; use devmine\inventory\solidentity\Skull; -use devmine\inventory\solidentity\solidentity; -use devmine\server\updater\AutoUpdater; +use devmine\inventory\solidentity\Tile; use devmine\utilities\main\Binary; use devmine\utilities\main\Color; use devmine\utilities\main\Config; @@ -154,14 +165,16 @@ use devmine\utilities\main\UUID; use devmine\utilities\main\VersionString; -use synapse\Synapse; +//TODO use devmine\worlds\generator\ender\Ender; + + /** * The class that manages everything */ class Server{ - const BROADCAST_CHANNEL_ADMINISTRATIVE = "devmine.broadcast.admin"; - const BROADCAST_CHANNEL_USERS = "devmine.broadcast.user"; + const BROADCAST_CHANNEL_ADMINISTRATIVE = "DevMine.broadcast.admin"; + const BROADCAST_CHANNEL_USERS = "DevMine.broadcast.user"; const PLAYER_MSG_TYPE_MESSAGE = 0; const PLAYER_MSG_TYPE_TIP = 1; @@ -198,9 +211,6 @@ class Server{ private $profilingTickRate = 20; - /** @var AutoUpdater */ - private $updater = null; - /** @var ServerScheduler */ private $scheduler = null; @@ -248,14 +258,14 @@ class Server{ /** @var RCON */ private $rcon; - /** @var EntityepilogosStore */ - private $entityepilogos; + /** @var EntityMetadataStore */ + private $entityMetadata; - /** @var PlayerepilogosStore */ - private $playerepilogos; + /** @var PlayerMetadataStore */ + private $playerMetadata; - /** @var LevelepilogosStore */ - private $levelepilogos; + /** @var LevelMetadataStore */ + private $levelMetadata; /** @var Network */ private $network; @@ -313,7 +323,7 @@ class Server{ /** @var Level */ private $levelDefault = null; - public $aboutstring = ""; + private $aboutContent = ""; /** Advanced Config */ public $advancedConfig = null; @@ -327,36 +337,18 @@ class Server{ public $netherLevel = null; public $weatherRandomDurationMin = 6000; public $weatherRandomDurationMax = 12000; - public $hungerHealth = 10; public $lightningTime = 200; public $lightningFire = false; - public $expCache = []; - public $expWriteAhead = 200; - public $aiConfig = []; - public $aiEnabled = false; - public $aiHolder = null; - public $inventoryNum = 36; - public $hungerTimer = 80; public $version; - public $allowSnowGolem; - public $allowIronGolem; + public $playerMsgType = self::PLAYER_MSG_TYPE_MESSAGE; + public $playerLoginMsg = ""; + public $playerLogoutMsg = ""; public $autoClearInv = true; public $dserverConfig = []; public $dserverPlayers = 0; public $dserverAllPlayers = 0; - public $redstoneEnabled = false; - public $allowFrequencyPulse = true; public $anvilEnabled = false; - public $pulseFrequency = 20; - public $playerMsgType = self::PLAYER_MSG_TYPE_MESSAGE; - public $playerLoginMsg = ""; - public $playerLogoutMsg = ""; - public $antiFly = false; public $asyncChunkRequest = true; - public $recipesFromJson = false; - public $creativeItemsFromJson = false; - public $minecartMovingType = 0; - public $checkMovement = false; public $keepExperience = false; public $limitedCreative = true; public $chunkRadius = -1; @@ -364,21 +356,18 @@ class Server{ public $allowSplashPotion = true; public $fireSpread = false; public $advancedCommandSelector = false; - public $synapseConfig = []; public $enchantingTableEnabled = true; public $countBookshelf = false; + public $allowInventoryCheats = false; /** @var CraftingDataPacket */ private $recipeList = null; - - /** @var Synapse */ - private $synapse = null; - + /** * @return string */ public function getName() : string{ - return "devmine"; + return "DevMine"; } /** @@ -387,13 +376,13 @@ public function getName() : string{ public function isRunning(){ return $this->isRunning === true; } - + /** * @return string * Returns a formatted string of how long the server has been running for */ public function getUptime(){ - $time = microtime(true) - \devmine\START_TIME; + $time = microtime(true) - \DevMine\START_TIME; $seconds = floor($time % 60); $minutes = null; @@ -413,54 +402,43 @@ public function getUptime(){ $uptime = ($minutes !== null ? ($hours !== null ? ($days !== null ? - "$days " . $this->getLanguage()->translateString("%devmine.command.status.days") . " " - : "") . "$hours " . $this->getLanguage()->translateString("%devmine.command.status.hours") . " " - : "") . "$minutes " . $this->getLanguage()->translateString("%devmine.command.status.minutes") . " " - : "") . "$seconds " . $this->getLanguage()->translateString("%devmine.command.status.seconds"); + "$days " . $this->getLanguage()->translateString("%DevMine.command.status.days") . " " + : "") . "$hours " . $this->getLanguage()->translateString("%DevMine.command.status.hours") . " " + : "") . "$minutes " . $this->getLanguage()->translateString("%DevMine.command.status.minutes") . " " + : "") . "$seconds " . $this->getLanguage()->translateString("%DevMine.command.status.seconds"); return $uptime; } /** * @return string */ - public function getdevmineVersion(){ - return \devmine\VERSION; + public function getDevMineVersion(){ + return \DevMine\VERSION; + } + + public function getFormattedVersion($prefix = ""){ + return (\DevMine\VERSION !== ""? $prefix . \DevMine\VERSION : ""); } /** * @return string */ public function getCodename(){ - return \devmine\CODENAME; + return \DevMine\CODENAME; } /** * @return string */ public function getVersion(){ - return \devmine\MINECRAFT_VERSION; + return Info::MINECRAFT_VERSION; } /** * @return string */ public function getApiVersion(){ - return \devmine\API_VERSION; - } - - - /** - * @return string - */ - public function getiTXApiVersion(){ - return \devmine\devmine_API_VERSION; - } - - /** - * @return string - */ - public function getGeniApiVersion(){ - return \devmine\devmine_API_VERSION; + return \DevMine\API_VERSION; } /** @@ -512,13 +490,6 @@ public function getIp(){ return $this->getConfigString("server-ip", "0.0.0.0"); } - /** - * @deprecated - */ - public function getServerName(){ - return $this->getConfigString("motd", "Minecraft: PE Server"); - } - public function getServerUniqueId(){ return $this->serverID; } @@ -717,31 +688,24 @@ public function getLogger(){ } /** - * @return EntityepilogosStore - */ - public function getEntityepilogos(){ - return $this->entityepilogos; - } - - /** - * @return PlayerepilogosStore + * @return EntityMetadataStore */ - public function getPlayerepilogos(){ - return $this->playerepilogos; + public function getEntityMetadata(){ + return $this->entityMetadata; } /** - * @return LevelepilogosStore + * @return PlayerMetadataStore */ - public function getLevelepilogos(){ - return $this->levelepilogos; + public function getPlayerMetadata(){ + return $this->playerMetadata; } /** - * @return AutoUpdater + * @return LevelMetadataStore */ - public function getUpdater(){ - return $this->updater; + public function getLevelMetadata(){ + return $this->levelMetadata; } /** @@ -772,10 +736,6 @@ public function getTick(){ return $this->tickCounter; } - public function getAIHolder(){ - return $this->aiHolder; - } - /** * Returns the last server TPS measure * @@ -812,56 +772,6 @@ public function getTickUsageAverage(){ return round((array_sum($this->useAverage) / count($this->useAverage)) * 100, 2); } - - /** - * @deprecated - * - * @param $address - * @param int $timeout - */ - public function blockAddress($address, $timeout = 300){ - $this->network->blockAddress($address, $timeout); - } - - /** - * @deprecated - * - * @param $address - * @param $port - * @param $payload - */ - public function sendPacket($address, $port, $payload){ - $this->network->sendPacket($address, $port, $payload); - } - - /** - * @deprecated - * - * @return SourceInterface[] - */ - public function getInterfaces(){ - return $this->network->getInterfaces(); - } - - /** - * @deprecated - * - * @param SourceInterface $interface - */ - public function addInterface(SourceInterface $interface){ - $this->network->registerInterface($interface); - } - - /** - * @deprecated - * - * @param SourceInterface $interface - */ - public function removeInterface(SourceInterface $interface){ - $interface->shutdown(); - $this->network->unregisterInterface($interface); - } - /** * @return SimpleCommandMap */ @@ -881,6 +791,10 @@ public function addRecipe(Recipe $recipe){ $this->generateRecipeList(); } + public function shouldSavePlayerData() : bool{ + return (bool) $this->getProperty("player.save-player-data", true); + } + /** * @param string $name * @@ -905,18 +819,20 @@ public function getOfflinePlayer($name){ public function getOfflinePlayerData($name){ $name = strtolower($name); $path = $this->getDataPath() . "players/"; - if(file_exists($path . "$name.dat")){ - try{ - $nbt = new NBT(NBT::BIG_ENDIAN); - $nbt->readCompressed(file_get_contents($path . "$name.dat")); - - return $nbt->getData(); - }catch(\Throwable $e){ //zlib decode error / corrupt data - rename($path . "$name.dat", $path . "$name.dat.bak"); - $this->logger->notice($this->getLanguage()->translateString("devmine.data.playerCorrupted", [$name])); + if($this->shouldSavePlayerData()){ + if(file_exists($path . "$name.dat")){ + try{ + $nbt = new NBT(NBT::BIG_ENDIAN); + $nbt->readCompressed(file_get_contents($path . "$name.dat")); + + return $nbt->getData(); + }catch(\Throwable $e){ //zlib decode error / corrupt data + rename($path . "$name.dat", $path . "$name.dat.bak"); + $this->logger->notice($this->getLanguage()->translateString("DevMine.data.playerCorrupted", [$name])); + } + }else{ + $this->logger->notice($this->getLanguage()->translateString("DevMine.data.playerNotFound", [$name])); } - }else{ - $this->logger->notice($this->getLanguage()->translateString("devmine.data.playerNotFound", [$name])); } $spawn = $this->getDefaultLevel()->getSafeSpawn(); $nbt = new CompoundTag("", [ @@ -951,18 +867,15 @@ public function getOfflinePlayerData($name){ new ByteTag("OnGround", 1), new ByteTag("Invulnerable", 0), new StringTag("NameTag", $name), - new ShortTag("Hunger", 20), new ShortTag("Health", 20), new ShortTag("MaxHealth", 20), - new LongTag("Experience", 0), - new LongTag("ExpLevel", 0), ]); $nbt->Pos->setTagType(NBT::TAG_Double); $nbt->Inventory->setTagType(NBT::TAG_Compound); $nbt->Motion->setTagType(NBT::TAG_Double); $nbt->Rotation->setTagType(NBT::TAG_Float); - /*if(file_exists($path . "$name.yml")){ //Importing old devmine-MP files + /*if(file_exists($path . "$name.yml")){ //Importing old DevMine-MP files $data = new Config($path . "$name.yml", Config::YAML, []); $nbt["playerGameType"] = (int) $data->get("gamemode"); $nbt["Level"] = $data->get("position")["level"]; @@ -973,7 +886,7 @@ public function getOfflinePlayerData($name){ $nbt["SpawnX"] = (int) $data->get("spawn")["x"]; $nbt["SpawnY"] = (int) $data->get("spawn")["y"]; $nbt["SpawnZ"] = (int) $data->get("spawn")["z"]; - $this->logger->notice($this->getLanguage()->translateString("devmine.data.playerOld", [$name])); + $this->logger->notice($this->getLanguage()->translateString("DevMine.data.playerOld", [$name])); foreach($data->get("inventory") as $slot => $item){ if(count($item) === 3){ $nbt->Inventory[$slot + 9] = new CompoundTag("", [ @@ -1024,18 +937,18 @@ public function getOfflinePlayerData($name){ * @param bool $async */ public function saveOfflinePlayerData($name, CompoundTag $nbtTag, $async = false){ - $nbt = new NBT(NBT::BIG_ENDIAN); - try{ - $nbt->setData($nbtTag); + if($this->shouldSavePlayerData()){ + $nbt = new NBT(NBT::BIG_ENDIAN); + try{ + $nbt->setData($nbtTag); - if($async){ - $this->getScheduler()->scheduleAsyncTask(new FileWriteTask($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed())); - }else{ - file_put_contents($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed()); - } - }catch(\Throwable $e){ - $this->logger->critical($this->getLanguage()->translateString("devmine.data.saveError", [$name, $e->getMessage()])); - if(\devmine\DEBUG > 1 and $this->logger instanceof MainLogger){ + if($async){ + $this->getScheduler()->scheduleAsyncTask(new FileWriteTask($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed())); + }else{ + file_put_contents($this->getDataPath() . "players/" . strtolower($name) . ".dat", $nbt->writeCompressed()); + } + }catch(\Throwable $e){ + $this->logger->critical($this->getLanguage()->translateString("DevMine.data.saveError", [$name, $e->getMessage()])); $this->logger->logException($e); } } @@ -1221,7 +1134,7 @@ public function loadLevel($name){ if($this->isLevelLoaded($name)){ return true; }elseif(!$this->isLevelGenerated($name)){ - $this->logger->notice($this->getLanguage()->translateString("devmine.level.notFound", [$name])); + $this->logger->notice($this->getLanguage()->translateString("DevMine.level.notFound", [$name])); return false; } @@ -1231,20 +1144,20 @@ public function loadLevel($name){ $provider = LevelProviderManager::getProvider($path); if($provider === null){ - $this->logger->error($this->getLanguage()->translateString("devmine.level.loadError", [$name, "Unknown provider"])); + $this->logger->error($this->getLanguage()->translateString("DevMine.level.loadError", [$name, "Unknown provider"])); return false; } //$entities = new Config($path."entities.yml", Config::YAML); - //if(file_exists($path . "solidentityEntities.yml")){ - // @rename($path . "solidentityEntities.yml", $path . "solidentities.yml"); + //if(file_exists($path . "tileEntities.yml")){ + // @rename($path . "tileEntities.yml", $path . "tiles.yml"); //} try{ $level = new Level($this, $name, $path, $provider); }catch(\Throwable $e){ - $this->logger->error($this->getLanguage()->translateString("devmine.level.loadError", [$name, $e->getMessage()])); + $this->logger->error($this->getLanguage()->translateString("DevMine.level.loadError", [$name, $e->getMessage()])); if($this->logger instanceof MainLogger){ $this->logger->logException($e); } @@ -1267,7 +1180,7 @@ public function loadLevel($name){ * * @param string $name * @param int $seed - * @param string $generator Class name that extends devmine\levels\generator\Noise + * @param string $generator Class name that extends devmine\worlds\generator\Noise * @param array $options * * @return bool @@ -1277,7 +1190,7 @@ public function generateLevel($name, $seed = null, $generator = null, $options = return false; } - $seed = $seed === null ? Binary::readInt(@Utils::getRandomBytes(4, false)) : (int) $seed; + $seed = $seed === null ? Binary::readInt(random_bytes(4)) : (int) $seed; if(!isset($options["preset"])){ $options["preset"] = $this->getConfigString("generator-settings", ""); @@ -1287,13 +1200,13 @@ public function generateLevel($name, $seed = null, $generator = null, $options = $generator = Generator::getGenerator($this->getLevelType()); } - if(($provider = LevelProviderManager::getProviderByName($providerName = $this->getProperty("level-settings.default-format", "mcregion"))) === null){ - $provider = LevelProviderManager::getProviderByName($providerName = "mcregion"); + if(($provider = LevelProviderManager::getProviderByName($providerName = $this->getProperty("level-settings.default-format", "pmanvil"))) === null){ + $provider = LevelProviderManager::getProviderByName($providerName = "anvil"); } try{ $path = $this->getDataPath() . "worlds/" . $name . "/"; - /** @var \devmine\levels\format\LevelProvider $provider */ + /** @var \devmine\worlds\format\LevelProvider $provider */ $provider::generate($path, $name, $seed, $generator, $options); $level = new Level($this, $name, $path, $provider); @@ -1303,7 +1216,7 @@ public function generateLevel($name, $seed = null, $generator = null, $options = $level->setTickRate($this->baseTickRate); }catch(\Throwable $e){ - $this->logger->error($this->getLanguage()->translateString("devmine.level.generateError", [$name, $e->getMessage()])); + $this->logger->error($this->getLanguage()->translateString("DevMine.level.generateError", [$name, $e->getMessage()])); if($this->logger instanceof MainLogger){ $this->logger->logException($e); } @@ -1314,7 +1227,7 @@ public function generateLevel($name, $seed = null, $generator = null, $options = $this->getPluginManager()->callEvent(new LevelLoadEvent($level)); - $this->getLogger()->notice($this->getLanguage()->translateString("devmine.level.backgroundGeneration", [$name])); + $this->getLogger()->notice($this->getLanguage()->translateString("DevMine.level.backgroundGeneration", [$name])); $centerX = $level->getSpawnLocation()->getX() >> 4; $centerZ = $level->getSpawnLocation()->getZ() >> 4; @@ -1522,7 +1435,7 @@ public function removeOp($name){ $this->operators->remove($opName); } } - + if(($player = $this->getPlayerExact($name)) !== null){ $player->recalculatePermissions(); } @@ -1620,19 +1533,6 @@ public static function microSleep(int $microseconds){ }, $microseconds); } - public function getExpectedExperience($level){ - if(isset($this->expCache[$level])) return $this->expCache[$level]; - $levelSquared = $level ** 2; - if($level < 16) $this->expCache[$level] = $levelSquared + 6 * $level; - elseif($level < 31) $this->expCache[$level] = 2.5 * $levelSquared - 40.5 * $level + 360; - else $this->expCache[$level] = 4.5 * $levelSquared - 162.5 * $level + 2220; - return $this->expCache[$level]; - } - - public function about(){ - $this->logger->info($this->aboutstring); - } - public function loadAdvancedConfig(){ $this->playerMsgType = $this->getAdvancedProperty("server.player-msg-type", self::PLAYER_MSG_TYPE_MESSAGE); $this->playerLoginMsg = $this->getAdvancedProperty("server.login-msg", "§3@player joined the game"); @@ -1642,31 +1542,12 @@ public function loadAdvancedConfig(){ $this->expEnabled = $this->getAdvancedProperty("player.experience", true); $this->keepInventory = $this->getAdvancedProperty("player.keep-inventory", false); $this->keepExperience = $this->getAdvancedProperty("player.keep-experience", false); - $this->netherEnabled = $this->getAdvancedProperty("nether.allow-nether", false); - $this->netherName = $this->getAdvancedProperty("nether.level-name", "nether"); + $this->netherEnabled = $this->getAdvancedProperty("level.allow-nether", false); + $this->netherName = $this->getAdvancedProperty("level.level-name", "nether"); $this->weatherRandomDurationMin = $this->getAdvancedProperty("level.weather-random-duration-min", 6000); $this->weatherRandomDurationMax = $this->getAdvancedProperty("level.weather-random-duration-max", 12000); - $this->hungerHealth = $this->getAdvancedProperty("player.hunger-health", 10); $this->lightningTime = $this->getAdvancedProperty("level.lightning-time", 200); $this->lightningFire = $this->getAdvancedProperty("level.lightning-fire", false); - $this->expWriteAhead = $this->getAdvancedProperty("server.experience-cache", 200); - $this->aiEnabled = $this->getAdvancedProperty("ai.enable", false); - $this->aiConfig = [ - "cow" => $this->getAdvancedProperty("ai.cow", true), - "chicken" => $this->getAdvancedProperty("ai.chicken", true), - "zombie" => $this->getAdvancedProperty("ai.zombie", 1), - "skeleton" => $this->getAdvancedProperty("ai.skeleton", true), - "pig" => $this->getAdvancedProperty("ai.pig", true), - "sheep" => $this->getAdvancedProperty("ai.sheep", true), - "creeper" => $this->getAdvancedProperty("ai.creeper", true), - "irongolem" => $this->getAdvancedProperty("ai.iron-golem", true), - "snowgolem" => $this->getAdvancedProperty("ai.snow-golem", true), - "pigzombie" => $this->getAdvancedProperty("ai.pigzombie", true), - "creeperexplode" => $this->getAdvancedProperty("ai.creeper-explode-destroy-block", false), - "mobgenerate" => $this->getAdvancedProperty("ai.mobgenerate", false), - ]; - $this->inventoryNum = min(91, $this->getAdvancedProperty("player.inventory-num", 36)); - $this->hungerTimer = $this->getAdvancedProperty("player.hunger-timer", 80); $this->allowSnowGolem = $this->getAdvancedProperty("server.allow-snow-golem", false); $this->allowIronGolem = $this->getAdvancedProperty("server.allow-iron-golem", false); $this->autoClearInv = $this->getAdvancedProperty("player.auto-clear-inventory", true); @@ -1684,40 +1565,35 @@ public function loadAdvancedConfig(){ "retryTimes" => $this->getAdvancedProperty("dserver.retry-times", 3), "serverList" => explode(";", $this->getAdvancedProperty("dserver.server-list", "")) ]; - $this->redstoneEnabled = $this->getAdvancedProperty("redstone.enable", false); - $this->allowFrequencyPulse = $this->getAdvancedProperty("redstone.allow-frequency-pulse", false); - $this->pulseFrequency = $this->getAdvancedProperty("redstone.pulse-frequency", 20); $this->getLogger()->setWrite(!$this->getAdvancedProperty("server.disable-log", false)); - $this->antiFly = $this->getAdvancedProperty("server.anti-fly", true); $this->asyncChunkRequest = $this->getAdvancedProperty("server.async-chunk-request", true); - $this->recipesFromJson = $this->getAdvancedProperty("server.recipes-from-json", false); - $this->creativeItemsFromJson = $this->getAdvancedProperty("server.creative-items-from-json", false); - $this->minecartMovingType = $this->getAdvancedProperty("server.minecart-moving-type", 0); - $this->checkMovement = $this->getAdvancedProperty("server.check-movement", true); $this->limitedCreative = $this->getAdvancedProperty("server.limited-creative", true); $this->chunkRadius = $this->getAdvancedProperty("player.chunk-radius", -1); $this->destroyBlockParticle = $this->getAdvancedProperty("server.destroy-block-particle", true); $this->allowSplashPotion = $this->getAdvancedProperty("server.allow-splash-potion", true); $this->fireSpread = $this->getAdvancedProperty("level.fire-spread", false); $this->advancedCommandSelector = $this->getAdvancedProperty("server.advanced-command-selector", false); - $this->synapseConfig = [ - "enabled" => $this->getAdvancedProperty("synapse.enabled", false), - "server-ip" => $this->getAdvancedProperty("synapse.server-ip", "127.0.0.1"), - "server-port" => $this->getAdvancedProperty("synapse.server-port", 10305), - "isMainServer" => $this->getAdvancedProperty("synapse.is-main-server", true), - "password" => $this->getAdvancedProperty("synapse.server-password", "123456"), - "description" => $this->getAdvancedProperty("synapse.description", "A Synapse client"), - "disable-rak" => $this->getAdvancedProperty("synapse.disable-rak", false), - ]; $this->anvilEnabled = $this->getAdvancedProperty("enchantment.enable-anvil", true); $this->enchantingTableEnabled = $this->getAdvancedProperty("enchantment.enable-enchanting-table", true); $this->countBookshelf = $this->getAdvancedProperty("enchantment.count-bookshelf", false); - } - public function isSynapseEnabled() : bool { - return (bool) $this->synapseConfig["enabled"]; + $this->allowInventoryCheats = $this->getAdvancedProperty("inventory.allow-cheats", false); + } - + + /** + * API for checking if PROXY is enabled + */ + public function isProxyEnabled(){ + $plugin = null;//$this->pluginManager->getPlugin('WingProxy'); + + if($plugin == null or $plugin->isDisabled()){ + return 'false'; + } else { + return 'true'; + } + } + /** * @return int * @@ -1744,12 +1620,6 @@ public function updateDServerInfo(){ $this->scheduler->scheduleAsyncTask(new DServerTask($this->dserverConfig["serverList"], $this->dserverConfig["retryTimes"])); } - public function generateExpCache($level){ - for($i = 0; $i <= $level; $i++){ - $this->getExpectedExperience($i); - } - } - public function getBuild(){ return $this->version->getBuild(); } @@ -1788,39 +1658,57 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ if(!file_exists($dataPath . "crashdumps/")){ mkdir($dataPath . "crashdumps/", 0777); } + + if(\Phar::running(true) === ""){ + $packages = "src"; + } else { + $packages = "phar"; + } $this->dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR; $this->pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR; + if(!file_exists($this->dataPath . "DevMine.yml")){ + $content = file_get_contents($this->filePath . "src/devmine/server/resources/DevMine.yml"); + @file_put_contents($this->dataPath . "DevMine.yml", $content); + } + $this->config = new Config($configPath = $this->dataPath . "DevMine.yml", Config::YAML, []); $this->console = new CommandReader($logger); - $version = new VersionString($this->getdevmineVersion()); + $version = new VersionString($this->getDevMineVersion()); $this->version = $version; + $mcpe = $this->getVersion() . " §c(Protocol: §d" . Info::CURRENT_PROTOCOL . "§c)"; + $code = $this->getCodename(); + $api = $this->getApiVersion(); + $ip = Utils::getIP(); + $port = "19132"; + $proxy = $this->isProxyEnabled(); + $ssl = $this->isExtensionInstalled("OpenSSL"); + $mode = $this->checkAuthentication(); + $lang = $this->getProperty("settings.language", "eng"); + $package = $packages; + + $this->logger->info(" +§e################################################### §6-- Loaded: Properties and Configuration -- +§e# # §cVersion: §d$version +§e#§b _______ _ §e# §cMCPE: §d$mcpe +§e#§b |__ __| | | §e# §cIP: §d$ip §cPort: §d$port +§e#§b | | ___ ___ ___ ___ _ __ __ _ ___| |_ §e# §cProxy Enabled: §d$proxy +§e#§b | |/ _ \/ __/ __|/ _ \ '__/ _` |/ __| __| §e# §cSSL Extension: §d$ssl +§e#§b | | __/\__ \__ \ __/ | | (_| | (__| |_ §e# §cAuthentication: §d$mode +§e#§b |_|\___||___/___/\___|_| \__,_|\___|\__| §e# ------------------------------------------ +§e# # §cCodename: §d$code +§e# # §cAPI Version: §d$api +§e# §bwww.github.com/DevMineTeam/DevMine §e# §cLanguage: §d$lang +§e# # §cPackage: §d$package +§e################################################### ------------------------------------------"); - - $this->aboutstring = "\n - §5devmine-iTX §3devmine §fis a fork of devmine-MP, made by §5iTX Technologies LLC§f. - §fVersion: §6" . $this->getdevmineVersion() . " - §fTarget client Version: §d" . \devmine\MINECRAFT_VERSION . " - §fLatest source code is available at https://github.com/iTXTech/devmine - §fDonate link: http://pl.zxda.net/plugins/203.html - \n"; - - $this->about(); - - $this->logger->info("Loading devmine.yml..."); - if(!file_exists($this->dataPath . "devmine.yml")){ - $content = file_get_contents($this->filePath . "src/devmine/resources/devmine.yml"); - if($version->isDev()){ - $content = str_replace("preferred-channel: stable", "preferred-channel: beta", $content); - } - @file_put_contents($this->dataPath . "devmine.yml", $content); - } - $this->config = new Config($configPath = $this->dataPath . "devmine.yml", Config::YAML, []); $nowLang = $this->getProperty("settings.language", "eng"); - if(strpos(\devmine\VERSION, "unsupported") !== false and getenv("GITLAB_CI") === false){ + + //Crashes unsupported builds without the correct configuration + if(strpos(\DevMine\VERSION, "unsupported") !== false and getenv("GITLAB_CI") === false){ if($this->getProperty("settings.enable-testing", false) !== true){ - throw new ServerException("This build is not intended for production use. You may set 'settings.enable-testing: true' under devmine.yml to allow use of non-production builds. Do so at your own risk and ONLY if you know what you are doing."); + throw new ServerException("This build is not intended for production use. You may set 'settings.enable-testing: true' under DevMine.yml to allow use of non-production builds. Do so at your own risk and ONLY if you know what you are doing."); }else{ $this->logger->warning("You are using an unsupported build. Do not use this build in a production environment."); } @@ -1831,30 +1719,23 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ unset($this->propertyCache["settings.language"]); } - $this->logger->info("Loading devmine.yml..."); - $lang = $this->getProperty("settings.language", BaseLang::FALLBACK_LANGUAGE); - if(file_exists($this->filePath . "src/devmine/resources/devmine_$lang.yml")){ - $content = file_get_contents($file = $this->filePath . "src/devmine/resources/devmine_$lang.yml"); + if(file_exists($this->filePath . "src/devmine/server/resources/DevMine_$lang.yml")){ + $content = file_get_contents($file = $this->filePath . "src/devmine/server/resources/DevMine_$lang.yml"); }else{ - $content = file_get_contents($file = $this->filePath . "src/devmine/resources/devmine_eng.yml"); + $content = file_get_contents($file = $this->filePath . "src/devmine/server/resources/DevMine_eng.yml"); } - if(!file_exists($this->dataPath . "devmine.yml")){ - @file_put_contents($this->dataPath . "devmine.yml", $content); + if(!file_exists($this->dataPath . "DevMine.yml")){ + @file_put_contents($this->dataPath . "DevMine.yml", $content); } $internelConfig = new Config($file, Config::YAML, []); - $this->advancedConfig = new Config($this->dataPath . "devmine.yml", Config::YAML, []); + $this->advancedConfig = new Config($this->dataPath . "DevMine.yml", Config::YAML, []); $cfgVer = $this->getAdvancedProperty("config.version", 0, $internelConfig); $advVer = $this->getAdvancedProperty("config.version", 0); $this->loadAdvancedConfig(); - if($this->expWriteAhead > 0){ - $this->generateExpCache($this->expWriteAhead); - } - - $this->logger->info("Loading server properties..."); $this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, [ "motd" => "Minecraft: PE Server", "server-port" => 19132, @@ -1876,18 +1757,17 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ "level-type" => "DEFAULT", "enable-query" => true, "enable-rcon" => false, - "rcon.password" => substr(base64_encode(@Utils::getRandomBytes(20, false)), 3, 10), + "rcon.password" => substr(base64_encode(random_bytes(20)), 3, 10), "auto-save" => true, + "online-mode" => false, ]); + $this->forceLanguage = $this->getProperty("settings.force-language", false); $this->baseLang = new BaseLang($this->getProperty("settings.language", BaseLang::FALLBACK_LANGUAGE)); - $this->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()])); $this->memoryManager = new MemoryManager($this); - $this->logger->info($this->getLanguage()->translateString("devmine.server.start", [TextFormat::AQUA . $this->getVersion(). TextFormat::WHITE])); - if(($poolSize = $this->getProperty("settings.async-workers", "auto")) === "auto"){ $poolSize = ServerScheduler::$WORKERS; $processors = Utils::getCoreCount() - 2; @@ -1918,9 +1798,9 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ $this->rcon = new RCON($this, $this->getConfigString("rcon.password", ""), $this->getConfigInt("rcon.port", $this->getPort()), ($ip = $this->getIp()) != "" ? $ip : "0.0.0.0", $this->getConfigInt("rcon.threads", 1), $this->getConfigInt("rcon.clients-per-thread", 50)); } - $this->entityepilogos = new EntityepilogosStore(); - $this->playerepilogos = new PlayerepilogosStore(); - $this->levelepilogos = new LevelepilogosStore(); + $this->entityMetadata = new EntityMetadataStore(); + $this->playerMetadata = new PlayerMetadataStore(); + $this->levelMetadata = new LevelMetadataStore(); $this->operators = new Config($this->dataPath . "ops.txt", Config::ENUM); $this->whitelist = new Config($this->dataPath . "white-list.txt", Config::ENUM); @@ -1944,17 +1824,16 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ $this->setConfigInt("difficulty", 3); } - define("devmine\\DEBUG", (int) $this->getProperty("debug.level", 1)); + define("DevMine\\DEBUG", (int) $this->getProperty("debug.level", 1)); if($this->logger instanceof MainLogger){ - $this->logger->setLogDebug(\devmine\DEBUG > 1); + $this->logger->setLogDebug(\DevMine\DEBUG > 1); } - if(\devmine\DEBUG >= 0){ - @cli_set_process_title($this->getName() . " " . $this->getdevmineVersion()); + if(\DevMine\DEBUG >= 0){ + @cli_set_process_title($this->getName() . " " . $this->getDevMineVersion()); } - $this->logger->info($this->getLanguage()->translateString("devmine.server.networkStart", [$this->getIp() === "" ? "*" : $this->getIp(), $this->getPort()])); - define("BOOTUP_RANDOM", @Utils::getRandomBytes(16)); + $this->logger->info(TextFormat::BLUE."Everything seems to be alright. Server started!"); $this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort()); $this->getLogger()->debug("Server unique id: " . $this->getServerUniqueId()); @@ -1964,64 +1843,49 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ $this->network->setName($this->getMotd()); - $this->logger->info($this->getLanguage()->translateString("devmine.server.info", [ - $this->getName(), - $this->getdevmineVersion(), - $this->getCodename(), - $this->getApiVersion() - ])); - $this->logger->info($this->getLanguage()->translateString("devmine.server.license", [$this->getName()])); - Timings::init(); $this->consoleSender = new ConsoleCommandSender(); $this->commandMap = new SimpleCommandMap($this); $this->registerEntities(); - $this->registersolidentities(); + $this->registerTiles(); - InventoryType::init($this->inventoryNum); + InventoryType::init(); Block::init(); Enchantment::init(); - Item::init($this->creativeItemsFromJson); + Item::init(); Biome::init(); Effect::init(); Attribute::init(); EnchantmentLevelTable::init(); Color::init(); - //TextWrapper::init(); - $this->craftingManager = new CraftingManager($this->recipesFromJson); + $this->craftingManager = new CraftingManager(); $this->pluginManager = new PluginManager($this, $this->commandMap); $this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender); $this->pluginManager->setUseTimings($this->getProperty("settings.enable-profiling", false)); $this->profilingTickRate = (float) $this->getProperty("settings.profile-report-trigger", 20); $this->pluginManager->registerInterface(PharPluginLoader::class); - $this->pluginManager->registerInterface(FolderPluginLoader::class); $this->pluginManager->registerInterface(ScriptPluginLoader::class); //set_exception_handler([$this, "exceptionHandler"]); register_shutdown_function([$this, "crashDump"]); $this->queryRegenerateTask = new QueryRegenerateEvent($this, 5); - - if(!$this->synapseConfig["enabled"] or ($this->synapseConfig["enabled"] and !$this->synapseConfig["disable-rak"])){ - $this->network->registerInterface(new RakLibInterface($this)); - }else{ - $this->logger->notice("RakLib has been disabled by synapse.disable-rak option"); - } - + $this->pluginManager->loadPlugins($this->pluginPath); - $this->updater = new AutoUpdater($this, $this->getProperty("auto-updater.host", "www.devmine.net")); - $this->enablePlugins(PluginLoadOrder::STARTUP); + + $this->network->registerInterface(new RakLibInterface($this)); - LevelProviderManager::addProvider($this, Anvil::class); - LevelProviderManager::addProvider($this, McRegion::class); + LevelProviderManager::addProvider(Anvil::class); + LevelProviderManager::addProvider(PMAnvil::class); + LevelProviderManager::addProvider(McRegion::class); if(extension_loaded("leveldb")){ - $this->logger->debug($this->getLanguage()->translateString("devmine.debug.enable")); - LevelProviderManager::addProvider($this, LevelDB::class); + $this->logger->debug($this->getLanguage()->translateString("DevMine.debug.enable")); + LevelProviderManager::addProvider(LevelDB::class); } @@ -2030,8 +1894,7 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ Generator::addGenerator(Normal::class, "default"); Generator::addGenerator(Nether::class, "hell"); Generator::addGenerator(Nether::class, "nether"); - Generator::addGenerator(Void::class, "void"); - Generator::addGenerator(Normal2::class, "normal2"); + //TODO Generator::addGenerator(Ender::class, "ender"); foreach((array) $this->getProperty("worlds", []) as $name => $worldSetting){ if($this->loadLevel($name) === false){ @@ -2074,7 +1937,7 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ $this->properties->save(true); if(!($this->getDefaultLevel() instanceof Level)){ - $this->getLogger()->emergency($this->getLanguage()->translateString("devmine.level.defaultError")); + $this->getLogger()->emergency($this->getLanguage()->translateString("DevMine.level.defaultError")); $this->forceShutdown(); return; @@ -2082,7 +1945,6 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ if($this->netherEnabled){ if(!$this->loadLevel($this->netherName)){ - //$this->logger->info("正在生成地狱 ".$this->netherName); $this->generateLevel($this->netherName, time(), Generator::getGenerator("nether")); } $this->netherLevel = $this->getLevelByName($this->netherName); @@ -2094,18 +1956,14 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ $this->enablePlugins(PluginLoadOrder::POSTWORLD); - if($this->aiEnabled) $this->aiHolder = new AIHolder($this); if($this->dserverConfig["enable"] and ($this->getAdvancedProperty("dserver.server-list", "") != "")) $this->scheduler->scheduleRepeatingTask(new CallbackTask([ $this, "updateDServerInfo" ]), $this->dserverConfig["timer"]); + - if($this->isSynapseEnabled()){ - $this->synapse = new Synapse($this, $this->synapseConfig); - } - - if($cfgVer != $advVer){ - $this->logger->notice("Your devmine.yml needs update"); + if($cfgVer > $advVer){ + $this->logger->notice("Your DevMine.yml needs update"); $this->logger->notice("Current Version: $advVer Latest Version: $cfgVer"); } @@ -2118,12 +1976,54 @@ public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, $ } /** - * @return Synapse + * @return WingProxy */ - public function getSynapse(){ - return $this->synapse; + + public function getProxy(){ + if($this->isProxyEnabled() == false){ + throw new \InvalidStateException("ERROR: Proxy is not enabled"); + + } else { + return $this->pluginManager()->getPlugin("WingProxy"); + } } + public function getOnlineMode(){ + + return $this->getConfigBoolean("online-mode", false); + + } + + public function isExtensionInstalled($type){ + switch($type){ + + case 'OpenSSL': + if(!extension_loaded("openssl")){ + return "false"; + $this->setConfigBool("online-mode", false); + + } else { + return "true"; + break; + } + case '$type'; + if(!extension_loaded($type)){ + return "false"; + + } else { + return "true"; + } + } + } + + public function checkAuthentication(){ + if($this->isExtensionInstalled("OpenSSL") == "false"){ + return "offline mode/insecure"; + + } else { + return "online mode/secure"; + } + } /** * @param string $message * @param Player[]|null $recipients @@ -2257,9 +2157,9 @@ public function batchPackets(array $players, array $packets, $forceSync = false) if(!$p->isEncoded){ $p->encode(); } - $str .= Binary::writeInt(strlen($p->buffer)) . $p->buffer; + $str .= Binary::writeUnsignedVarInt(strlen($p->buffer)) . $p->buffer; }else{ - $str .= Binary::writeInt(strlen($p)) . $p; + $str .= Binary::writeUnsignedVarInt(strlen($p)) . $p; } } @@ -2317,15 +2217,6 @@ public function enablePlugin(Plugin $plugin){ $this->pluginManager->enablePlugin($plugin); } - /** - * @param Plugin $plugin - * - * @deprecated - */ - public function loadPlugin(Plugin $plugin){ - $this->enablePlugin($plugin); - } - public function disablePlugins(){ $this->pluginManager->disablePlugins(); } @@ -2352,16 +2243,12 @@ public function checkConsole(){ * @throws \Throwable */ public function dispatchCommand(CommandSender $sender, $commandLine){ - if(!($sender instanceof CommandSender)){ - throw new ServerException("CommandSender is not valid"); - } - if($this->commandMap->dispatch($sender, $commandLine)){ return true; } - $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.notFound")); + $sender->sendMessage(new TranslationContainer(TextFormat::GOLD . "%commands.generic.notFound")); return false; } @@ -2400,7 +2287,6 @@ public function reload(){ } $this->pluginManager->registerInterface(PharPluginLoader::class); - $this->pluginManager->registerInterface(FolderPluginLoader::class); $this->pluginManager->registerInterface(ScriptPluginLoader::class); $this->pluginManager->loadPlugins($this->pluginPath); $this->enablePlugins(PluginLoadOrder::STARTUP); @@ -2414,18 +2300,15 @@ public function reload(){ * @param string $msg */ public function shutdown(bool $restart = false, string $msg = ""){ - /*if($this->expEnabled){ - foreach($this->getLevels() as $level){ - foreach($level->getEntities() as $e){ - if($e instanceof ExperienceOrb) $e->close(); - } - } - }*/ /*if($this->isRunning){ $killer = new ServerKiller(90); $killer->start(); $killer->kill(); }*/ + + $this->getPluginManager()->callEvent($ev = new event\server\ServerShutdownEvent()); + if($ev->isCancelled(true)) return; + $this->isRunning = false; if($msg != ""){ $this->propertyCache["settings.shutdown-message"] = $msg; @@ -2485,12 +2368,7 @@ public function forceShutdown(){ $interface->shutdown(); $this->network->unregisterInterface($interface); } - - if($this->isSynapseEnabled()){ - $this->getLogger()->debug("Stopping Synapse client"); - $this->synapse->shutdown(); - } - + //$this->memoryManager->doObjectCleanup(); gc_collect_cycles(); @@ -2507,7 +2385,7 @@ public function getQueryInformation(){ } /** - * Starts the devmine-MP server and starts processing ticks and packets + * Starts the DevMine-MP server and starts processing ticks and packets */ public function start(){ if($this->getConfigBoolean("enable-query", true) === true){ @@ -2538,13 +2416,9 @@ public function start(){ $this->dispatchSignals = true; } - $this->logger->info($this->getLanguage()->translateString("devmine.server.defaultGameMode", [self::getGamemodeString($this->getGamemode())])); + $this->logger->info($this->getLanguage()->translateString("DevMine.server.defaultGameMode", [self::getGamemodeString($this->getGamemode())])); - $this->logger->info($this->getLanguage()->translateString("devmine.server.startFinished", [round(microtime(true) - \devmine\START_TIME, 3)])); - - if(!file_exists($this->getPluginPath() . DIRECTORY_SEPARATOR . "devmine")){ - @mkdir($this->getPluginPath() . DIRECTORY_SEPARATOR . "devmine"); - } + $this->logger->info($this->getLanguage()->translateString("DevMine.server.startFinished", [round(microtime(true) - \DevMine\START_TIME, 3)])); $this->tickProcessor(); $this->forceShutdown(); @@ -2610,15 +2484,15 @@ public function crashDump(){ ini_set("error_reporting", 0); ini_set("memory_limit", -1); //Fix error dump not dumped on memory problems - $this->logger->emergency($this->getLanguage()->translateString("devmine.crash.create")); + $this->logger->emergency($this->getLanguage()->translateString("DevMine.crash.create")); try{ $dump = new CrashDump($this); }catch(\Throwable $e){ - $this->logger->critical($this->getLanguage()->translateString("devmine.crash.error", $e->getMessage())); + $this->logger->critical($this->getLanguage()->translateString("DevMine.crash.error", $e->getMessage())); return; } - $this->logger->emergency($this->getLanguage()->translateString("devmine.crash.submit", [$dump->getPath()])); + $this->logger->emergency($this->getLanguage()->translateString("DevMine.crash.submit", [$dump->getPath()])); if($this->getProperty("auto-report.enabled", true) !== false){ @@ -2637,17 +2511,17 @@ public function crashDump(){ } if($report){ - $reply = Utils::postURL("http://" . $this->getProperty("auto-report.host", "crash.devmine.net") . "/submit/api", [ + $reply = Utils::postURL("http://" . $this->getProperty("auto-report.host", "crash.pocketmine.net") . "/submit/api", [ "report" => "yes", - "name" => $this->getName() . " " . $this->getdevmineVersion(), - "email" => "crash@devmine.net", + "name" => $this->getName() . " " . $this->getDevMineVersion(), + "email" => "crash@pocketmine.net", "reportPaste" => base64_encode($dump->getEncodedData()) ]); if(($data = json_decode($reply)) !== false and isset($data->crashId)){ $reportId = $data->crashId; $reportUrl = $data->crashUrl; - $this->logger->emergency($this->getLanguage()->translateString("devmine.crash.archive", [$reportUrl, $reportId])); + $this->logger->emergency($this->getLanguage()->translateString("DevMine.crash.archive", [$reportUrl, $reportId])); } } } @@ -2725,6 +2599,9 @@ public function sendFullPlayerListData(Player $p){ $pk = new PlayerListPacket(); $pk->type = PlayerListPacket::TYPE_ADD; foreach($this->playerList as $player){ + if($p === $player){ + continue; //fixes duplicates + } $pk->entries[] = [$player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData()]; } @@ -2797,8 +2674,8 @@ private function checkTickUpdates($currentTick, $tickTime){ } } }catch(\Throwable $e){ - $this->logger->critical($this->getLanguage()->translateString("devmine.level.tickError", [$level->getName(), $e->getMessage()])); - if(\devmine\DEBUG > 1 and $this->logger instanceof MainLogger){ + $this->logger->critical($this->getLanguage()->translateString("DevMine.level.tickError", [$level->getName(), $e->getMessage()])); + if(\DevMine\DEBUG > 1 and $this->logger instanceof MainLogger){ $this->logger->logException($e); } } @@ -2867,8 +2744,7 @@ private function titleTick(){ $u = Utils::getMemoryUsage(true); $usage = round(($u[0] / 1024) / 1024, 2) . "/" . round(($d[0] / 1024) / 1024, 2) . "/" . round(($u[1] / 1024) / 1024, 2) . "/" . round(($u[2] / 1024) / 1024, 2) . " MB @ " . Utils::getThreadCount() . " threads"; - echo "\x1b]0;" . $this->getName() . " " . - $this->getGameVersion() . "-#" . $this->getBuild() . + echo "\x1b]0;" . $this->getName() . $this->getFormattedVersion("-") . " | Online " . count($this->players) . "/" . $this->getMaxPlayers() . " | Memory " . $usage . " | U " . round($this->network->getUpload() / 1024, 2) . @@ -2892,7 +2768,7 @@ public function handlePacket($address, $port, $payload){ $this->queryHandler->handle($address, $port, $payload); } }catch(\Throwable $e){ - if(\devmine\DEBUG > 1){ + if(\DevMine\DEBUG > 1){ if($this->logger instanceof MainLogger){ $this->logger->logException($e); } @@ -2960,10 +2836,7 @@ private function tick(){ Timings::$connectionTimer->startTiming(); $this->network->processInterfaces(); - if($this->isSynapseEnabled()){ - $this->synapse->tick(); - } - + if($this->rcon !== null){ $this->rcon->check(); } @@ -3010,7 +2883,7 @@ private function tick(){ } if($this->getTicksPerSecondAverage() < 1){ - $this->logger->warning($this->getLanguage()->translateString("devmine.server.tickOverload")); + $this->logger->warning($this->getLanguage()->translateString("DevMine.server.tickOverload")); } } @@ -3054,7 +2927,10 @@ private function registerEntities(){ Entity::registerEntity(Arrow::class); Entity::registerEntity(Bat::class); Entity::registerEntity(Blaze::class); + //Entity::registerEntity(BlazeFireball::class); + //Entity::registerEntity(BlueWitherSkull::class); Entity::registerEntity(Boat::class); + //Entity::registerEntity(Camera::class); Entity::registerEntity(CaveSpider::class); Entity::registerEntity(Chicken::class); Entity::registerEntity(Cow::class); @@ -3062,12 +2938,19 @@ private function registerEntities(){ Entity::registerEntity(DroppedItem::class); Entity::registerEntity(Egg::class); Entity::registerEntity(Enderman::class); + + //Entity::registerEntity(EnderDragon::class); + + //Entity::registerEntity(ElderGuardian::class); Entity::registerEntity(FallingSand::class); Entity::registerEntity(FishingHook::class); Entity::registerEntity(Ghast::class); + //Entity::registerEntity(GhastFireball::class); + //Entity::registerEntity(Guardian::class); Entity::registerEntity(Husk::class); Entity::registerEntity(IronGolem::class); Entity::registerEntity(LavaSlime::class); //Magma Cube + //Entity::registerEntity(LeashKnot::class); Entity::registerEntity(Lightning::class); Entity::registerEntity(Minecart::class); Entity::registerEntity(MinecartChest::class); @@ -3093,27 +2976,31 @@ private function registerEntities(){ Entity::registerEntity(ThrownPotion::class); Entity::registerEntity(Villager::class); Entity::registerEntity(Witch::class); + //Entity::registerEntity(Wither::class); + //Entity::registerEntity(WitherSkeleton::class); Entity::registerEntity(Wolf::class); Entity::registerEntity(XPOrb::class); Entity::registerEntity(Zombie::class); Entity::registerEntity(ZombieVillager::class); - + Entity::registerEntity(Human::class, true); } - private function registersolidentities(){ - solidentity::registersolidentity(BrewingStand::class); - solidentity::registersolidentity(Chest::class); - solidentity::registersolidentity(Furnace::class); - solidentity::registersolidentity(Sign::class); - solidentity::registersolidentity(EnchantTable::class); - solidentity::registersolidentity(FlowerPot::class); - solidentity::registersolidentity(Skull::class); - solidentity::registersolidentity(MobSpawner::class); - solidentity::registersolidentity(ItemFrame::class); - solidentity::registersolidentity(Dispenser::class); - solidentity::registersolidentity(Dropper::class); - solidentity::registersolidentity(DLDetector::class); - solidentity::registersolidentity(Cauldron::class); + private function registerTiles(){ + Tile::registerTile(Beacon::class); + Tile::registerTile(BrewingStand::class); + Tile::registerTile(Cauldron::class); + Tile::registerTile(Chest::class); + Tile::registerTile(Dispenser::class); + Tile::registerTile(DLDetector::class); + Tile::registerTile(Dropper::class); + Tile::registerTile(EnchantTable::class); + Tile::registerTile(FlowerPot::class); + Tile::registerTile(Furnace::class); + Tile::registerTile(Hopper::class); + Tile::registerTile(ItemFrame::class); + Tile::registerTile(MobSpawner::class); + Tile::registerTile(Sign::class); + Tile::registerTile(Skull::class); } } diff --git a/src/devmine/server/Thread.php b/src/devmine/server/Thread.php index f4c3b90..52e3c40 100644 --- a/src/devmine/server/Thread.php +++ b/src/devmine/server/Thread.php @@ -26,9 +26,9 @@ public function setClassLoader(\ClassLoader $loader = null){ public function registerClassLoader(){ if(!interface_exists("ClassLoader", false)){ - require(\devmine\PATH . "src/spl/ClassLoader.php"); - require(\devmine\PATH . "src/spl/BaseClassLoader.php"); - require(\devmine\PATH . "src/devmine/server/CompatibleClassLoader.php"); + require(\DevMine\PATH . "src/spl/ClassLoader.php"); + require(\DevMine\PATH . "src/spl/BaseClassLoader.php"); + require(\DevMine\PATH . "src/devmine/CompatibleClassLoader.php"); } if($this->classLoader !== null){ $this->classLoader->register(true); diff --git a/src/devmine/server/ThreadManager.php b/src/devmine/server/ThreadManager.php index 456e06b..e8ff0cf 100644 --- a/src/devmine/server/ThreadManager.php +++ b/src/devmine/server/ThreadManager.php @@ -4,7 +4,7 @@ namespace devmine\server; -class ThreadManager extends \Volatile{ +class ThreadManager extends \BaseClassLoader{ /** @var ThreadManager */ private static $instance = null; @@ -49,4 +49,4 @@ public function getAll(){ return $array; } -} \ No newline at end of file +} diff --git a/src/devmine/server/Worker.php b/src/devmine/server/Worker.php index e4666e1..f965631 100644 --- a/src/devmine/server/Worker.php +++ b/src/devmine/server/Worker.php @@ -27,9 +27,9 @@ public function setClassLoader(\ClassLoader $loader = null){ public function registerClassLoader(){ if(!interface_exists("ClassLoader", false)){ - require(\devmine\PATH . "src/spl/ClassLoader.php"); - require(\devmine\PATH . "src/spl/BaseClassLoader.php"); - require(\devmine\PATH . "src/devmine/server/CompatibleClassLoader.php"); + require(\DevMine\PATH . "src/spl/ClassLoader.php"); + require(\DevMine\PATH . "src/spl/BaseClassLoader.php"); + require(\DevMine\PATH . "src/devmine/CompatibleClassLoader.php"); } if($this->classLoader !== null){ $this->classLoader->register(true); diff --git a/src/devmine/server/calculations/AxisAlignedBB.php b/src/devmine/server/calculations/AxisAlignedBB.php index e7f335e..7608e08 100644 --- a/src/devmine/server/calculations/AxisAlignedBB.php +++ b/src/devmine/server/calculations/AxisAlignedBB.php @@ -4,7 +4,7 @@ namespace devmine\server\calculations; -use devmine\levels\MovingObjectPosition; +use devmine\worlds\MovingObjectPosition; class AxisAlignedBB{ diff --git a/src/devmine/server/calculations/Math.php b/src/devmine/server/calculations/Math.php index a32dcce..2a7fbf5 100644 --- a/src/devmine/server/calculations/Math.php +++ b/src/devmine/server/calculations/Math.php @@ -19,4 +19,17 @@ public static function ceilFloat($n){ $i = (int) ($n + 1); return $n >= $i ? $i : $i - 1; } + + public static function clamp($value, $low, $high){ + return min($high, max($low, $value)); + } + + public static function solveQuadratic($a, $b, $c): array{ + $x[0] = (-$b + sqrt($b ** 2 - 4 * $a * $c)) / (2 * $a); + $x[1] = (-$b - sqrt($b ** 2 - 4 * $a * $c)) / (2 * $a); + if($x[0] == $x[1]){ + return [$x[0]]; + } + return $x; + } } \ No newline at end of file diff --git a/src/devmine/server/calculations/Matrix.php b/src/devmine/server/calculations/Matrix.php index 67e721d..8f53505 100644 --- a/src/devmine/server/calculations/Matrix.php +++ b/src/devmine/server/calculations/Matrix.php @@ -32,7 +32,7 @@ public function __construct($rows, $columns, array $set = []){ $this->set($set); } - public function st(array $m){ + public function set(array $m){ for($r = 0; $r < $this->rows; ++$r){ $this->matrix[$r] = []; for($c = 0; $c < $this->columns; ++$c){ diff --git a/src/devmine/server/calculations/Vector2.php b/src/devmine/server/calculations/Vector2.php index f015c51..27c42fc 100644 --- a/src/devmine/server/calculations/Vector2.php +++ b/src/devmine/server/calculations/Vector2.php @@ -6,7 +6,7 @@ use devmine\utilities\main\Random; /** - * WARNING: This class is available on the devmine-MP Zephir project. + * WARNING: This class is available on the DevMine-MP Zephir project. * If this class is modified, remember to modify the PHP C extension. */ class Vector2{ @@ -116,11 +116,6 @@ public function __toString(){ } public static function createRandomDirection(Random $random){ - return self::createDirection($random->nextFloat() * 2 * pi()); + return VectorMath::getDirection2D($random->nextFloat() * 2 * pi()); } - - public static function createDirection(float $angle){ - return new Vector2(cos($angle), sin($angle)); - } - } \ No newline at end of file diff --git a/src/devmine/server/calculations/Vector3.php b/src/devmine/server/calculations/Vector3.php index 8c09ba2..68d2a31 100644 --- a/src/devmine/server/calculations/Vector3.php +++ b/src/devmine/server/calculations/Vector3.php @@ -4,6 +4,8 @@ namespace devmine\server\calculations; +use devmine\utilities\main\Random; + class Vector3{ const SIDE_DOWN = 0; @@ -327,4 +329,7 @@ public function __toString(){ return "Vector3(x=" . $this->x . ",y=" . $this->y . ",z=" . $this->z . ")"; } + public static function createRandomDirection(Random $random){ + return VectorMath::getDirection3D($random->nextFloat() * 2 * pi(), $random->nextFloat() * 2 * pi()); + } } diff --git a/src/devmine/server/calculations/VectorMath.php b/src/devmine/server/calculations/VectorMath.php index 4f84db0..86c48c9 100644 --- a/src/devmine/server/calculations/VectorMath.php +++ b/src/devmine/server/calculations/VectorMath.php @@ -7,8 +7,13 @@ abstract class VectorMath{ - public static function getDirection2D($azimuth){ + public static function getDirection2D($azimuth) : Vector2{ return new Vector2(cos($azimuth), sin($azimuth)); } + public static function getDirection3D($azimuth, $inclination) : Vector3{ + $yFact = cos($inclination); + return new Vector3($yFact * cos($azimuth), sin($inclination), $yFact * sin($azimuth)); + } + } \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Ageable.php b/src/devmine/server/calculations/entity/Ageable.php new file mode 100644 index 0000000..6180816 --- /dev/null +++ b/src/devmine/server/calculations/entity/Ageable.php @@ -0,0 +1,10 @@ +getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BABY); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Arrow.php b/src/devmine/server/calculations/entity/Arrow.php new file mode 100644 index 0000000..099cab4 --- /dev/null +++ b/src/devmine/server/calculations/entity/Arrow.php @@ -0,0 +1,98 @@ +isCritical = (bool) $critical; + if(!isset($nbt->Potion)){ + $nbt->Potion = new ShortTag("Potion", 0); + } + parent::__construct($chunk, $nbt, $shootingEntity); + $this->potionId = $this->namedtag["Potion"]; + } + + public function getPotionId() : int{ + return $this->potionId; + } + + public function onUpdate($currentTick){ + if($this->closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if(!$this->hadCollision and $this->isCritical){ + $this->level->addParticle(new CriticalParticle($this->add( + $this->width / 2 + mt_rand(-100, 100) / 500, + $this->height / 2 + mt_rand(-100, 100) / 500, + $this->width / 2 + mt_rand(-100, 100) / 500))); + }elseif($this->onGround){ + $this->isCritical = false; + } + + if($this->potionId != 0){ + if(!$this->onGround or ($this->onGround and ($currentTick % 4) == 0)){ + $color = Potion::getColor($this->potionId - 1); + $this->level->addParticle(new MobSpellParticle($this->add( + $this->width / 2 + mt_rand(-100, 100) / 500, + $this->height / 2 + mt_rand(-100, 100) / 500, + $this->width / 2 + mt_rand(-100, 100) / 500), $color[0], $color[1], $color[2])); + } + $hasUpdate = true; + } + + if($this->age > 1200){ + $this->kill(); + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = Arrow::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Attachable.php b/src/devmine/server/calculations/entity/Attachable.php new file mode 100644 index 0000000..510163c --- /dev/null +++ b/src/devmine/server/calculations/entity/Attachable.php @@ -0,0 +1,10 @@ + $maxValue or $defaultValue > $maxValue or $defaultValue < $minValue){ + throw new \InvalidArgumentException("Invalid ranges: min value: $minValue, max value: $maxValue, $defaultValue: $defaultValue"); + } + + return self::$attributes[(int) $id] = new Attribute($id, $name, $minValue, $maxValue, $defaultValue, $shouldSend); + } + + /** + * @param $id + * + * @return null|Attribute + */ + public static function getAttribute($id){ + return isset(self::$attributes[$id]) ? clone self::$attributes[$id] : null; + } + + /** + * @param $name + * + * @return null|Attribute + */ + public static function getAttributeByName($name){ + foreach(self::$attributes as $a){ + if($a->getName() === $name){ + return clone $a; + } + } + + return null; + } + + private function __construct($id, $name, $minValue, $maxValue, $defaultValue, $shouldSend = true){ + $this->id = (int) $id; + $this->name = (string) $name; + $this->minValue = (float) $minValue; + $this->maxValue = (float) $maxValue; + $this->defaultValue = (float) $defaultValue; + $this->shouldSend = (bool) $shouldSend; + + $this->currentValue = $this->defaultValue; + } + + public function getMinValue(){ + return $this->minValue; + } + + public function setMinValue($minValue){ + if($minValue > $this->getMaxValue()){ + throw new \InvalidArgumentException("Value $minValue is bigger than the maxValue!"); + } + + if($this->minValue != $minValue){ + $this->desynchronized = true; + $this->minValue = $minValue; + } + return $this; + } + + public function getMaxValue(){ + return $this->maxValue; + } + + public function setMaxValue($maxValue){ + if($maxValue < $this->getMinValue()){ + throw new \InvalidArgumentException("Value $maxValue is bigger than the minValue!"); + } + + if($this->maxValue != $maxValue){ + $this->desynchronized = true; + $this->maxValue = $maxValue; + } + return $this; + } + + public function getDefaultValue(){ + return $this->defaultValue; + } + + public function setDefaultValue($defaultValue){ + if($defaultValue > $this->getMaxValue() or $defaultValue < $this->getMinValue()){ + throw new \InvalidArgumentException("Value $defaultValue exceeds the range!"); + } + + if($this->defaultValue !== $defaultValue){ + $this->desynchronized = true; + $this->defaultValue = $defaultValue; + } + return $this; + } + + public function getValue(){ + return $this->currentValue; + } + + public function setValue($value, bool $fit = true, bool $shouldSend = false){ + if($value > $this->getMaxValue() or $value < $this->getMinValue()){ + if(!$fit){ + Server::getInstance()->getLogger()->error("[Attribute / {$this->getName()}] Value $value exceeds the range!"); + } + $value = min(max($value, $this->getMinValue()), $this->getMaxValue()); + } + + if($this->currentValue != $value){ + $this->desynchronized = true; + $this->currentValue = $value; + } + + if($shouldSend){ + $this->desynchronized = true; + } + return $this; + } + + public function getName(){ + return $this->name; + } + + public function getId(){ + return $this->id; + } + + public function isSyncable(){ + return $this->shouldSend; + } + + public function isDesynchronized() : bool{ + return $this->shouldSend and $this->desynchronized; + } + + public function markSynchronized(bool $synced = true){ + $this->desynchronized = !$synced; + } +} diff --git a/src/devmine/server/calculations/entity/AttributeMap.php b/src/devmine/server/calculations/entity/AttributeMap.php new file mode 100644 index 0000000..a3ae600 --- /dev/null +++ b/src/devmine/server/calculations/entity/AttributeMap.php @@ -0,0 +1,52 @@ +attributes[$attribute->getId()] = $attribute; + } + + /** + * @param int $id + * + * @return Attribute|null + */ + public function getAttribute(int $id){ + return $this->attributes[$id] ?? null; + } + + public function getAll(): array{ + return $this->attributes; + } + + /** + * @return Attribute[] + */ + public function needSend() : array{ + return array_filter($this->attributes, function (Attribute $attribute){ + return $attribute->isSyncable() and $attribute->isDesynchronized(); + }); + } + + public function offsetExists($offset){ + return isset($this->attributes[$offset]); + } + + public function offsetGet($offset){ + return $this->attributes[$offset]->getValue(); + } + + public function offsetSet($offset, $value){ + $this->attributes[$offset]->setValue($value); + } + + public function offsetUnset($offset){ + throw new \RuntimeException("Could not unset an attribute from an attribute map"); + } +} diff --git a/src/devmine/server/calculations/entity/Bat.php b/src/devmine/server/calculations/entity/Bat.php new file mode 100644 index 0000000..0a8e9df --- /dev/null +++ b/src/devmine/server/calculations/entity/Bat.php @@ -0,0 +1,93 @@ +setMaxHealth(6); + parent::initEntity(); + } + + public function __construct(Chunk $chunk, CompoundTag $nbt){ + if(!isset($nbt->isResting)){ + $nbt->isResting = new ByteTag("isResting", 0); + } + parent::__construct($chunk, $nbt); + + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_RESTING, $this->isResting()); + } + + public function isResting() : int{ + return (int) $this->namedtag["isResting"]; + } + + public function setResting(bool $resting){ + $this->namedtag->isResting = new ByteTag("isResting", $resting ? 1 : 0); + } + + public function onUpdate($currentTick){ + if ($this->age > 20 * 60 * 10) { + $this->kill(); + } + return parent::onUpdate($currentTick); + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Bat::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Blaze.php b/src/devmine/server/calculations/entity/Blaze.php new file mode 100644 index 0000000..28c69dc --- /dev/null +++ b/src/devmine/server/calculations/entity/Blaze.php @@ -0,0 +1,70 @@ +eid = $this->getId(); + $pk->type = self::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + parent::spawnTo($player); + } + + public function getDrops(){ + $cause = $this->lastDamageCause; + //Only drop when kill by player or dog(No add now.) + if($cause instanceof EntityDamageByEntityEvent and $cause->getDamager() instanceof Player){ + $lootingL = $cause->getDamager()->getItemInHand()->getEnchantmentLevel(Enchantment::TYPE_WEAPON_LOOTING); + $drops = array(ItemItem::get(ItemItem::BLAZE_ROD, 0, mt_rand(0, 1 + $lootingL))); + return $drops; + } + return []; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Boat.php b/src/devmine/server/calculations/entity/Boat.php new file mode 100644 index 0000000..d581e99 --- /dev/null +++ b/src/devmine/server/calculations/entity/Boat.php @@ -0,0 +1,138 @@ +WoodID)){ + $nbt->WoodID = new IntTag("WoodID", 0); + } + parent::__construct($chunk, $nbt); + $this->setDataProperty(self::DATA_VARIANT, self::DATA_TYPE_INT, $this->getWoodID()); + } + + public function getWoodID() : int{ + return (int) $this->namedtag["WoodID"]; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Boat::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = 0; + $pk->speedY = 0; + $pk->speedZ = 0; + $pk->yaw = 0; + $pk->pitch = 0; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function attack($damage, EntityDamageEvent $source){ + parent::attack($damage, $source); + + if(!$source->isCancelled()){ + $pk = new EntityEventPacket(); + $pk->eid = $this->id; + $pk->event = EntityEventPacket::HURT_ANIMATION; + foreach($this->getLevel()->getPlayers() as $player){ + $player->dataPacket($pk); + } + } + } + + public function onUpdate($currentTick){ + if($this->closed){ + return false; + } + $tickDiff = $currentTick - $this->lastUpdate; + if($tickDiff <= 0 and !$this->justCreated){ + return true; + } + + $this->lastUpdate = $currentTick; + + $this->timings->startTiming(); + + $hasUpdate = $this->entityBaseTick($tickDiff); + + if(!$this->level->getBlock(new Vector3($this->x,$this->y,$this->z))->getBoundingBox()==null or $this->isInsideOfWater()){ + $this->motionY = 0.1; + }else{ + $this->motionY = -0.08; + } + + $this->move($this->motionX, $this->motionY, $this->motionZ); + $this->updateMovement(); + + if($this->linkedEntity == null or $this->linkedType = 0){ + if($this->age > 1500){ + $this->close(); + $hasUpdate = true; + //$this->scheduleUpdate(); + + $this->age = 0; + } + $this->age++; + }else $this->age = 0; + + $this->timings->stopTiming(); + + + return $hasUpdate or !$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + } + + + public function getDrops(){ + return [ + ItemItem::get(ItemItem::BOAT, 0, 1) + ]; + } + + public function getSaveId(){ + $class = new \ReflectionClass(static::class); + return $class->getShortName(); + } +} diff --git a/src/devmine/server/calculations/entity/CaveSpider.php b/src/devmine/server/calculations/entity/CaveSpider.php new file mode 100644 index 0000000..f7e80bf --- /dev/null +++ b/src/devmine/server/calculations/entity/CaveSpider.php @@ -0,0 +1,57 @@ +eid = $this->getId(); + $pk->type = CaveSpider::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Chicken.php b/src/devmine/server/calculations/entity/Chicken.php new file mode 100644 index 0000000..aa8cbfe --- /dev/null +++ b/src/devmine/server/calculations/entity/Chicken.php @@ -0,0 +1,77 @@ +eid = $this->getId(); + $pk->type = Chicken::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + parent::spawnTo($player); + } + + public function getDrops(){ + $drops = []; + if ($this->lastDamageCause instanceof EntityDamageByEntityEvent and $this->lastDamageCause->getEntity() instanceof Player) { + + switch (\mt_rand(0, 2)) { + case 0: + $drops[] = ItemItem::get(ItemItem::RAW_CHICKEN, 0, 1); + break; + case 1: + $drops[] = ItemItem::get(ItemItem::FEATHER, 0, 1); + break; + case 2: + $drops[] = ItemItem::get(ItemItem::FEATHER, 0, 2); + break; + } + } + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Colorable.php b/src/devmine/server/calculations/entity/Colorable.php new file mode 100644 index 0000000..bb74e91 --- /dev/null +++ b/src/devmine/server/calculations/entity/Colorable.php @@ -0,0 +1,10 @@ +eid = $this->getId(); + $pk->type = Cow::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $lootingL = 0; + $cause = $this->lastDamageCause; + if($cause instanceof EntityDamageByEntityEvent and $cause->getDamager() instanceof Player){ + $lootingL = $cause->getDamager()->getItemInHand()->getEnchantmentLevel(Enchantment::TYPE_WEAPON_LOOTING); + } + $drops = array(ItemItem::get(ItemItem::RAW_BEEF, 0, mt_rand(1, 3 + $lootingL))); + $drops[] = ItemItem::get(ItemItem::LEATHER, 0, mt_rand(0, 2 + $lootingL)); + //TODO: add judgement for Steak + /*if ($this->lastDamageCause instanceof EntityDamageByEntityEvent and $this->lastDamageCause->getEntity() instanceof Player) { + $drops[] = ItemItem::get(ItemItem::LEATHER, 0, mt_rand(0,2)); + }*/ + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Creature.php b/src/devmine/server/calculations/entity/Creature.php new file mode 100644 index 0000000..00a87c8 --- /dev/null +++ b/src/devmine/server/calculations/entity/Creature.php @@ -0,0 +1,320 @@ +attackingTick > 0){ + $this->attackingTick--; + } + if(!$this->isAlive() and $this->hasSpawned){ + ++$this->deadTicks; + if($this->deadTicks >= 20){ + $this->despawnFromAll(); + } + return true; + } + if($this->isAlive()){ + + $this->motionY -= $this->gravity; + + $this->move($this->motionX, $this->motionY, $this->motionZ); + + $friction = 1 - $this->drag; + + if($this->onGround and (abs($this->motionX) > 0.00001 or abs($this->motionZ) > 0.00001)){ + $friction = $this->getLevel()->getBlock($this->temporalVector->setComponents((int) floor($this->x), (int) floor($this->y - 1), (int) floor($this->z) - 1))->getFrictionFactor() * $friction; + } + + $this->motionX *= $friction; + $this->motionY *= 1 - $this->drag; + $this->motionZ *= $friction; + + if($this->onGround){ + $this->motionY *= -0.5; + } + + $this->updateMovement(); + } + } + parent::entityBaseTick(); + return parent::onUpdate($tick); + } + + public function willMove($distance = 36){ + foreach($this->getViewers() as $viewer){ + if($this->distance($viewer->getLocation()) <= $distance) return true; + } + return false; + } + + public function attack($damage, EntityDamageEvent $source){ + parent::attack($damage, $source); + if(!$source->isCancelled() and $source->getCause() == EntityDamageEvent::CAUSE_ENTITY_ATTACK){ + $this->attackingTick = 20; + } + } + + /** + * @param Level $level + * @param Vector3 $v3 + * @param bool $hate + * @param bool $reason + * @return bool|float|string + * 判断某坐标是否可以行走 + * 并给出原因 + */ + public function ifjump(Level $level, Vector3 $v3, $hate = false, $reason = false){ //boybook Y轴算法核心函数 + $x = floor($v3->getX()); + $y = floor($v3->getY()); + $z = floor($v3->getZ()); + + //echo ($y." "); + if($this->whatBlock($level, new Vector3($x, $y, $z)) == "air"){ + //echo "前方空气 "; + if($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "block" or new Vector3($x, $y - 1, $z) == "climb"){ //方块 + //echo "考虑向前 "; + if($this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "half" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "high"){ //上方一格被堵住了 + //echo "上方卡住 \n"; + if($reason) return 'up!'; + return false; //上方卡住 + }else{ + //echo "GO向前走 \n"; + if($reason) return 'GO'; + return $y; //向前走 + } + }elseif($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "water"){ //水 + //echo "下水游泳 \n"; + if($reason) return 'swim'; + return $y - 1; //降低一格向前走(下水游泳) + }elseif($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "half"){ //半砖 + //echo "下到半砖 \n"; + if($reason) return 'half'; + return $y - 0.5; //向下跳0.5格 + }elseif($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "lava"){ //岩浆 + //echo "前方岩浆 \n"; + if($reason) return 'lava'; + return false; //前方岩浆 + }elseif($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "air"){ //空气 + //echo "考虑向下跳 "; + if($this->whatBlock($level, new Vector3($x, $y - 2, $z)) == "block"){ + //echo "GO向下跳 \n"; + if($reason) return 'down'; + return $y - 1; //向下跳 + }else{ //前方悬崖 + //echo "前方悬崖 \n"; + if($reason) return 'fall'; + if($hate === false){ + return false; + }else{ + return $y - 1; //向下跳 + } + } + } + }elseif($this->whatBlock($level, new Vector3($x, $y, $z)) == "water"){ //水 + //echo "正在水中"; + if($this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "water"){ //上面还是水 + //echo "向上游 \n"; + if($reason) return 'inwater'; + return $y + 1; //向上游,防溺水 + }elseif($this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "half"){ //上方一格被堵住了 + if($this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y - 1, $z)) == "half"){ //下方一格被也堵住了 + //echo "上下都被卡住 \n"; + if($reason) return 'up!_down!'; + return false; //上下都被卡住 + }else{ + //echo "向下游 \n"; + if($reason) return 'up!'; + return $y - 1; //向下游,防卡住 + } + }else{ + //echo "游泳ing... \n"; + if($reason) return 'swim...'; + return $y; //向前游 + } + }elseif($this->whatBlock($level, new Vector3($x, $y, $z)) == "half"){ //半砖 + //echo "前方半砖 \n"; + if($this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "half" or $this->whatBlock($level, new Vector3($x, $y + 1, $z)) == "high"){ //上方一格被堵住了 + //return false; //上方卡住 + }else{ + if($reason) return 'halfGO'; + return $y + 0.5; + } + + }elseif($this->whatBlock($level, new Vector3($x, $y, $z)) == "lava"){ //岩浆 + //echo "前方岩浆 \n"; + if($reason) return 'lava'; + return false; + }elseif($this->whatBlock($level, new Vector3($x, $y, $z)) == "high"){ //1.5格高方块 + //echo "前方栅栏 \n"; + if($reason) return 'high'; + return false; + }elseif($this->whatBlock($level, new Vector3($x, $y, $z)) == "climb"){ //梯子 + //echo "前方梯子 \n"; + //return $y; + if($reason) return 'climb'; + if($hate){ + return $y + 0.7; + }else{ + return $y + 0.5; + } + }else{ //考虑向上 + //echo "考虑向上 "; + if($this->whatBlock($level, new Vector3($x, $y + 1, $z)) != "air"){ //前方是面墙 + //echo "前方是墙 \n"; + if($reason) return 'wall'; + return false; + }else{ + if($this->whatBlock($level, new Vector3($x, $y + 2, $z)) == "block" or $this->whatBlock($level, new Vector3($x, $y + 2, $z)) == "half" or $this->whatBlock($level, new Vector3($x, $y + 2, $z)) == "high"){ //上方两格被堵住了 + //echo "2格处被堵 \n"; + if($reason) return 'up2!'; + return false; + }else{ + //echo "GO向上跳 \n"; + if($reason) return 'upGO'; + return $y + 1; //向上跳 + } + } + } + return false; + } + + public function whatBlock(Level $level, $v3){ //boybook的y轴判断法 核心 什么方块? + $id = $level->getBlockIdAt($v3->x, $v3->y, $v3->z); + $damage = $level->getBlockDataAt($v3->x, $v3->y, $v3->z); + switch($id){ + case 0: + case 6: + case 27: + case 30: + case 31: + case 37: + case 38: + case 39: + case 40: + case 50: + case 51: + case 63: + case 66: + case 68: + case 78: + case 111: + case 141: + case 142: + case 171: + case 175: + case 244: + case 323: + //透明方块 + return "air"; + break; + case 8: + case 9: + //水 + return "water"; + break; + case 10: + case 11: + //岩浆 + return "lava"; + break; + case 44: + case 158: + //半砖 + if($damage >= 8){ + return "block"; + }else{ + return "half"; + } + break; + case 64: + //门 + //var_dump($damage." "); + //TODO 不知如何判断门是否开启,因为以下条件永远满足 + if(($damage & 0x08) === 0x08){ + return "air"; + }else{ + return "block"; + } + break; + case 85: + case 107: + case 139: + //1.5格高的无法跳跃物 + return "high"; + break; + case 65: + case 106: + //可攀爬物 + return "climb"; + break; + default: + //普通方块 + return "block"; + break; + } + } + + /** + * @param $mx + * @param $mz + * @return float|int + * 获取yaw角度 + */ + public function getMyYaw($mx, $mz){ //根据motion计算转向角度 + //转向计算 + if($mz == 0){ //斜率不存在 + if($mx < 0){ + $yaw = -90; + }else{ + $yaw = 90; + } + }else{ //存在斜率 + if($mx >= 0 and $mz > 0){ //第一象限 + $atan = atan($mx / $mz); + $yaw = rad2deg($atan); + }elseif($mx >= 0 and $mz < 0){ //第二象限 + $atan = atan($mx / abs($mz)); + $yaw = 180 - rad2deg($atan); + }elseif($mx < 0 and $mz < 0){ //第三象限 + $atan = atan($mx / $mz); + $yaw = -(180 - rad2deg($atan)); + }elseif($mx < 0 and $mz > 0){ //第四象限 + $atan = atan(abs($mx) / $mz); + $yaw = -(rad2deg($atan)); + }else{ + $yaw = 0; + } + } + + $yaw = -$yaw; + return $yaw; + } + + /** + * @param Vector3 $from + * @param Vector3 $to + * @return float|int + * 获取pitch角度 + */ + public function getMyPitch(Vector3 $from, Vector3 $to){ + $distance = $from->distance($to); + $height = $to->y - $from->y; + if($height > 0){ + return -rad2deg(asin($height / $distance)); + }elseif($height < 0){ + return rad2deg(asin(-$height / $distance)); + }else{ + return 0; + } + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Creeper.php b/src/devmine/server/calculations/entity/Creeper.php new file mode 100644 index 0000000..928c84a --- /dev/null +++ b/src/devmine/server/calculations/entity/Creeper.php @@ -0,0 +1,87 @@ +namedtag->powered)){ + $this->setPowered(false); + } + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_POWERED, $this->isPowered()); + } + + public function setPowered(bool $powered, Lightning $lightning = null){ + if($lightning != null){ + $powered = true; + $cause = CreeperPowerEvent::CAUSE_LIGHTNING; + }else $cause = $powered ? CreeperPowerEvent::CAUSE_SET_ON : CreeperPowerEvent::CAUSE_SET_OFF; + + $this->getLevel()->getServer()->getPluginManager()->callEvent($ev = new CreeperPowerEvent($this, $lightning, $cause)); + + if(!$ev->isCancelled()){ + $this->namedtag->powered = new ByteTag("powered", $powered ? 1 : 0); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_POWERED, $powered); + } + } + + public function isPowered() : bool{ + return (bool) $this->namedtag["powered"]; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Creeper::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Damageable.php b/src/devmine/server/calculations/entity/Damageable.php new file mode 100644 index 0000000..eb9b24b --- /dev/null +++ b/src/devmine/server/calculations/entity/Damageable.php @@ -0,0 +1,10 @@ +setMaxHealth(200); + parent::initEntity(); + } + + public function getName() : string{ + return "Ender Dragon"; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Dragon::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/DragonFireBall.php b/src/devmine/server/calculations/entity/DragonFireBall.php new file mode 100644 index 0000000..c888dd4 --- /dev/null +++ b/src/devmine/server/calculations/entity/DragonFireBall.php @@ -0,0 +1,62 @@ +closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = DragonFireBall::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Effect.php b/src/devmine/server/calculations/entity/Effect.php new file mode 100644 index 0000000..6649f53 --- /dev/null +++ b/src/devmine/server/calculations/entity/Effect.php @@ -0,0 +1,343 @@ +id = $id; + $this->name = $name; + $this->bad = (bool) $isBad; + $this->setColor($r, $g, $b); + } + + public function getName() : string{ + return $this->name; + } + + public function getId(){ + return $this->id; + } + + public function setDuration($ticks){ + $this->duration = (($ticks > self::MAX_DURATION) ? self::MAX_DURATION : $ticks); + return $this; + } + + public function getDuration(){ + return $this->duration; + } + + public function isVisible(){ + return $this->show; + } + + public function setVisible($bool){ + $this->show = (bool) $bool; + return $this; + } + + /** + * @return int + */ + public function getAmplifier(){ + return $this->amplifier; + } + + /** + * @param int $amplifier + * + * @return $this + */ + public function setAmplifier($amplifier){ + $this->amplifier = (int) $amplifier; + return $this; + } + + public function isAmbient(){ + return $this->ambient; + } + + public function setAmbient($ambient = true){ + $this->ambient = (bool) $ambient; + return $this; + } + + public function isBad(){ + return $this->bad; + } + + public function canTick(){ + if($this->amplifier < 0) $this->amplifier = 0; + switch($this->id){ + case Effect::POISON: + if(($interval = (25 >> $this->amplifier)) > 0){ + return ($this->duration % $interval) === 0; + } + return true; + case Effect::WITHER: + if(($interval = (50 >> $this->amplifier)) > 0){ + return ($this->duration % $interval) === 0; + } + return true; + case Effect::REGENERATION: + if(($interval = (40 >> $this->amplifier)) > 0){ + return ($this->duration % $interval) === 0; + } + return true; + case Effect::HUNGER: + if($this->amplifier < 0){ // prevents hacking with amplifier -1 + return false; + } + if(($interval = 20) > 0){ + return ($this->duration % $interval) === 0; + } + return true; + case Effect::HEALING: + case Effect::HARMING: + return true; + case Effect::SATURATION: + if(($interval = (20 >> $this->amplifier)) > 0){ + return ($this->duration % $interval) === 0; + } + return true; + } + return false; + } + + public function applyEffect(Entity $entity){ + switch($this->id){ + case Effect::POISON: + if($entity->getHealth() > 1){ + $ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_MAGIC, 1); + $entity->attack($ev->getFinalDamage(), $ev); + } + break; + + case Effect::WITHER: + $ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_MAGIC, 1); + $entity->attack($ev->getFinalDamage(), $ev); + break; + + case Effect::REGENERATION: + if($entity->getHealth() < $entity->getMaxHealth()){ + $ev = new EntityRegainHealthEvent($entity, 1, EntityRegainHealthEvent::CAUSE_MAGIC); + $entity->heal($ev->getAmount(), $ev); + } + break; + case Effect::HUNGER: + if($entity instanceof Human){ + $entity->exhaust(0.5 * $this->amplifier, PlayerExhaustEvent::CAUSE_POTION); + } + break; + case Effect::HEALING: + $level = $this->amplifier + 1; + if(($entity->getHealth() + 4 * $level) <= $entity->getMaxHealth()) { + $ev = new EntityRegainHealthEvent($entity, 4 * $level, EntityRegainHealthEvent::CAUSE_MAGIC); + $entity->heal($ev->getAmount(), $ev); + } else { + $ev = new EntityRegainHealthEvent($entity, $entity->getMaxHealth() - $entity->getHealth(), EntityRegainHealthEvent::CAUSE_MAGIC); + $entity->heal($ev->getAmount(), $ev); + } + break; + case Effect::HARMING: + $level = $this->amplifier + 1; + if(($entity->getHealth() - 6 * $level) >= 0) { + $ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_MAGIC, 6 * $level); + $entity->attack($ev->getFinalDamage(), $ev); + } else { + $ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_MAGIC, $entity->getHealth()); + $entity->attack($ev->getFinalDamage(), $ev); + } + break; + case Effect::SATURATION: + if($entity instanceof Player){ + if($entity->getServer()->foodEnabled) { + $entity->setFood($entity->getFood() + 1); + } + } + break; + } + } + + public function getColor(){ + return [$this->color >> 16, ($this->color >> 8) & 0xff, $this->color & 0xff]; + } + + public function setColor($r, $g, $b){ + $this->color = (($r & 0xff) << 16) + (($g & 0xff) << 8) + ($b & 0xff); + } + + public function add(Entity $entity, $modify = false, Effect $oldEffect = null){ + if($entity instanceof Player){ + $pk = new MobEffectPacket(); + $pk->eid = 0; + $pk->effectId = $this->getId(); + $pk->amplifier = $this->getAmplifier(); + $pk->particles = $this->isVisible(); + $pk->duration = $this->getDuration(); + if($modify){ + $pk->eventId = MobEffectPacket::EVENT_MODIFY; + }else{ + $pk->eventId = MobEffectPacket::EVENT_ADD; + } + + $entity->dataPacket($pk); + + if($this->id === Effect::SPEED){ + $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); + if($modify and $oldEffect !== null){ + $speed = $attr->getValue() / (1 + 0.2 * ($oldEffect->getAmplifier() + 1)); + }else{ + $speed = $attr->getValue(); + } + $speed *= (1 + 0.2 * ($this->amplifier + 1)); + $attr->setValue($speed); + }elseif($this->id === Effect::SLOWNESS){ + $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); + if($modify and $oldEffect !== null){ + $speed = $attr->getValue() / (1 - 0.15 * ($oldEffect->getAmplifier() + 1)); + }else{ + $speed = $attr->getValue(); + } + $speed *= (1 - (0.15 * $this->amplifier + 1)); + $attr->setValue($speed); + } + } + + if($this->id === Effect::INVISIBILITY){ + $entity->setDataFlag(Entity::DATA_FLAGS, Entity::DATA_FLAG_INVISIBLE, true); + $entity->setNameTagVisible(false); + } + } + + public function remove(Entity $entity){ + if($entity instanceof Player){ + $pk = new MobEffectPacket(); + $pk->eid = 0; + $pk->eventId = MobEffectPacket::EVENT_REMOVE; + $pk->effectId = $this->getId(); + + $entity->dataPacket($pk); + + if($this->id === Effect::SPEED){ + $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); + $attr->setValue($attr->getValue() / (1 + 0.2 * ($this->amplifier + 1))); + }elseif($this->id === Effect::SLOWNESS){ + $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); + $attr->setValue($attr->getValue() / (1 - 0.15 * ($this->amplifier + 1))); + } + } + + if($this->id === Effect::INVISIBILITY){ + $entity->setDataFlag(Entity::DATA_FLAGS, Entity::DATA_FLAG_INVISIBLE, false); + $entity->setNameTagVisible(true); + } + } +} diff --git a/src/devmine/server/calculations/entity/Egg.php b/src/devmine/server/calculations/entity/Egg.php new file mode 100644 index 0000000..660d6c2 --- /dev/null +++ b/src/devmine/server/calculations/entity/Egg.php @@ -0,0 +1,77 @@ +closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $hasUpdate = true; //Chance to spawn chicken + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = Egg::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} diff --git a/src/devmine/server/calculations/entity/EnderCrystal.php b/src/devmine/server/calculations/entity/EnderCrystal.php new file mode 100644 index 0000000..fe8eac7 --- /dev/null +++ b/src/devmine/server/calculations/entity/EnderCrystal.php @@ -0,0 +1,58 @@ +eid = $this->getId(); + $pk->type = EnderCrystal::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = 0; + $pk->speedY = 0; + $pk->speedZ = 0; + $pk->yaw = 0; + $pk->pitch = 0; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} diff --git a/src/devmine/server/calculations/entity/EnderPearl.php b/src/devmine/server/calculations/entity/EnderPearl.php new file mode 100644 index 0000000..4477759 --- /dev/null +++ b/src/devmine/server/calculations/entity/EnderPearl.php @@ -0,0 +1,77 @@ +closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + /** @return Player */ + public function getSpawner(){ + return $this->player; + } + + public function setSpawner(Player $player){ + $this->player = $player; + } + + public function close(){ + if ($this->getSpawner() instanceof Player) { + $this->getSpawner()->teleport($this); + } + parent::close(); + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = self::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} diff --git a/src/devmine/server/calculations/entity/Enderman.php b/src/devmine/server/calculations/entity/Enderman.php new file mode 100644 index 0000000..8f4a466 --- /dev/null +++ b/src/devmine/server/calculations/entity/Enderman.php @@ -0,0 +1,57 @@ +eid = $this->getId(); + $pk->type = Enderman::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Entity.php b/src/devmine/server/calculations/entity/Entity.php new file mode 100644 index 0000000..6009990 --- /dev/null +++ b/src/devmine/server/calculations/entity/Entity.php @@ -0,0 +1,1919 @@ + [self::DATA_TYPE_LONG, 0], + self::DATA_AIR => [self::DATA_TYPE_SHORT, 400], + self::DATA_MAX_AIR => [self::DATA_TYPE_SHORT, 400], + self::DATA_NAMETAG => [self::DATA_TYPE_STRING, ""], + //self::DATA_SILENT => [self::DATA_TYPE_BYTE, 0], + self::DATA_LEAD_HOLDER => [self::DATA_TYPE_LONG, -1], + self::DATA_LEAD => [self::DATA_TYPE_BYTE, 0], + ]; + + public $passenger = null; + public $vehicle = null; + + /** @var Chunk */ + public $chunk; + + protected $lastDamageCause = null; + + /** @var Block[] */ + private $blocksAround = []; + + public $lastX = null; + public $lastY = null; + public $lastZ = null; + + public $motionX; + public $motionY; + public $motionZ; + /** @var Vector3 */ + public $temporalVector; + public $lastMotionX; + public $lastMotionY; + public $lastMotionZ; + + public $lastYaw; + public $lastPitch; + + /** @var AxisAlignedBB */ + public $boundingBox; + public $onGround; + public $inBlock = false; + public $positionChanged; + public $motionChanged; + public $deadTicks = 0; + protected $age = 0; + + public $height; + + public $eyeHeight = null; + + public $width; + public $length; + + /** @var int */ + private $health = 20; + private $maxHealth = 20; + + protected $ySize = 0; + protected $stepHeight = 0; + public $keepMovement = false; + + public $fallDistance = 0; + public $ticksLived = 0; + public $lastUpdate; + public $maxFireTicks; + public $fireTicks = 0; + public $namedtag; + public $canCollide = true; + + protected $isStatic = false; + + public $isCollided = false; + public $isCollidedHorizontally = false; + public $isCollidedVertically = false; + + public $noDamageTicks; + protected $justCreated; + protected $fireProof; + private $invulnerable; + + /** @var AttributeMap */ + protected $attributeMap; + + protected $gravity; + protected $drag; + + /** @var Server */ + protected $server; + + public $closed = false; + + /** @var \devmine\events\TimingsHandler */ + protected $timings; + protected $isPlayer = false; + + /** @var Entity */ + protected $linkedEntity = null; + /** 0 no linked 1 linked other 2 be linked */ + protected $linkedType = null; + + protected $riding = null; + + /** @var PressurePlate */ + protected $activatedPressurePlates = []; + + public $dropExp = [0, 0]; + + + public function __construct(Chunk $chunk, CompoundTag $nbt){ + if($chunk === null or $chunk->getProvider() === null){ + throw new ChunkException("Invalid garbage Chunk given to Entity"); + } + + $this->timings = Timings::getEntityTimings($this); + + $this->isPlayer = $this instanceof Player; + + $this->temporalVector = new Vector3(); + + if($this->eyeHeight === null){ + $this->eyeHeight = $this->height / 2 + 0.1; + } + + $this->id = Entity::$entityCount++; + $this->justCreated = true; + $this->namedtag = $nbt; + + $this->chunk = $chunk; + $this->setLevel($chunk->getProvider()->getLevel()); + $this->server = $chunk->getProvider()->getLevel()->getServer(); + + $this->boundingBox = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + $this->setPositionAndRotation( + $this->temporalVector->setComponents( + $this->namedtag["Pos"][0], + $this->namedtag["Pos"][1], + $this->namedtag["Pos"][2] + ), + $this->namedtag->Rotation[0], + $this->namedtag->Rotation[1] + ); + $this->setMotion($this->temporalVector->setComponents($this->namedtag["Motion"][0], $this->namedtag["Motion"][1], $this->namedtag["Motion"][2])); + + if(is_nan($this->x) or is_infinite($this->x) or is_nan($this->y) or is_infinite($this->y) or is_nan($this->z) or is_infinite($this->z)){ + throw new \InvalidStateException("Invalid entity coordinates"); + } + + if(!isset($this->namedtag->FallDistance)){ + $this->namedtag->FallDistance = new FloatTag("FallDistance", 0); + } + $this->fallDistance = $this->namedtag["FallDistance"]; + + if(!isset($this->namedtag->Fire)){ + $this->namedtag->Fire = new ShortTag("Fire", 0); + } + $this->fireTicks = $this->namedtag["Fire"]; + + if(!isset($this->namedtag->Air)){ + $this->namedtag->Air = new ShortTag("Air", 300); + } + $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, $this->namedtag["Air"]); + + if(!isset($this->namedtag->OnGround)){ + $this->namedtag->OnGround = new ByteTag("OnGround", 0); + } + $this->onGround = $this->namedtag["OnGround"] > 0 ? true : false; + + if(!isset($this->namedtag->Invulnerable)){ + $this->namedtag->Invulnerable = new ByteTag("Invulnerable", 0); + } + $this->invulnerable = $this->namedtag["Invulnerable"] > 0 ? true : false; + + $this->attributeMap = new AttributeMap(); + + $this->chunk->addEntity($this); + $this->level->addEntity($this); + $this->initEntity(); + $this->lastUpdate = $this->server->getTick(); + $this->server->getPluginManager()->callEvent(new EntitySpawnEvent($this)); + + $this->scheduleUpdate(); + + } + + /** + * @return int + */ + public function getDropExpMin() : int{ + return $this->dropExp[0]; + } + + /** + * @return int + */ + public function getDropExpMax() : int{ + return $this->dropExp[1]; + } + + /** + * @return string + */ + public function getNameTag(){ + return $this->getDataProperty(self::DATA_NAMETAG); + } + + /** + * @return bool + */ + public function isNameTagVisible(){ + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_CAN_SHOW_NAMETAG); + } + + + /** + * @return bool + */ + public function isNameTagAlwaysVisible(){ + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ALWAYS_SHOW_NAMETAG); + } + + /** + * @param string $name + */ + public function setNameTag($name){ + $this->setDataProperty(self::DATA_NAMETAG, self::DATA_TYPE_STRING, $name); + } + + /** + * @param bool $value + */ + public function setNameTagVisible($value = true){ + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_CAN_SHOW_NAMETAG, $value); + } + /** + * @param bool $value + */ + public function setNameTagAlwaysVisible($value = true){ + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ALWAYS_SHOW_NAMETAG, $value); + } + + public function isSneaking(){ + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_SNEAKING); + } + + public function setSneaking($value = true){ + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_SNEAKING, (bool) $value); + } + + public function isSprinting(){ + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_SPRINTING); + } + + public function setSprinting($value = true){ + if($value !== $this->isSprinting()){ + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_SPRINTING, (bool) $value); + $attr = $this->attributeMap->getAttribute(Attribute::MOVEMENT_SPEED); + $attr->setValue($value ? ($attr->getValue() * 1.3) : ($attr->getValue() / 1.3)); + } + } + + public function isImmobile() : bool{ + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_IMMOBILE); + } + public function setImmobile($value = true) : bool{ + return $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_IMMOBILE, $value); + } + + /** + * @return Effect[] + */ + public function getEffects(){ + return $this->effects; + } + + public function removeAllEffects(){ + foreach($this->effects as $effect){ + $this->removeEffect($effect->getId()); + } + } + + public function removeEffect($effectId){ + Server::getInstance()->getPluginManager()->callEvent($ev = new EntityEffectRemoveEvent($this, $effectId)); + if($ev->isCancelled()){ + return false; + } + if(isset($this->effects[$effectId])){ + $effect = $this->effects[$effectId]; + unset($this->effects[$effectId]); + $effect->remove($this); + if($effectId === Effect::ABSORPTION and $this instanceof Human){ + $this->setAbsorption(0); + } + + $this->recalculateEffectColor(); + return true; + } + } + + public function getEffect($effectId){ + return isset($this->effects[$effectId]) ? $this->effects[$effectId] : null; + } + + public function hasEffect($effectId){ + return isset($this->effects[$effectId]); + } + + public function addEffect(Effect $effect){ + Server::getInstance()->getPluginManager()->callEvent($ev = new EntityEffectAddEvent($this, $effect)); + if($ev->isCancelled()){ + return false; + } + if($effect->getId() === Effect::HEALTH_BOOST){ + $this->setHealth($this->getHealth() + 4 * ($effect->getAmplifier() + 1)); + } + if($effect->getId() === Effect::ABSORPTION and $this instanceof Human){ + $this->setAbsorption(4 * ($effect->getAmplifier() + 1)); + } + + if(isset($this->effects[$effect->getId()])){ + $oldEffect = $this->effects[$effect->getId()]; + if(($effect->getAmplifier() <= ($oldEffect->getAmplifier())) and $effect->getDuration() < $oldEffect->getDuration()){ + return; + } + $effect->add($this, true, $oldEffect); + }else{ + $effect->add($this, false); + } + + $this->effects[$effect->getId()] = $effect; + + $this->recalculateEffectColor(); + return true; + } + + protected function recalculateEffectColor(){ + $color = [0, 0, 0]; //RGB + $count = 0; + $ambient = true; + foreach($this->effects as $effect){ + if($effect->isVisible()){ + $c = $effect->getColor(); + $color[0] += $c[0] * ($effect->getAmplifier() + 1); + $color[1] += $c[1] * ($effect->getAmplifier() + 1); + $color[2] += $c[2] * ($effect->getAmplifier() + 1); + $count += $effect->getAmplifier() + 1; + if(!$effect->isAmbient()){ + $ambient = false; + } + } + } + + if($count > 0){ + $r = ($color[0] / $count) & 0xff; + $g = ($color[1] / $count) & 0xff; + $b = ($color[2] / $count) & 0xff; + + $this->setDataProperty(Entity::DATA_POTION_COLOR, Entity::DATA_TYPE_INT, ($r << 16) + ($g << 8) + $b); + $this->setDataProperty(Entity::DATA_POTION_AMBIENT, Entity::DATA_TYPE_BYTE, $ambient ? 1 : 0); + }else{ + $this->setDataProperty(Entity::DATA_POTION_COLOR, Entity::DATA_TYPE_INT, 0); + $this->setDataProperty(Entity::DATA_POTION_AMBIENT, Entity::DATA_TYPE_BYTE, 0); + } + } + + /** + * @param int|string $type + * @param Chunk $chunk + * @param CompoundTag $nbt + * @param $args + * + * @return Entity|Projectile + */ + public static function createEntity($type, Chunk $chunk, CompoundTag $nbt, ...$args){ + if(isset(self::$knownEntities[$type])){ + $class = self::$knownEntities[$type]; + return new $class($chunk, $nbt, ...$args); + } + + return null; + } + + public static function registerEntity($className, $force = false){ + $class = new \ReflectionClass($className); + if(is_a($className, Entity::class, true) and !$class->isAbstract()){ + if($className::NETWORK_ID !== -1){ + self::$knownEntities[$className::NETWORK_ID] = $className; + }elseif(!$force){ + return false; + } + + self::$knownEntities[$class->getShortName()] = $className; + self::$shortNames[$className] = $class->getShortName(); + return true; + } + + return false; + } + + /** + * Returns the short save name + * + * @return string + */ + public function getSaveId(){ + return self::$shortNames[static::class]; + } + + public function saveNBT(){ + if(!($this instanceof Player)){ + $this->namedtag->id = new StringTag("id", $this->getSaveId()); + if($this->getNameTag() !== ""){ + $this->namedtag->CustomName = new StringTag("CustomName", $this->getNameTag()); + $this->namedtag->CustomNameVisible = new StringTag("CustomNameVisible", $this->isNameTagVisible()); + }else{ + unset($this->namedtag->CustomName); + unset($this->namedtag->CustomNameVisible); + } + } + + $this->namedtag->Pos = new ListTag("Pos", [ + new DoubleTag(0, $this->x), + new DoubleTag(1, $this->y), + new DoubleTag(2, $this->z) + ]); + + $this->namedtag->Motion = new ListTag("Motion", [ + new DoubleTag(0, $this->motionX), + new DoubleTag(1, $this->motionY), + new DoubleTag(2, $this->motionZ) + ]); + + $this->namedtag->Rotation = new ListTag("Rotation", [ + new FloatTag(0, $this->yaw), + new FloatTag(1, $this->pitch) + ]); + + $this->namedtag->FallDistance = new FloatTag("FallDistance", $this->fallDistance); + $this->namedtag->Fire = new ShortTag("Fire", $this->fireTicks); + $this->namedtag->Air = new ShortTag("Air", $this->getDataProperty(self::DATA_AIR)); + $this->namedtag->OnGround = new ByteTag("OnGround", $this->onGround == true ? 1 : 0); + $this->namedtag->Invulnerable = new ByteTag("Invulnerable", $this->invulnerable == true ? 1 : 0); + + if(count($this->effects) > 0){ + $effects = []; + foreach($this->effects as $effect){ + $effects[$effect->getId()] = new CompoundTag($effect->getId(), [ + "Id" => new ByteTag("Id", $effect->getId()), + "Amplifier" => new ByteTag("Amplifier", $effect->getAmplifier()), + "Duration" => new IntTag("Duration", $effect->getDuration()), + "Ambient" => new ByteTag("Ambient", 0), + "ShowParticles" => new ByteTag("ShowParticles", $effect->isVisible() ? 1 : 0) + ]); + } + + $this->namedtag->ActiveEffects = new ListTag("ActiveEffects", $effects); + }else{ + unset($this->namedtag->ActiveEffects); + } + } + + protected function initEntity(){ + if(!($this->namedtag instanceof CompoundTag)){ + throw new \InvalidArgumentException("Expecting CompoundTag, received " . get_class($this->namedtag)); + } + + if(isset($this->namedtag->CustomName)){ + $this->setNameTag($this->namedtag["CustomName"]); + if(isset($this->namedtag->CustomNameVisible)){ + $this->setNameTagVisible($this->namedtag["CustomNameVisible"] > 0); + } + } + + $this->scheduleUpdate(); + + $this->addAttributes(); + + if(isset($this->namedtag->ActiveEffects)){ + foreach($this->namedtag->ActiveEffects->getValue() as $e){ + $effect = Effect::getEffect($e["Id"]); + if($effect === null){ + continue; + } + + $effect->setAmplifier($e["Amplifier"])->setDuration($e["Duration"])->setVisible($e["ShowParticles"] > 0); + + $this->addEffect($effect); + } + } + + } + + protected function addAttributes(){ + } + + /** + * @return Player[] + */ + public function getViewers(){ + return $this->hasSpawned; + } + + /** + * @param Player $player + */ + public function spawnTo(Player $player){ + if(!isset($this->hasSpawned[$player->getLoaderId()]) and isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])){ + $this->hasSpawned[$player->getLoaderId()] = $player; + } + } + + public function sendPotionEffects(Player $player){ + foreach($this->effects as $effect){ + $pk = new MobEffectPacket(); + $pk->eid = 0; + $pk->effectId = $effect->getId(); + $pk->amplifier = $effect->getAmplifier(); + $pk->particles = $effect->isVisible(); + $pk->duration = $effect->getDuration(); + $pk->eventId = MobEffectPacket::EVENT_ADD; + + $player->dataPacket($pk); + } + } + + /** + * @param Player[]|Player $player + * @param array $data Properly formatted entity data, defaults to everything + */ + public function sendData($player, array $data = null){ + if(!is_array($player)){ + $player = [$player]; + } + + $pk = new SetEntityDataPacket(); + $pk->eid = ($player === $this ? 0 : $this->getId()); + $pk->metadata = $data === null ? $this->dataProperties : $data; + + foreach($player as $p){ + if($p === $this){ + continue; + } + $p->dataPacket(clone $pk); + } + if($this instanceof Player){ + $pk->eid = 0; + $this->dataPacket($pk); + } + } + + /** + * @param Player $player + */ + public function despawnFrom(Player $player){ + if(isset($this->hasSpawned[$player->getLoaderId()])){ + $pk = new RemoveEntityPacket(); + $pk->eid = $this->getId(); + $player->dataPacket($pk); + unset($this->hasSpawned[$player->getLoaderId()]); + } + } + + /** + * @param float $damage + * @param EntityDamageEvent $source + * + * @return bool + */ + public function attack($damage, EntityDamageEvent $source){ + if($this->hasEffect(Effect::FIRE_RESISTANCE) + and ($source->getCause() === EntityDamageEvent::CAUSE_FIRE + or $source->getCause() === EntityDamageEvent::CAUSE_FIRE_TICK + or $source->getCause() === EntityDamageEvent::CAUSE_LAVA) + ){ + $source->setCancelled(); + } + + $this->server->getPluginManager()->callEvent($source); + if($source->isCancelled()){ + return false; + } + $this->setLastDamageCause($source); + + if($this instanceof Human){ + $damage = round($source->getFinalDamage()); + if($this->getAbsorption() > 0){ + $absorption = $this->getAbsorption() - $damage; + $this->setAbsorption($absorption <= 0 ? 0 : $absorption); + $this->setHealth($this->getHealth() + $absorption); + }else{ + $this->setHealth($this->getHealth() - $damage); + } + }else{ + $this->setHealth($this->getHealth() - round($source->getFinalDamage())); + } + return true; + } + + /** + * @param float $amount + * @param EntityRegainHealthEvent $source + * + */ + public function heal($amount, EntityRegainHealthEvent $source){ + $this->server->getPluginManager()->callEvent($source); + if($source->isCancelled()){ + return; + } + + $this->setHealth($this->getHealth() + $source->getAmount()); + } + + /** + * @return int + */ + public function getHealth(){ + return $this->health; + } + + public function isAlive(){ + return $this->health > 0; + } + + /** + * Sets the health of the Entity. This won't send any update to the players + * + * @param int $amount + */ + public function setHealth($amount){ + $amount = (int) $amount; + if($amount === $this->health){ + return; + } + + if($amount <= 0){ + if($this->isAlive()){ + $this->kill(); + } + }elseif($amount <= $this->getMaxHealth() or $amount < $this->health){ + $this->health = (int) $amount; + }else{ + $this->health = $this->getMaxHealth(); + } + } + + /** + * @param EntityDamageEvent $type + */ + public function setLastDamageCause(EntityDamageEvent $type){ + $this->lastDamageCause = $type; + } + + /** + * @return EntityDamageEvent|null + */ + public function getLastDamageCause(){ + return $this->lastDamageCause; + } + + public function getAttributeMap(){ + return $this->attributeMap; + } + + /** + * @return int + */ + public function getMaxHealth(){ + return $this->maxHealth + ($this->hasEffect(Effect::HEALTH_BOOST) ? 4 * ($this->getEffect(Effect::HEALTH_BOOST)->getAmplifier() + 1) : 0); + } + + /** + * @param int $amount + */ + public function setMaxHealth($amount){ + $this->maxHealth = (int) $amount; + } + + public function canCollideWith(Entity $entity){ + return !$this->justCreated and $entity !== $this; + } + + protected function checkObstruction($x, $y, $z){ + $i = Math::floorFloat($x); + $j = Math::floorFloat($y); + $k = Math::floorFloat($z); + + $diffX = $x - $i; + $diffY = $y - $j; + $diffZ = $z - $k; + + if(Block::$solid[$this->level->getBlockIdAt($i, $j, $k)]){ + $flag = !Block::$solid[$this->level->getBlockIdAt($i - 1, $j, $k)]; + $flag1 = !Block::$solid[$this->level->getBlockIdAt($i + 1, $j, $k)]; + $flag2 = !Block::$solid[$this->level->getBlockIdAt($i, $j - 1, $k)]; + $flag3 = !Block::$solid[$this->level->getBlockIdAt($i, $j + 1, $k)]; + $flag4 = !Block::$solid[$this->level->getBlockIdAt($i, $j, $k - 1)]; + $flag5 = !Block::$solid[$this->level->getBlockIdAt($i, $j, $k + 1)]; + + $direction = -1; + $limit = 9999; + + if($flag){ + $limit = $diffX; + $direction = 0; + } + + if($flag1 and 1 - $diffX < $limit){ + $limit = 1 - $diffX; + $direction = 1; + } + + if($flag2 and $diffY < $limit){ + $limit = $diffY; + $direction = 2; + } + + if($flag3 and 1 - $diffY < $limit){ + $limit = 1 - $diffY; + $direction = 3; + } + + if($flag4 and $diffZ < $limit){ + $limit = $diffZ; + $direction = 4; + } + + if($flag5 and 1 - $diffZ < $limit){ + $direction = 5; + } + + $force = lcg_value() * 0.2 + 0.1; + + if($direction === 0){ + $this->motionX = -$force; + + return true; + } + + if($direction === 1){ + $this->motionX = $force; + + return true; + } + + if($direction === 2){ + $this->motionY = -$force; + + return true; + } + + if($direction === 3){ + $this->motionY = $force; + + return true; + } + + if($direction === 4){ + $this->motionZ = -$force; + + return true; + } + + if($direction === 5){ + $this->motionZ = $force; + + return true; + } + } + + return false; + } + + public function entityBaseTick($tickDiff = 1){ + + Timings::$timerEntityBaseTick->startTiming(); + //TODO: check vehicles + + $this->blocksAround = null; + $this->justCreated = false; + + if(!$this->isAlive()){ + $this->removeAllEffects(); + $this->despawnFromAll(); + if(!$this->isPlayer){ + $this->close(); + } + + Timings::$timerEntityBaseTick->stopTiming(); + return false; + } + + if(count($this->effects) > 0){ + foreach($this->effects as $effect){ + if($effect->canTick()){ + $effect->applyEffect($this); + } + $effect->setDuration($effect->getDuration() - $tickDiff); + if($effect->getDuration() <= 0){ + $this->removeEffect($effect->getId()); + } + } + } + + $hasUpdate = false; + + $this->checkBlockCollision(); + + if($this->y <= -16 and $this->isAlive()){ + $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10); + $this->attack($ev->getFinalDamage(), $ev); + $hasUpdate = true; + } + + if($this->fireTicks > 0){ + if($this->fireProof){ + $this->fireTicks -= 4 * $tickDiff; + if($this->fireTicks < 0){ + $this->fireTicks = 0; + } + }else{ + if(!$this->hasEffect(Effect::FIRE_RESISTANCE) and (($this->fireTicks % 20) === 0 or $tickDiff > 20)){ + $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FIRE_TICK, 1); + $this->attack($ev->getFinalDamage(), $ev); + } + $this->fireTicks -= $tickDiff; + } + + if($this->fireTicks <= 0 && $this->fireTicks > -10){ + $this->extinguish(); + }else{ + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ONFIRE, true); + $hasUpdate = true; + } + } + + if($this->noDamageTicks > 0){ + $this->noDamageTicks -= $tickDiff; + if($this->noDamageTicks < 0){ + $this->noDamageTicks = 0; + } + } + + $this->age += $tickDiff; + $this->ticksLived += $tickDiff; + + Timings::$timerEntityBaseTick->stopTiming(); + + return $hasUpdate; + } + + protected function updateMovement(){ + $diffPosition = ($this->x - $this->lastX) ** 2 + ($this->y - $this->lastY) ** 2 + ($this->z - $this->lastZ) ** 2; + $diffRotation = ($this->yaw - $this->lastYaw) ** 2 + ($this->pitch - $this->lastPitch) ** 2; + + $diffMotion = ($this->motionX - $this->lastMotionX) ** 2 + ($this->motionY - $this->lastMotionY) ** 2 + ($this->motionZ - $this->lastMotionZ) ** 2; + + if($diffPosition > 0.04 or $diffRotation > 2.25 and ($diffMotion > 0.0001 and $this->getMotion()->lengthSquared() <= 0.00001)){ //0.2 ** 2, 1.5 ** 2 + $this->lastX = $this->x; + $this->lastY = $this->y; + $this->lastZ = $this->z; + + $this->lastYaw = $this->yaw; + $this->lastPitch = $this->pitch; + + $this->addMovement($this->x, $this->y + $this->getEyeHeight(), $this->z, $this->yaw, $this->pitch, $this->yaw); + } + + if($diffMotion > 0.0025 or ($diffMotion > 0.0001 and $this->getMotion()->lengthSquared() <= 0.0001)){ //0.05 ** 2 + $this->lastMotionX = $this->motionX; + $this->lastMotionY = $this->motionY; + $this->lastMotionZ = $this->motionZ; + + $this->level->addEntityMotion($this->chunk->getX(), $this->chunk->getZ(), $this->id, $this->motionX, $this->motionY, $this->motionZ); + } + } + + public function addMovement($x, $y, $z, $yaw, $pitch, $headYaw = null){ + $this->level->addEntityMovement($this->chunk->getX(), $this->chunk->getZ(), $this->id, $x, $y, $z, $yaw, $pitch, $headYaw === null ? $yaw : $headYaw); + } + + /** + * @return Vector3 + */ + public function getDirectionVector(){ + $y = -sin(deg2rad($this->pitch)); + $xz = cos(deg2rad($this->pitch)); + $x = -$xz * sin(deg2rad($this->yaw)); + $z = $xz * cos(deg2rad($this->yaw)); + + return $this->temporalVector->setComponents($x, $y, $z)->normalize(); + } + + public function getDirectionPlane(){ + return (new Vector2(-cos(deg2rad($this->yaw) - M_PI_2), -sin(deg2rad($this->yaw) - M_PI_2)))->normalize(); + } + + public function onUpdate($currentTick){ + if($this->closed){ + return false; + } + + if(!$this->isAlive()){ + ++$this->deadTicks; + if($this->deadTicks >= 10){ + $this->despawnFromAll(); + if(!$this->isPlayer){ + $this->close(); + } + } + return $this->deadTicks < 10; + } + + $tickDiff = $currentTick - $this->lastUpdate; + if($tickDiff <= 0){ + return false; + } + + $this->lastUpdate = $currentTick; + + $this->timings->startTiming(); + + $hasUpdate = $this->entityBaseTick($tickDiff); + + $this->updateMovement(); + + $this->timings->stopTiming(); + + //if($this->isStatic()) + return $hasUpdate; + //return !($this instanceof Player); + } + + public final function scheduleUpdate(){ + $this->level->updateEntities[$this->id] = $this; + } + + public function isOnFire(){ + return $this->fireTicks > 0; + } + + public function setOnFire($seconds){ + $ticks = $seconds * 20; + if($ticks > $this->fireTicks){ + $this->fireTicks = $ticks; + } + } + + public function getDirection(){ + $rotation = ($this->yaw - 90) % 360; + if($rotation < 0){ + $rotation += 360.0; + } + if((0 <= $rotation and $rotation < 45) or (315 <= $rotation and $rotation < 360)){ + return 2; //North + }elseif(45 <= $rotation and $rotation < 135){ + return 3; //East + }elseif(135 <= $rotation and $rotation < 225){ + return 0; //South + }elseif(225 <= $rotation and $rotation < 315){ + return 1; //West + }else{ + return null; + } + } + + public function extinguish(){ + $this->fireTicks = 0; + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ONFIRE, false); + } + + public function canTriggerWalking(){ + return true; + } + + public function resetFallDistance(){ + $this->fallDistance = 0; + } + + protected function updateFallState($distanceThisTick, $onGround){ + if($onGround === true){ + if($this->fallDistance > 0){ + if($this instanceof Living){ + $this->fall($this->fallDistance); + } + $this->resetFallDistance(); + } + }elseif($distanceThisTick < 0){ + $this->fallDistance -= $distanceThisTick; + } + } + + public function getBoundingBox(){ + return $this->boundingBox; + } + + public function fall($fallDistance){ + if($this instanceof Player and $this->isSpectator()){ + return; + } + if($this->getLevel()->getServer()->destroyBlockParticle and $fallDistance > 3){ + $this->getLevel()->addParticle(new DestroyBlockParticle($this, $this->getLevel()->getBlock($this->floor()->subtract(0, 1, 0)))); + } + if($this->isInsideOfWater()){ + return; + } + $damage = floor($fallDistance - 3 - ($this->hasEffect(Effect::JUMP) ? $this->getEffect(Effect::JUMP)->getAmplifier() + 1 : 0)); + + //Get the block directly beneath the player's feet, check if it is a slime block + if($this->getLevel()->getBlock($this->floor()->subtract(0, 1, 0)) instanceof SlimeBlock){ + $damage = 0; + } + if($damage > 0){ + $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FALL, $damage); + $this->attack($ev->getFinalDamage(), $ev); + } + } + + public function handleLavaMovement(){ //TODO + + } + + public function getEyeHeight(){ + return $this->eyeHeight; + } + + public function moveFlying(){ //TODO + + } + + public function onCollideWithPlayer(Human $entityPlayer){ + + } + + protected function switchLevel(Level $targetLevel){ + if($this->closed){ + return false; + } + + if($this->isValid()){ + $this->server->getPluginManager()->callEvent($ev = new EntityLevelChangeEvent($this, $this->level, $targetLevel)); + if($ev->isCancelled()){ + return false; + } + + $this->level->removeEntity($this); + if($this->chunk !== null){ + $this->chunk->removeEntity($this); + } + $this->despawnFromAll(); + } + + $this->setLevel($targetLevel); + $this->level->addEntity($this); + $this->chunk = null; + + return true; + } + + public function getPosition(){ + return new Position($this->x, $this->y, $this->z, $this->level); + } + + public function getLocation(){ + return new Location($this->x, $this->y, $this->z, $this->yaw, $this->pitch, $this->level); + } + + public function isInsideOfPortal(){ + $blocks = $this->getBlocksAround(); + + foreach($blocks as $block){ + if($block instanceof Portal){ + return true; + } + } + + return false; + } + + public function isInsideOfWater(){ + $block = $this->level->getBlock($this->temporalVector->setComponents(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z))); + + if($block instanceof Water){ + $f = ($block->y + 1) - ($block->getFluidHeightPercent() - 0.1111111); + return $y < $f; + } + + return false; + } + + public function isInsideOfSolid(){ + $block = $this->level->getBlock($this->temporalVector->setComponents(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z))); + + $bb = $block->getBoundingBox(); + + if($bb !== null and $block->isSolid() and !$block->isTransparent() and $bb->intersectsWith($this->getBoundingBox())){ + return true; + } + return false; + } + + public function isInsideOfFire(){ + foreach($this->getBlocksAround() as $block){ + if($block instanceof Fire){ + return true; + } + } + return false; + } + + public function fastMove($dx, $dy, $dz){ + if($dx == 0 and $dz == 0 and $dy == 0){ + return true; + } + + Timings::$entityMoveTimer->startTiming(); + + /*$newBB = $this->boundingBox->getOffsetBoundingBox($dx, $dy, $dz); + + $list = $this->level->getCollisionCubes($this, $newBB, false); + + if(count($list) === 0){ + $this->boundingBox = $newBB; + }*/ + + $this->x = ($this->boundingBox->minX + $this->boundingBox->maxX) / 2; + $this->y = $this->boundingBox->minY - $this->ySize; + $this->z = ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2; + + $this->checkChunks(); + + if(!$this->onGround or $dy != 0){ + $bb = clone $this->boundingBox; + $bb->minY -= 0.75; + $this->onGround = false; + if(!$this->level->getBlock(new Vector3($this->x, $this->y - 1, $this->z))->isTransparent()) + $this->onGround = true; + /* + if(count($this->level->getCollisionBlocks($bb)) > 0){ + $this->onGround = true; + }*/ + } + $this->isCollided = $this->onGround; + $this->updateFallState($dy, $this->onGround); + + + Timings::$entityMoveTimer->stopTiming(); + + return true; + } + + public function move($dx, $dy, $dz){ + + if($dx == 0 and $dz == 0 and $dy == 0){ + return true; + } + + if($this->keepMovement){ + $this->boundingBox->offset($dx, $dy, $dz); + $this->setPosition($this->temporalVector->setComponents(($this->boundingBox->minX + $this->boundingBox->maxX) / 2, $this->boundingBox->minY, ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2)); + $this->onGround = $this->isPlayer ? true : false; + return true; + }else{ + + Timings::$entityMoveTimer->startTiming(); + + $this->ySize *= 0.4; + + /* + if($this->isColliding){ //With cobweb? + $this->isColliding = false; + $dx *= 0.25; + $dy *= 0.05; + $dz *= 0.25; + $this->motionX = 0; + $this->motionY = 0; + $this->motionZ = 0; + } + */ + + $movX = $dx; + $movY = $dy; + $movZ = $dz; + + $axisalignedbb = clone $this->boundingBox; + + /*$sneakFlag = $this->onGround and $this instanceof Player; + + if($sneakFlag){ + for($mov = 0.05; $dx != 0.0 and count($this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, -1, 0))) === 0; $movX = $dx){ + if($dx < $mov and $dx >= -$mov){ + $dx = 0; + }elseif($dx > 0){ + $dx -= $mov; + }else{ + $dx += $mov; + } + } + + for(; $dz != 0.0 and count($this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, -1, $dz))) === 0; $movZ = $dz){ + if($dz < $mov and $dz >= -$mov){ + $dz = 0; + }elseif($dz > 0){ + $dz -= $mov; + }else{ + $dz += $mov; + } + } + + //TODO: big messy loop + }*/ + + $list = $this->level->getCollisionCubes($this, $this->level->getTickRate() > 1 ? $this->boundingBox->getOffsetBoundingBox($dx, $dy, $dz) : $this->boundingBox->addCoord($dx, $dy, $dz), false); + + foreach($list as $bb){ + $dy = $bb->calculateYOffset($this->boundingBox, $dy); + } + + $this->boundingBox->offset(0, $dy, 0); + + $fallingFlag = ($this->onGround or ($dy != $movY and $movY < 0)); + + foreach($list as $bb){ + $dx = $bb->calculateXOffset($this->boundingBox, $dx); + } + + $this->boundingBox->offset($dx, 0, 0); + + foreach($list as $bb){ + $dz = $bb->calculateZOffset($this->boundingBox, $dz); + } + + $this->boundingBox->offset(0, 0, $dz); + + + if($this->stepHeight > 0 and $fallingFlag and $this->ySize < 0.05 and ($movX != $dx or $movZ != $dz)){ + $cx = $dx; + $cy = $dy; + $cz = $dz; + $dx = $movX; + $dy = $this->stepHeight; + $dz = $movZ; + + $axisalignedbb1 = clone $this->boundingBox; + + $this->boundingBox->setBB($axisalignedbb); + + $list = $this->level->getCollisionCubes($this, $this->boundingBox->addCoord($dx, $dy, $dz), false); + + foreach($list as $bb){ + $dy = $bb->calculateYOffset($this->boundingBox, $dy); + } + + $this->boundingBox->offset(0, $dy, 0); + + foreach($list as $bb){ + $dx = $bb->calculateXOffset($this->boundingBox, $dx); + } + + $this->boundingBox->offset($dx, 0, 0); + + foreach($list as $bb){ + $dz = $bb->calculateZOffset($this->boundingBox, $dz); + } + + $this->boundingBox->offset(0, 0, $dz); + + if(($cx ** 2 + $cz ** 2) >= ($dx ** 2 + $dz ** 2)){ + $dx = $cx; + $dy = $cy; + $dz = $cz; + $this->boundingBox->setBB($axisalignedbb1); + }else{ + $this->ySize += 0.5; + } + + } + + $this->x = ($this->boundingBox->minX + $this->boundingBox->maxX) / 2; + $this->y = $this->boundingBox->minY - $this->ySize; + $this->z = ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2; + + $this->checkChunks(); + + $this->checkGroundState($movX, $movY, $movZ, $dx, $dy, $dz); + $this->updateFallState($dy, $this->onGround); + + if($movX != $dx){ + $this->motionX = 0; + } + + if($movY != $dy){ + $this->motionY = 0; + } + + if($movZ != $dz){ + $this->motionZ = 0; + } + + + //TODO: vehicle collision events (first we need to spawn them!) + + Timings::$entityMoveTimer->stopTiming(); + + return true; + } + } + + protected function checkGroundState($movX, $movY, $movZ, $dx, $dy, $dz){ + $this->isCollidedVertically = $movY != $dy; + $this->isCollidedHorizontally = ($movX != $dx or $movZ != $dz); + $this->isCollided = ($this->isCollidedHorizontally or $this->isCollidedVertically); + $this->onGround = ($movY != $dy and $movY < 0); + } + + public function getBlocksAround(){ + if($this->blocksAround === null){ + $minX = Math::floorFloat($this->boundingBox->minX); + $minY = Math::floorFloat($this->boundingBox->minY); + $minZ = Math::floorFloat($this->boundingBox->minZ); + $maxX = Math::ceilFloat($this->boundingBox->maxX); + $maxY = Math::ceilFloat($this->boundingBox->maxY); + $maxZ = Math::ceilFloat($this->boundingBox->maxZ); + + $this->blocksAround = []; + + for($z = $minZ; $z <= $maxZ; ++$z){ + for($x = $minX; $x <= $maxX; ++$x){ + for($y = $minY; $y <= $maxY; ++$y){ + $block = $this->level->getBlock($this->temporalVector->setComponents($x, $y, $z)); + if($block->hasEntityCollision()){ + $this->blocksAround[Level::blockHash($block->x, $block->y, $block->z)] = $block; + } + } + } + } + } + + return $this->blocksAround; + } + + protected function checkBlockCollision(){ + $vector = new Vector3(0, 0, 0); + + foreach($blocksaround = $this->getBlocksAround() as $block){ + $block->onEntityCollide($this); + if($this->getLevel()->getServer()->redstoneEnabled and !$this->isPlayer){ + if($block instanceof PressurePlate){ + $this->activatedPressurePlates[Level::blockHash($block->x, $block->y, $block->z)] = $block; + } + } + $block->addVelocityToEntity($this, $vector); + } + + if($this->getLevel()->getServer()->redstoneEnabled and !$this->isPlayer){ + /** @var \devmine\inventory\blocks\PressurePlate $block * */ + foreach($this->activatedPressurePlates as $key => $block){ + if(!isset($blocksaround[$key])) $block->checkActivation(); + } + } + + if($vector->lengthSquared() > 0){ + $vector = $vector->normalize(); + $d = 0.014; + $this->motionX += $vector->x * $d; + $this->motionY += $vector->y * $d; + $this->motionZ += $vector->z * $d; + } + } + + public function setPositionAndRotation(Vector3 $pos, $yaw, $pitch){ + if($this->setPosition($pos) === true){ + $this->setRotation($yaw, $pitch); + + return true; + } + + return false; + } + + public function setRotation($yaw, $pitch){ + $this->yaw = $yaw; + $this->pitch = $pitch; + $this->scheduleUpdate(); + } + + protected function checkChunks(){ + if($this->chunk === null or ($this->chunk->getX() !== ($this->x >> 4) or $this->chunk->getZ() !== ($this->z >> 4))){ + if($this->chunk !== null){ + $this->chunk->removeEntity($this); + } + $this->chunk = $this->level->getChunk($this->x >> 4, $this->z >> 4, true); + + if(!$this->justCreated){ + $newChunk = $this->level->getChunkPlayers($this->x >> 4, $this->z >> 4); + foreach($this->hasSpawned as $player){ + if(!isset($newChunk[$player->getLoaderId()])){ + $this->despawnFrom($player); + }else{ + unset($newChunk[$player->getLoaderId()]); + } + } + foreach($newChunk as $player){ + $this->spawnTo($player); + } + } + + if($this->chunk === null){ + return; + } + + $this->chunk->addEntity($this); + } + } + + public function setLocation(Location $pos){ + if($this->closed){ + return false; + } + + $this->setPositionAndRotation($pos, $pos->yaw, $pos->pitch); + + return true; + } + + public function setPosition(Vector3 $pos){ + if($this->closed){ + return false; + } + + if($pos instanceof Position and $pos->level !== null and $pos->level !== $this->level){ + if($this->switchLevel($pos->getLevel()) === false){ + return false; + } + } + + $this->x = $pos->x; + $this->y = $pos->y; + $this->z = $pos->z; + + $radius = $this->width / 2; + $this->boundingBox->setBounds($pos->x - $radius, $pos->y, $pos->z - $radius, $pos->x + $radius, $pos->y + $this->height, $pos->z + $radius); + + $this->checkChunks(); + + return true; + } + + public function getMotion(){ + return new Vector3($this->motionX, $this->motionY, $this->motionZ); + } + + public function setMotion(Vector3 $motion){ + if(!$this->justCreated){ + $this->server->getPluginManager()->callEvent($ev = new EntityMotionEvent($this, $motion)); + if($ev->isCancelled()){ + return false; + } + } + + $this->motionX = $motion->x; + $this->motionY = $motion->y; + $this->motionZ = $motion->z; + + if(!$this->justCreated){ + $this->updateMovement(); + } + + return true; + } + + public function isOnGround(){ + return $this->onGround === true; + } + + public function kill(){ + $this->health = 0; + $this->removeAllEffects(); + $this->scheduleUpdate(); + + if($this->getLevel()->getServer()->expEnabled){ + $exp = mt_rand($this->getDropExpMin(), $this->getDropExpMax()); + if($exp > 0) $this->getLevel()->spawnXPOrb($this, $exp); + } + } + + /** + * @param Vector3|Position|Location $pos + * @param float $yaw + * @param float $pitch + * + * @return bool + */ + public function teleport(Vector3 $pos, $yaw = null, $pitch = null){ + if($pos instanceof Location){ + $yaw = $yaw === null ? $pos->yaw : $yaw; + $pitch = $pitch === null ? $pos->pitch : $pitch; + } + $from = Position::fromObject($this, $this->level); + $to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevel() : $this->level); + $this->server->getPluginManager()->callEvent($ev = new EntityTeleportEvent($this, $from, $to)); + if($ev->isCancelled()){ + return false; + } + $this->ySize = 0; + $pos = $ev->getTo(); + + $this->setMotion($this->temporalVector->setComponents(0, 0, 0)); + if($this->setPositionAndRotation($pos, $yaw === null ? $this->yaw : $yaw, $pitch === null ? $this->pitch : $pitch) !== false){ + $this->resetFallDistance(); + $this->onGround = true; + + $this->lastX = $this->x; + $this->lastY = $this->y; + $this->lastZ = $this->z; + + $this->lastYaw = $this->yaw; + $this->lastPitch = $this->pitch; + + $this->updateMovement(); + + return true; + } + + return false; + } + + public function getId(){ + return $this->id; + } + + public function respawnToAll(){ + foreach($this->hasSpawned as $key => $player){ + unset($this->hasSpawned[$key]); + $this->spawnTo($player); + } + } + + public function spawnToAll(){ + if($this->chunk === null or $this->closed){ + return; + } + foreach($this->level->getChunkPlayers($this->chunk->getX(), $this->chunk->getZ()) as $player){ + if($player->isOnline()){ + $this->spawnTo($player); + } + } + } + + public function despawnFromAll(){ + foreach($this->hasSpawned as $player){ + $this->despawnFrom($player); + } + } + + public function close(){ + if(!$this->closed){ + $this->server->getPluginManager()->callEvent(new EntityDespawnEvent($this)); + $this->closed = true; + $this->removeEffect(Effect::HEALTH_BOOST); + $this->despawnFromAll(); + if($this->linkedType != 0){ + $this->linkedEntity->setLinked(0, $this); + } + if($this->chunk !== null){ + $this->chunk->removeEntity($this); + } + if($this->level !== null){ + $this->level->removeEntity($this); + } + } + + if($this->getLevel()->getServer()->redstoneEnabled){ + /** @var \devmine\inventory\blocks\PressurePlate $block * */ + foreach($this->activatedPressurePlates as $key => $block){ + $block->checkActivation(); + } + } + + $this->activatedPressurePlates = []; + + if($this->attributeMap != null){ + $this->attributeMap = null; + } + } + + /** + * @param int $id + * @param int $type + * @param mixed $value + * + * @return bool + */ + public function setDataProperty($id, $type, $value){ + if($this->getDataProperty($id) !== $value){ + $this->dataProperties[$id] = [$type, $value]; + + $this->sendData($this->hasSpawned, [$id => $this->dataProperties[$id]]); + + return true; + } + + return false; + } + + public function linkEntity(Entity $entity){ + return $this->setLinked(1, $entity); + } + + public function sendLinkedData(){ + if($this->linkedEntity instanceof Entity){ + $this->setLinked($this->linkedType, $this->linkedEntity); + } + } + + public function setLinked($type = 0, Entity $entity){ + if($type != 0 and $entity === null){ + return false; + } + if($entity === $this){ + return false; + } + switch($type){ + case 0: + if($this->linkedType == 0){ + return true; + } + $this->linkedType = 0; + $pk = new SetEntityLinkPacket(); + $pk->from = $entity->getId(); + $pk->to = $this->getId(); + $pk->type = 3; + $this->server->broadcastPacket($this->level->getPlayers(), $pk); + if($this instanceof Player){ + $pk = new SetEntityLinkPacket(); + $pk->from = $entity->getId(); + $pk->to = 0; + $pk->type = 3; + $this->dataPacket($pk); + } + if($this->linkedEntity->getLinkedType()){ + $this->linkedEntity->setLinked(0, $this); + } + $this->linkedEntity = null; + return true; + case 1: + if(!$entity->isAlive()){ + return false; + } + $this->linkedEntity = $entity; + $this->linkedType = 1; + $entity->linkedEntity = $this; + $entity->linkedType = 1; + $pk = new SetEntityLinkPacket(); + $pk->from = $entity->getId(); + $pk->to = $this->getId(); + $pk->type = 2; + $this->server->broadcastPacket($this->level->getPlayers(), $pk); + if($this instanceof Player){ + $pk = new SetEntityLinkPacket(); + $pk->from = $entity->getId(); + $pk->to = 0; + $pk->type = 2; + $this->dataPacket($pk); + } + return true; + case 2: + if(!$entity->isAlive()){ + return false; + } + if($entity->getLinkedEntity() !== $this){ + return $entity->linkEntity($this); + } + $this->linkedEntity = $entity; + $this->linkedType = 2; + return true; + default: + return false; + } + } + + public function getLinkedEntity(){ + return $this->linkedEntity; + } + + public function getLinkedType(){ + return $this->linkedType; + } + + /** + * @param int $id + * + * @return mixed + */ + public function getDataProperty($id){ + return isset($this->dataProperties[$id]) ? $this->dataProperties[$id][1] : null; + } + + /** + * @param int $id + * + * @return int + */ + public function getDataPropertyType($id){ + return isset($this->dataProperties[$id]) ? $this->dataProperties[$id][0] : null; + } + + /** + * @param $propertyId + * @param $id + * @param bool $value + * @param int $type + */ + public function setDataFlag($propertyId, $id, $value = true, $type = self::DATA_TYPE_LONG){ + if($this->getDataFlag($propertyId, $id) !== $value){ + $flags = (int) $this->getDataProperty($propertyId); + $flags ^= 1 << $id; + $this->setDataProperty($propertyId, $type, $flags); + } + } + + /** + * @param int $propertyId + * @param int $id + * + * @return bool + */ + public function getDataFlag($propertyId, $id){ + return (((int) $this->getDataProperty($propertyId)) & (1 << $id)) > 0; + } + + public function __destruct(){ + $this->close(); + } + + public function setMetadata($metadataKey, MetadataValue $metadataValue){ + $this->server->getEntityMetadata()->setMetadata($this, $metadataKey, $metadataValue); + } + + public function getMetadata($metadataKey){ + return $this->server->getEntityMetadata()->getMetadata($this, $metadataKey); + } + + public function hasMetadata($metadataKey){ + return $this->server->getEntityMetadata()->hasMetadata($this, $metadataKey); + } + + public function removeMetadata($metadataKey, Plugin $plugin){ + $this->server->getEntityMetadata()->removeMetadata($this, $metadataKey, $plugin); + } + + public function __toString(){ + return (new \ReflectionClass($this))->getShortName() . "(" . $this->getId() . ")"; + } + +} diff --git a/src/devmine/server/calculations/entity/Explosive.php b/src/devmine/server/calculations/entity/Explosive.php new file mode 100644 index 0000000..7f03772 --- /dev/null +++ b/src/devmine/server/calculations/entity/Explosive.php @@ -0,0 +1,11 @@ +namedtag->TileID)){ + $this->blockId = $this->namedtag["TileID"]; + }elseif(isset($this->namedtag->Tile)){ + $this->blockId = $this->namedtag["Tile"]; + $this->namedtag["TileID"] = new IntTag("TileID", $this->blockId); + } + + if(isset($this->namedtag->Data)){ + $this->damage = $this->namedtag["Data"]; + } + + if($this->blockId === 0){ + $this->close(); + return; + } + + $this->setDataProperty(self::DATA_BLOCK_INFO, self::DATA_TYPE_INT, $this->getBlock() | ($this->getDamage() << 8)); + } + + public function canCollideWith(Entity $entity){ + return false; + } + + public function attack($damage, EntityDamageEvent $source){ + if($source->getCause() === EntityDamageEvent::CAUSE_VOID){ + parent::attack($damage, $source); + } + } + + public function onUpdate($currentTick){ + + if($this->closed){ + return false; + } + + $this->timings->startTiming(); + + $tickDiff = $currentTick - $this->lastUpdate; + if($tickDiff <= 0 and !$this->justCreated){ + return true; + } + + $this->lastUpdate = $currentTick; + + $height = $this->fallDistance; + + $hasUpdate = $this->entityBaseTick($tickDiff); + + if($this->isAlive()){ + $pos = (new Vector3($this->x - 0.5, $this->y, $this->z - 0.5))->round(); + + if($this->ticksLived === 1){ + $block = $this->level->getBlock($pos); + if($block->getId() !== $this->blockId){ + return true; + } + $this->level->setBlock($pos, Block::get(0), true); + } + + $this->motionY -= $this->gravity; + + $this->move($this->motionX, $this->motionY, $this->motionZ); + + $friction = 1 - $this->drag; + + $this->motionX *= $friction; + $this->motionY *= 1 - $this->drag; + $this->motionZ *= $friction; + + $pos = (new Vector3($this->x - 0.5, $this->y, $this->z - 0.5))->round(); + + if($this->onGround){ + $this->kill(); + $block = $this->level->getBlock($pos); + if($block->getId() > 0 and !$block->isSolid() and !($block instanceof Liquid)){ + $this->getLevel()->dropItem($this, ItemItem::get($this->getBlock(), $this->getDamage(), 1)); + }else{ + if($block instanceof SnowLayer){ + $oldDamage = $block->getDamage(); + $this->server->getPluginManager()->callEvent($ev = new EntityBlockChangeEvent($this, $block, Block::get($this->getBlock(), $this->getDamage() + $oldDamage))); + }else{ + $this->server->getPluginManager()->callEvent($ev = new EntityBlockChangeEvent($this, $block, Block::get($this->getBlock(), $this->getDamage()))); + } + + if(!$ev->isCancelled()){ + $this->getLevel()->setBlock($pos, $ev->getTo(), true); + if($ev->getTo() instanceof Anvil){ + $sound = new AnvilFallSound($this); + $this->getLevel()->addSound($sound); + foreach($this->level->getNearbyEntities($this->boundingBox->grow(0.1, 0.1, 0.1), $this) as $entity){ + $entity->scheduleUpdate(); + if(!$entity->isAlive()){ + continue; + } + if($entity instanceof Living){ + $damage = ($height - 1) * 2; + if($damage > 40) $damage = 40; + $ev = new EntityDamageByEntityEvent($this, $entity, EntityDamageByEntityEvent::CAUSE_FALL, $damage, 0.1); + $entity->attack($damage, $ev); + } + } + + } + } + } + $hasUpdate = true; + } + + $this->updateMovement(); + } + + return $hasUpdate or !$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + } + + public function getBlock(){ + return $this->blockId; + } + + public function getDamage(){ + return $this->damage; + } + + public function saveNBT(){ + $this->namedtag->TileID = new IntTag("TileID", $this->blockId); + $this->namedtag->Data = new ByteTag("Data", $this->damage); + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = FallingSand::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} diff --git a/src/devmine/server/calculations/entity/FishingHook.php b/src/devmine/server/calculations/entity/FishingHook.php new file mode 100644 index 0000000..6043adb --- /dev/null +++ b/src/devmine/server/calculations/entity/FishingHook.php @@ -0,0 +1,173 @@ +namedtag->Data)){ + $this->data = $this->namedtag["Data"]; + } + + // $this->setDataProperty(FallingSand::DATA_BLOCK_INFO, self::DATA_TYPE_INT, $this->getData()); + } + + public function __construct(Chunk $chunk, CompoundTag $nbt, Entity $shootingEntity = null){ + parent::__construct($chunk, $nbt, $shootingEntity); + } + + public function setData($id){ + $this->data = $id; + } + + public function getData(){ + return $this->data; + } + + public function onUpdate($currentTick){ + if($this->closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->isCollidedVertically && $this->isInsideOfWater()){ + $this->motionX = 0; + $this->motionY += 0.01; + $this->motionZ = 0; + $this->motionChanged = true; + $hasUpdate = true; + }elseif($this->isCollided && $this->keepMovement === true){ + $this->motionX = 0; + $this->motionY = 0; + $this->motionZ = 0; + $this->motionChanged = true; + $this->keepMovement = false; + $hasUpdate = true; + } + if($this->attractTimer === 0 && mt_rand(0, 100) <= 30){ // chance, that a fish bites + $this->coughtTimer = mt_rand(5, 10) * 20; // random delay to catch fish + $this->attractTimer = mt_rand(30, 100) * 20; // reset timer + $this->attractFish(); + if($this->shootingEntity instanceof Player) $this->shootingEntity->sendTip("A fish bites!"); + }elseif($this->attractTimer > 0){ + $this->attractTimer--; + } + if($this->coughtTimer > 0){ + $this->coughtTimer--; + $this->fishBites(); + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function fishBites(){ + if($this->shootingEntity instanceof Player){ + $pk = new EntityEventPacket(); + $pk->eid = $this->shootingEntity->getId();//$this or $this->shootingEntity + $pk->event = EntityEventPacket::FISH_HOOK_HOOK; + Server::broadcastPacket($this->shootingEntity->hasSpawned, $pk); + } + } + + public function attractFish(){ + if($this->shootingEntity instanceof Player){ + $pk = new EntityEventPacket(); + $pk->eid = $this->shootingEntity->getId();//$this or $this->shootingEntity + $pk->event = EntityEventPacket::FISH_HOOK_BUBBLE; + Server::broadcastPacket($this->shootingEntity->hasSpawned, $pk); + } + } + + public function reelLine(){ + $this->damageRod = false; + + if($this->shootingEntity instanceof Player && $this->coughtTimer > 0){ + $fishes = [ItemItem::RAW_FISH, ItemItem::RAW_SALMON, ItemItem::CLOWN_FISH, ItemItem::PUFFER_FISH]; + $fish = array_rand($fishes, 1); + $item = ItemItem::get($fishes[$fish]); + $this->getLevel()->getServer()->getPluginManager()->callEvent($ev = new PlayerFishEvent($this->shootingEntity, $item, $this)); + if(!$ev->isCancelled()){ + $this->shootingEntity->getInventory()->addItem($item); + $this->shootingEntity->addExperience(mt_rand(1, 6)); + $this->damageRod = true; + } + } + + if($this->shootingEntity instanceof Player){ + $this->shootingEntity->unlinkHookFromPlayer(); + } + + if(!$this->closed){ + $this->kill(); + $this->close(); + } + + return $this->damageRod; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = FishingHook::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} diff --git a/src/devmine/server/calculations/entity/FlyingAnimal.php b/src/devmine/server/calculations/entity/FlyingAnimal.php new file mode 100644 index 0000000..2f4b1cd --- /dev/null +++ b/src/devmine/server/calculations/entity/FlyingAnimal.php @@ -0,0 +1,138 @@ +closed !== false){ + return false; + } + if ($this->willMove(100)) { + if(++$this->switchDirectionTicker === $this->switchDirectionTicks){ + $this->switchDirectionTicker = 0; + if(mt_rand(0, 100) < 50){ + $this->flyDirection = null; + } + } + + $this->lastUpdate = $currentTick; + + $this->timings->startTiming(); + + if($this->isAlive()){ + + if($this->y > $this->highestY and $this->flyDirection !== null){ + $this->flyDirection->y = -0.5; + } + + $inAir = !$this->isInsideOfSolid() and !$this->isInsideOfWater(); + if(!$inAir){ + $this->flyDirection = null; + } + if($this->flyDirection instanceof Vector3){ + //var_dump($this->flyDirection); + $this->setMotion($this->flyDirection->multiply($this->flySpeed)); + }else{ + $this->flyDirection = $this->generateRandomDirection(); + $this->flySpeed = mt_rand(50, 100) / 500; + $this->setMotion($this->flyDirection); + } + + //$expectedPos = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ); + + //$motion = $this->flyDirection->multiply($this->flySpeed); + $this->move($this->motionX, $this->motionY, $this->motionZ); + $this->updateMovement(); + //$this->getLevel()->addEntityMotion($this->chunk->getX(), $this->chunk->getZ(), $this->getId(), $motion->x, $motion->y, $motion->z); + + //echo "EID = {$this->getId()}, motionX = $this->motionX, motionY = $this->motionY, motionZ = $this->motionZ\n"; + /* + + if($expectedPos->distanceSquared($this) > 0){ + $this->flyDirection = $this->generateRandomDirection(); + $this->flySpeed = mt_rand(50, 100) / 500; + } + + $friction = 1 - $this->drag; + + $this->motionX *= $friction; + $this->motionY *= 1 - $this->drag; + $this->motionZ *= $friction; +*/ + $f = sqrt(($this->motionX ** 2) + ($this->motionZ ** 2)); + $this->yaw = (-atan2($this->motionX, $this->motionZ) * 180 / M_PI); + $this->pitch = (-atan2($f, $this->motionY) * 180 / M_PI); + + if($this->onGround and $this->flyDirection instanceof Vector3){ + $this->flyDirection->y *= -1; + } + + + } + } + parent::onUpdate($currentTick); + //parent::entityBaseTick(); + $this->timings->stopTiming(); + + return !$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + } + + private function generateRandomDirection(){ + return new Vector3(mt_rand(-1000, 1000) / 1000, mt_rand(-500, 500) / 1000, mt_rand(-1000, 1000) / 1000); + } + + public function initEntity(){ + parent::initEntity(); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BABY, false); + } + + public function isBaby(){ + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BABY); + } + + public function attack($damage, EntityDamageEvent $source){ + if($source->isCancelled()){ + return; + } + if ($source->getCause() == EntityDamageEvent::CAUSE_FALL) { + $source->setCancelled(); + return; + } + parent::attack($damage, $source); + } + +} diff --git a/src/devmine/server/calculations/entity/Ghast.php b/src/devmine/server/calculations/entity/Ghast.php new file mode 100644 index 0000000..673de12 --- /dev/null +++ b/src/devmine/server/calculations/entity/Ghast.php @@ -0,0 +1,43 @@ +setMaxHealth(10); + parent::initEntity(); + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Ghast::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Hanging.php b/src/devmine/server/calculations/entity/Hanging.php new file mode 100644 index 0000000..4dcf25e --- /dev/null +++ b/src/devmine/server/calculations/entity/Hanging.php @@ -0,0 +1,10 @@ +skin; + } + + public function getSkinId(){ + return $this->skinId; + } + + /** + * @return UUID|null + */ + public function getUniqueId(){ + return $this->uuid; + } + + /** + * @return string + */ + public function getRawUniqueId(){ + return $this->rawUUID; + } + + /** + * @param string $str + * @param string $skinId + */ + public function setSkin($str, $skinId){ + $this->skin = $str; + $this->skinId = $skinId; + } + + public function getFood() : float{ + return $this->attributeMap->getAttribute(Attribute::HUNGER)->getValue(); + } + + /** + * WARNING: This method does not check if full and may throw an exception if out of bounds. + * Use {@link Human::addFood()} for this purpose + * + * @param float $new + * + * @throws \InvalidArgumentException + */ + public function setFood(float $new){ + $attr = $this->attributeMap->getAttribute(Attribute::HUNGER); + $old = $attr->getValue(); + $attr->setValue($new); + // ranges: 18-20 (regen), 7-17 (none), 1-6 (no sprint), 0 (health depletion) + foreach([17, 6, 0] as $bound){ + if(($old > $bound) !== ($new > $bound)){ + $reset = true; + } + } + if(isset($reset)){ + $this->foodTickTimer = 0; + } + + } + + public function getMaxFood() : float{ + return $this->attributeMap->getAttribute(Attribute::HUNGER)->getMaxValue(); + } + + public function addFood(float $amount){ + $attr = $this->attributeMap->getAttribute(Attribute::HUNGER); + $amount += $attr->getValue(); + $amount = max(min($amount, $attr->getMaxValue()), $attr->getMinValue()); + $this->setFood($amount); + } + + public function getSaturation() : float{ + return $this->attributeMap->getAttribute(Attribute::SATURATION)->getValue(); + } + + /** + * WARNING: This method does not check if saturated and may throw an exception if out of bounds. + * Use {@link Human::addSaturation()} for this purpose + * + * @param float $saturation + * + * @throws \InvalidArgumentException + */ + public function setSaturation(float $saturation){ + $this->attributeMap->getAttribute(Attribute::SATURATION)->setValue($saturation); + } + + public function addSaturation(float $amount){ + $attr = $this->attributeMap->getAttribute(Attribute::SATURATION); + $attr->setValue($attr->getValue() + $amount, true); + } + + public function getExhaustion() : float{ + return $this->attributeMap->getAttribute(Attribute::EXHAUSTION)->getValue(); + } + + /** + * WARNING: This method does not check if exhausted and does not consume saturation/food. + * Use {@link Human::exhaust()} for this purpose. + * + * @param float $exhaustion + */ + public function setExhaustion(float $exhaustion){ + $this->attributeMap->getAttribute(Attribute::EXHAUSTION)->setValue($exhaustion); + } + + /** + * Increases a human's exhaustion level. + * + * @param float $amount + * @param int $cause + * + * @return float the amount of exhaustion level increased + */ + public function exhaust(float $amount, int $cause = PlayerExhaustEvent::CAUSE_CUSTOM) : float{ + $this->server->getPluginManager()->callEvent($ev = new PlayerExhaustEvent($this, $amount, $cause)); + if($ev->isCancelled()){ + return 0.0; + } + + $exhaustion = $this->getExhaustion(); + $exhaustion += $ev->getAmount(); + + while($exhaustion >= 4.0){ + $exhaustion -= 4.0; + + $saturation = $this->getSaturation(); + if($saturation > 0){ + $saturation = max(0, $saturation - 1.0); + $this->setSaturation($saturation); + }else{ + $food = $this->getFood(); + if($food > 0){ + $food--; + $this->setFood($food); + } + } + } + $this->setExhaustion($exhaustion); + + return $ev->getAmount(); + } + + public function getXpLevel() : int{ + return (int) $this->attributeMap->getAttribute(Attribute::EXPERIENCE_LEVEL)->getValue(); + } + + public function setXpLevel(int $level) : bool{ + $this->server->getPluginManager()->callEvent($ev = new PlayerExperienceChangeEvent($this, $level, $this->getXpProgress())); + if(!$ev->isCancelled()){ + $this->attributeMap->getAttribute(Attribute::EXPERIENCE_LEVEL)->setValue($ev->getExpLevel()); + return true; + } + return false; + } + + public function addXpLevel(int $level) : bool{ + return $this->setXpLevel($this->getXpLevel() + $level); + } + + public function takeXpLevel(int $level) : bool{ + return $this->setXpLevel($this->getXpLevel() - $level); + } + + public function getXpProgress() : float{ + return $this->attributeMap->getAttribute(Attribute::EXPERIENCE)->getValue(); + } + + public function setXpProgress(float $progress) : bool{ + $this->attributeMap->getAttribute(Attribute::EXPERIENCE)->setValue($progress); + return true; + } + + public function getTotalXp() : int{ + return $this->totalXp; + } + + /** + * Changes the total exp of a player + * + * @param int $xp + * @param bool $syncLevel This will reset the level to be in sync with the total. Usually you don't want to do this, + * because it'll mess up use of xp in anvils and enchanting tables. + * + * @return bool + */ + public function setTotalXp(int $xp, bool $syncLevel = false) : bool{ + $xp &= 0x7fffffff; + if($xp === $this->totalXp){ + return false; + } + if(!$syncLevel){ + $level = $this->getXpLevel(); + $diff = $xp - $this->totalXp + $this->getFilledXp(); + if($diff > 0){ //adding xp + while($diff > ($v = self::getLevelXpRequirement($level))){ + $diff -= $v; + if(++$level >= 21863){ + $diff = $v; //fill exp bar + break; + } + } + }else{ //taking xp + while($diff < ($v = self::getLevelXpRequirement($level - 1))){ + $diff += $v; + if(--$level <= 0){ + $diff = 0; + break; + } + } + } + $progress = ($diff / $v); + }else{ + $values = self::getLevelFromXp($xp); + $level = $values[0]; + $progress = $values[1]; + } + + $this->server->getPluginManager()->callEvent($ev = new PlayerExperienceChangeEvent($this, $level, $progress)); + if(!$ev->isCancelled()){ + $this->totalXp = $xp; + $this->setXpLevel($ev->getExpLevel()); + $this->setXpProgress($ev->getProgress()); + return true; + } + return false; + } + + public function addXp(int $xp, bool $syncLevel = false) : bool{ + return $this->setTotalXp($this->totalXp + $xp, $syncLevel); + } + + public function takeXp(int $xp, bool $syncLevel = false) : bool{ + return $this->setTotalXp($this->totalXp - $xp, $syncLevel); + } + + public function getRemainderXp() : int{ + return self::getLevelXpRequirement($this->getXpLevel()) - $this->getFilledXp(); + } + + public function getFilledXp() : int{ + return self::getLevelXpRequirement($this->getXpLevel()) * $this->getXpProgress(); + } + + public function recalculateXpProgress() : float{ + $this->setXpProgress($this->getRemainderXp() / self::getLevelXpRequirement($this->getXpLevel())); + } + + public function getXpSeed() : int{ + //TODO: use this for randomizing enchantments in enchanting tables + return $this->xpSeed; + } + + public function resetXpCooldown(){ + $this->xpCooldown = microtime(true); + } + + public function canPickupXp() : bool{ + return microtime(true) - $this->xpCooldown > 0.5; + } + + /** + * Returns the total amount of exp required to reach the specified level. + * + * @param int $level + * + * @return int + */ + public static function getTotalXpRequirement(int $level) : int{ + if($level <= 16){ + return ($level ** 2) + (6 * $level); + }elseif($level <= 31){ + return (2.5 * ($level ** 2)) - (40.5 * $level) + 360; + }elseif($level <= 21863){ + return (4.5 * ($level ** 2)) - (162.5 * $level) + 2220; + } + return PHP_INT_MAX; //prevent float returns for invalid levels on 32-bit systems + } + + /** + * Returns the amount of exp required to complete the specified level. + * + * @param int $level + * + * @return int + */ + public static function getLevelXpRequirement(int $level) : int{ + if($level <= 16){ + return (2 * $level) + 7; + }elseif($level <= 31){ + return (5 * $level) - 38; + }elseif($level <= 21863){ + return (9 * $level) - 158; + } + return PHP_INT_MAX; + } + + /** + * Converts a quantity of exp into a level and a progress percentage + * + * @param int $xp + * + * @return int[] + */ + public static function getLevelFromXp(int $xp) : array{ + $xp &= 0x7fffffff; + + /** These values are correct up to and including level 16 */ + $a = 1; + $b = 6; + $c = -$xp; + if($xp > self::getTotalXpRequirement(16)){ + /** Modify the coefficients to fit the relevant equation */ + if($xp <= self::getTotalXpRequirement(31)){ + /** Levels 16-31 */ + $a = 2.5; + $b = -40.5; + $c += 360; + }else{ + /** Level 32+ */ + $a = 4.5; + $b = -162.5; + $c += 2220; + } + } + + $answer = max(Math::solveQuadratic($a, $b, $c)); //Use largest result value + $level = floor($answer); + $progress = $answer - $level; + return [$level, $progress]; + } + + public function getInventory(){ + return $this->inventory; + } + + public function getFloatingInventory(){ + return $this->floatingInventory; + } + + public function getTransactionQueue(){ + //Is creating the transaction queue ondemand a good idea? I think only if it's destroyed afterwards. hmm... + if($this->transactionQueue === null){ + //Potential for crashes here if a plugin attempts to use this, say for an NPC plugin or something... + $this->transactionQueue = new SimpleTransactionQueue($this); + } + return $this->transactionQueue; + } + + protected function initEntity(){ + $this->setDataFlag(self::DATA_PLAYER_FLAGS, self::DATA_PLAYER_FLAG_SLEEP, false, self::DATA_TYPE_BYTE); + $this->setDataProperty(self::DATA_PLAYER_BED_POSITION, self::DATA_TYPE_POS, [0, 0, 0], false); + + $inventoryContents = ($this->namedtag->Inventory ?? null); + $this->inventory = new PlayerInventory($this, $inventoryContents); + + //Virtual inventory for desktop GUI crafting and anti-cheat transaction processing + $this->floatingInventory = new FloatingInventory($this); + + if($this instanceof Player){ + $this->addWindow($this->inventory, 0); + }else{ + if(isset($this->namedtag->NameTag)){ + $this->setNameTag($this->namedtag["NameTag"]); + } + + if(isset($this->namedtag->Skin) and $this->namedtag->Skin instanceof CompoundTag){ + $this->setSkin($this->namedtag->Skin["Data"], $this->namedtag->Skin["Name"]); + } + + $this->uuid = UUID::fromData($this->getId(), $this->getSkinData(), $this->getNameTag()); + } + + + parent::initEntity(); + + if(!isset($this->namedtag->foodLevel) or !($this->namedtag->foodLevel instanceof IntTag)){ + $this->namedtag->foodLevel = new IntTag("foodLevel", $this->getFood()); + }else{ + $this->setFood($this->namedtag["foodLevel"]); + } + + if(!isset($this->namedtag->foodExhaustionLevel) or !($this->namedtag->foodExhaustionLevel instanceof IntTag)){ + $this->namedtag->foodExhaustionLevel = new FloatTag("foodExhaustionLevel", $this->getExhaustion()); + }else{ + $this->setExhaustion($this->namedtag["foodExhaustionLevel"]); + } + + if(!isset($this->namedtag->foodSaturationLevel) or !($this->namedtag->foodSaturationLevel instanceof IntTag)){ + $this->namedtag->foodSaturationLevel = new FloatTag("foodSaturationLevel", $this->getSaturation()); + }else{ + $this->setSaturation($this->namedtag["foodSaturationLevel"]); + } + + if(!isset($this->namedtag->foodTickTimer) or !($this->namedtag->foodTickTimer instanceof IntTag)){ + $this->namedtag->foodTickTimer = new IntTag("foodTickTimer", $this->foodTickTimer); + }else{ + $this->foodTickTimer = $this->namedtag["foodTickTimer"]; + } + + if(!isset($this->namedtag->XpLevel) or !($this->namedtag->XpLevel instanceof IntTag)){ + $this->namedtag->XpLevel = new IntTag("XpLevel", 0); + } + $this->setXpLevel($this->namedtag["XpLevel"]); + + if(!isset($this->namedtag->XpP) or !($this->namedtag->XpP instanceof FloatTag)){ + $this->namedtag->XpP = new FloatTag("XpP", 0); + } + $this->setXpProgress($this->namedtag["XpP"]); + + if(!isset($this->namedtag->XpTotal) or !($this->namedtag->XpTotal instanceof IntTag)){ + $this->namedtag->XpTotal = new IntTag("XpTotal", 0); + } + $this->totalXp = $this->namedtag["XpTotal"]; + + if(!isset($this->namedtag->XpSeed) or !($this->namedtag->XpSeed instanceof IntTag)){ + $this->namedtag->XpSeed = new IntTag("XpSeed", mt_rand(PHP_INT_MIN, PHP_INT_MAX)); + } + $this->xpSeed = $this->namedtag["XpSeed"]; + } + + public function getAbsorption() : int{ + return $this->attributeMap->getAttribute(Attribute::ABSORPTION)->getValue(); + } + + public function setAbsorption(int $absorption){ + $this->attributeMap->getAttribute(Attribute::ABSORPTION)->setValue($absorption); + } + + protected function addAttributes(){ + parent::addAttributes(); + + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::SATURATION)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXHAUSTION)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::HUNGER)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXPERIENCE_LEVEL)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXPERIENCE)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::HEALTH)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::MOVEMENT_SPEED)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::ABSORPTION)); + } + + public function entityBaseTick($tickDiff = 1, $EnchantL = 0){ + if($this->getInventory() instanceof PlayerInventory){ + $EnchantL = $this->getInventory()->getHelmet()->getEnchantmentLevel(Enchantment::TYPE_WATER_BREATHING); + } + $hasUpdate = parent::entityBaseTick($tickDiff, $EnchantL); + + if($this->server->foodEnabled){ + $food = $this->getFood(); + $health = $this->getHealth(); + if($food >= 18){ + $this->foodTickTimer++; + if($this->foodTickTimer >= 80 and $health < $this->getMaxHealth()){ + $this->heal(1, new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_SATURATION)); + $this->exhaust(3.0, PlayerExhaustEvent::CAUSE_HEALTH_REGEN); + $this->foodTickTimer = 0; + + } + }elseif($food === 0){ + $this->foodTickTimer++; + if($this->foodTickTimer >= 80){ + $diff = $this->server->getDifficulty(); + $can = false; + if($diff === 1){ + $can = $health > 10; + }elseif($diff === 2){ + $can = $health > 1; + }elseif($diff === 3){ + $can = true; + } + if($can){ + $this->attack(1, new EntityDamageEvent($this, EntityDamageEvent::CAUSE_STARVATION, 1)); + } + } + } + if($food <= 6){ + if($this->isSprinting()){ + $this->setSprinting(false); + } + } + } + + return $hasUpdate; + } + + public function getName(){ + return $this->getNameTag(); + } + + public function getDrops(){ + $drops = []; + if($this->inventory !== null){ + foreach($this->inventory->getContents() as $item){ + $drops[] = $item; + } + } + + return $drops; + } + + public function saveNBT(){ + parent::saveNBT(); + $this->namedtag->Inventory = new ListTag("Inventory", []); + $this->namedtag->Inventory->setTagType(NBT::TAG_Compound); + if($this->inventory !== null){ + + //Hotbar + for($slot = 0; $slot < $this->inventory->getHotbarSize(); ++$slot){ + $inventorySlotIndex = $this->inventory->getHotbarSlotIndex($slot); + $item = $this->inventory->getItem($inventorySlotIndex); + $tag = NBT::putItemHelper($item, $slot); + $tag->TrueSlot = new ByteTag("TrueSlot", $inventorySlotIndex); + $this->namedtag->Inventory[$slot] = $tag; + } + + //Normal inventory + $slotCount = $this->inventory->getSize() + $this->inventory->getHotbarSize(); + for($slot = $this->inventory->getHotbarSize(); $slot < $slotCount; ++$slot){ + $item = $this->inventory->getItem($slot - $this->inventory->getHotbarSize()); + //As NBT, real inventory slots are slots 9-44, NOT 0-35 + $this->namedtag->Inventory[$slot] = NBT::putItemHelper($item, $slot); + } + + //Armour + for($slot = 100; $slot < 104; ++$slot){ + $item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100); + if($item instanceof ItemItem and $item->getId() !== ItemItem::AIR){ + $this->namedtag->Inventory[$slot] = NBT::putItemHelper($item, $slot); + } + } + } + + if(strlen($this->getSkinData()) > 0){ + $this->namedtag->Skin = new CompoundTag("Skin", [ + "Data" => new StringTag("Data", $this->getSkinData()), + "Name" => new StringTag("Name", $this->getSkinId()) + ]); + } + + //Xp + $this->namedtag->XpLevel = new IntTag("XpLevel", $this->getXpLevel()); + $this->namedtag->XpTotal = new IntTag("XpTotal", $this->getTotalXp()); + $this->namedtag->XpP = new FloatTag("XpP", $this->getXpProgress()); + $this->namedtag->XpSeed = new IntTag("XpSeed", $this->getXpSeed()); + + //Food + $this->namedtag->foodLevel = new IntTag("foodLevel", $this->getFood()); + $this->namedtag->foodExhaustionLevel = new FloatTag("foodExhaustionLevel", $this->getExhaustion()); + $this->namedtag->foodSaturationLevel = new FloatTag("foodSaturationLevel", $this->getSaturation()); + $this->namedtag->foodTickTimer = new IntTag("foodTickTimer", $this->foodTickTimer); + } + + public function spawnTo(Player $player){ + if(strlen($this->skin) < 64 * 32 * 4){ + $e = new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set"); + $this->server->getLogger()->logException($e); + $this->close(); + }elseif($player !== $this and !isset($this->hasSpawned[$player->getLoaderId()])){ + $this->hasSpawned[$player->getLoaderId()] = $player; + + if(!($this instanceof Player)){ + $this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getName(), $this->skinId, $this->skin, [$player]); + } + + $pk = new AddPlayerPacket(); + $pk->uuid = $this->getUniqueId(); + $pk->username = $this->getName(); + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->item = $this->getInventory()->getItemInHand(); + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + $this->sendLinkedData(); + + $this->inventory->sendArmorContents($player); + + if(!($this instanceof Player)){ + $this->server->removePlayerListData($this->getUniqueId(), [$player]); + } + } + } + + public function despawnFrom(Player $player){ + if(isset($this->hasSpawned[$player->getLoaderId()])){ + + $pk = new RemoveEntityPacket(); + $pk->eid = $this->getId(); + $player->dataPacket($pk); + unset($this->hasSpawned[$player->getLoaderId()]); + } + } + + public function close(){ + if(!$this->closed){ + if($this->getFloatingInventory() instanceof FloatingInventory){ + foreach($this->getFloatingInventory()->getContents() as $craftingItem){ + $this->level->dropItem($this, $craftingItem); + } + }else{ + $this->server->getLogger()->debug("Attempted to drop a null crafting inventory\n"); + } + if(!($this instanceof Player) or $this->loggedIn){ + foreach($this->inventory->getViewers() as $viewer){ + $viewer->removeWindow($this->inventory); + } + } + parent::close(); + } + } +} diff --git a/src/devmine/server/calculations/entity/Husk.php b/src/devmine/server/calculations/entity/Husk.php new file mode 100644 index 0000000..eb1ae9d --- /dev/null +++ b/src/devmine/server/calculations/entity/Husk.php @@ -0,0 +1,52 @@ +eid = $this->getId(); + $pk->type = Husk::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + Entity::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/InstantEffect.php b/src/devmine/server/calculations/entity/InstantEffect.php new file mode 100644 index 0000000..d71a786 --- /dev/null +++ b/src/devmine/server/calculations/entity/InstantEffect.php @@ -0,0 +1,9 @@ +setMaxHealth(100); + parent::initEntity(); + } + + public function getName() { + return "Iron Golem"; + } + + public function spawnTo(Player $player) { + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = self::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + //Not affected by Looting. + $drops = array(ItemItem::get(ItemItem::IRON_INGOT, 0, mt_rand(3, 5))); + $drops[] = ItemItem::get(ItemItem::POPPY, 0, mt_rand(0, 2)); + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Item.php b/src/devmine/server/calculations/entity/Item.php new file mode 100644 index 0000000..805a70a --- /dev/null +++ b/src/devmine/server/calculations/entity/Item.php @@ -0,0 +1,233 @@ +setMaxHealth(5); + $this->setHealth($this->namedtag["Health"]); + if(isset($this->namedtag->Age)){ + $this->age = $this->namedtag["Age"]; + } + if(isset($this->namedtag->PickupDelay)){ + $this->pickupDelay = $this->namedtag["PickupDelay"]; + } + if(isset($this->namedtag->Owner)){ + $this->owner = $this->namedtag["Owner"]; + } + if(isset($this->namedtag->Thrower)){ + $this->thrower = $this->namedtag["Thrower"]; + } + if(!isset($this->namedtag->Item)){ + $this->close(); + return; + } + $this->item = NBT::getItemHelper($this->namedtag->Item); + if($this->item->getId() <= 0){ + $this->close(); + return; + } + + + $this->server->getPluginManager()->callEvent(new ItemSpawnEvent($this)); + } + + public function attack($damage, EntityDamageEvent $source){ + if( + $source->getCause() === EntityDamageEvent::CAUSE_VOID or + $source->getCause() === EntityDamageEvent::CAUSE_FIRE_TICK or + $source->getCause() === EntityDamageEvent::CAUSE_ENTITY_EXPLOSION or + $source->getCause() === EntityDamageEvent::CAUSE_BLOCK_EXPLOSION + ){ + parent::attack($damage, $source); + } + } + + public function onUpdate($currentTick){ + if($this->closed){ + return false; + } + + $this->age++; + + $tickDiff = $currentTick - $this->lastUpdate; + if($tickDiff <= 0 and !$this->justCreated){ + return true; + } + + $this->lastUpdate = $currentTick; + + $this->timings->startTiming(); + + $hasUpdate = $this->entityBaseTick($tickDiff); + + if($this->isAlive()){ + + if($this->pickupDelay > 0 and $this->pickupDelay < 32767){ //Infinite delay + $this->pickupDelay -= $tickDiff; + if($this->pickupDelay < 0){ + $this->pickupDelay = 0; + } + } + + $this->motionY -= $this->gravity; + + if($this->checkObstruction($this->x, $this->y, $this->z)){ + $hasUpdate = true; + } + + $this->move($this->motionX, $this->motionY, $this->motionZ); + + $friction = 1 - $this->drag; + + if($this->onGround and (abs($this->motionX) > 0.00001 or abs($this->motionZ) > 0.00001)){ + $friction = $this->getLevel()->getBlock($this->temporalVector->setComponents((int) floor($this->x), (int) floor($this->y - 1), (int) floor($this->z) - 1))->getFrictionFactor() * $friction; + } + + $this->motionX *= $friction; + $this->motionY *= 1 - $this->drag; + $this->motionZ *= $friction; + + if($this->onGround){ + $this->motionY *= -0.5; + } + + if($currentTick % 5 ==0) + $this->updateMovement(); + + if($this->age > 2000){ + $this->server->getPluginManager()->callEvent($ev = new ItemDespawnEvent($this)); + if($ev->isCancelled()){ + $this->age = 0; + }else{ + $this->kill(); + $hasUpdate = true; + } + } + + } + + $this->timings->stopTiming(); + + return $hasUpdate or !$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + } + + public function saveNBT(){ + parent::saveNBT(); + $this->namedtag->Item = NBT::putItemHelper($this->item); + $this->namedtag->Health = new ShortTag("Health", $this->getHealth()); + $this->namedtag->Age = new ShortTag("Age", $this->age); + $this->namedtag->PickupDelay = new ShortTag("PickupDelay", $this->pickupDelay); + if($this->owner !== null){ + $this->namedtag->Owner = new StringTag("Owner", $this->owner); + } + if($this->thrower !== null){ + $this->namedtag->Thrower = new StringTag("Thrower", $this->thrower); + } + } + + /** + * @return ItemItem + */ + public function getItem(){ + return $this->item; + } + + public function canCollideWith(Entity $entity){ + return false; + } + + /** + * @return int + */ + public function getPickupDelay(){ + return $this->pickupDelay; + } + + /** + * @param int $delay + */ + public function setPickupDelay($delay){ + $this->pickupDelay = $delay; + } + + /** + * @return string + */ + public function getOwner(){ + return $this->owner; + } + + /** + * @param string $owner + */ + public function setOwner($owner){ + $this->owner = $owner; + } + + /** + * @return string + */ + public function getThrower(){ + return $this->thrower; + } + + /** + * @param string $thrower + */ + public function setThrower($thrower){ + $this->thrower = $thrower; + } + + public function spawnTo(Player $player){ + $pk = new AddItemEntityPacket(); + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->item = $this->getItem(); + $player->dataPacket($pk); + + $this->sendData($player); + + parent::spawnTo($player); + } +} diff --git a/src/devmine/server/calculations/entity/LavaSlime.php b/src/devmine/server/calculations/entity/LavaSlime.php new file mode 100644 index 0000000..900fe03 --- /dev/null +++ b/src/devmine/server/calculations/entity/LavaSlime.php @@ -0,0 +1,38 @@ +eid = $this->getId(); + $pk->type = LavaSlime::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Lightning.php b/src/devmine/server/calculations/entity/Lightning.php new file mode 100644 index 0000000..cee604a --- /dev/null +++ b/src/devmine/server/calculations/entity/Lightning.php @@ -0,0 +1,115 @@ +setMaxHealth(2); + $this->setHealth(2); + } + + public function onUpdate($tick){ + parent::onUpdate($tick); + if($this->age > 20){ + $this->kill(); + $this->close(); + } + return true; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = self::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + $pk = new ExplodePacket(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->radius = 10; + $pk->records = []; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function spawnToAll(){ + parent::spawnToAll(); + + if($this->getLevel()->getServer()->lightningFire){ + $fire = ItemItem::get(ItemItem::FIRE)->getBlock(); + $oldBlock = $this->getLevel()->getBlock($this); + if($oldBlock instanceof Liquid){ + + }elseif($oldBlock->isSolid()){ + $v3 = new Vector3($this->x, $this->y + 1, $this->z); + }else{ + $v3 = new Vector3($this->x, $this->y, $this->z); + } + if(isset($v3)) $this->getLevel()->setBlock($v3, $fire); + + foreach($this->level->getNearbyEntities($this->boundingBox->grow(4, 3, 4), $this) as $entity){ + if($entity instanceof Player){ + $damage = mt_rand(8, 20); + $ev = new EntityDamageByEntityEvent($this, $entity, EntityDamageByEntityEvent::CAUSE_LIGHTNING, $damage); + if($entity->attack($ev->getFinalDamage(), $ev) === true){ + $ev->useArmors(); + } + $entity->setOnFire(mt_rand(3, 8)); + } + + if($entity instanceof Creeper){ + $entity->setPowered(true, $this); + } + } + } + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Living.php b/src/devmine/server/calculations/entity/Living.php new file mode 100644 index 0000000..8219db9 --- /dev/null +++ b/src/devmine/server/calculations/entity/Living.php @@ -0,0 +1,283 @@ +namedtag->HealF)){ + $this->namedtag->Health = new ShortTag("Health", (int) $this->namedtag["HealF"]); + unset($this->namedtag->HealF); + } + + if(!isset($this->namedtag->Health) or !($this->namedtag->Health instanceof ShortTag)){ + $this->namedtag->Health = new ShortTag("Health", $this->getMaxHealth()); + } + + if($this->namedtag["Health"] <= 0) + $this->setHealth(20); + else $this->setHealth($this->namedtag["Health"]); + } + + public function setHealth($amount){ + $wasAlive = $this->isAlive(); + parent::setHealth($amount); + if($this->isAlive() and !$wasAlive){ + $pk = new EntityEventPacket(); + $pk->eid = $this->getId(); + $pk->event = EntityEventPacket::RESPAWN; + Server::broadcastPacket($this->hasSpawned, $pk); + } + } + + public function saveNBT(){ + parent::saveNBT(); + $this->namedtag->Health = new ShortTag("Health", $this->getHealth()); + } + + public abstract function getName(); + + public function hasLineOfSight(Entity $entity){ + //TODO: head height + return true; + //return $this->getLevel()->rayTraceBlocks(Vector3::createVector($this->x, $this->y + $this->height, $this->z), Vector3::createVector($entity->x, $entity->y + $entity->height, $entity->z)) === null; + } + + public function heal($amount, EntityRegainHealthEvent $source){ + parent::heal($amount, $source); + if($source->isCancelled()){ + return; + } + + $this->attackTime = 0; + } + + public function attack($damage, EntityDamageEvent $source){ + if($this->attackTime > 0 or $this->noDamageTicks > 0){ + $lastCause = $this->getLastDamageCause(); + if($lastCause !== null and $lastCause->getDamage() >= $damage){ + $source->setCancelled(); + } + } + + parent::attack($damage, $source); + + if($source->isCancelled()){ + return; + } + + if($source instanceof EntityDamageByEntityEvent){ + $e = $source->getDamager(); + if($source instanceof EntityDamageByChildEntityEvent){ + $e = $source->getChild(); + } + + if($e->isOnFire() > 0 and !($e instanceof Player)){ + $this->setOnFire(2 * $this->server->getDifficulty()); + } + + $deltaX = $this->x - $e->x; + $deltaZ = $this->z - $e->z; + $this->knockBack($e, $damage, $deltaX, $deltaZ, $source->getKnockBack()); + if($e instanceof Husk){ + $this->addEffect(Effect::getEffect(Effect::HUNGER)->setDuration(7 * 20 * $this->server->getDifficulty())); + } + } + + $pk = new EntityEventPacket(); + $pk->eid = $this->getId(); + $pk->event = $this->getHealth() <= 0 ? EntityEventPacket::DEATH_ANIMATION : EntityEventPacket::HURT_ANIMATION; //Ouch! + Server::broadcastPacket($this->hasSpawned, $pk); + + $this->attackTime = 10; //0.5 seconds cooldown + } + + public function knockBack(Entity $attacker, $damage, $x, $z, $base = 0.4){ + $f = sqrt($x * $x + $z * $z); + if($f <= 0){ + return; + } + + $f = 1 / $f; + + $motion = new Vector3($this->motionX, $this->motionY, $this->motionZ); + + $motion->x /= 2; + $motion->y /= 2; + $motion->z /= 2; + $motion->x += $x * $f * $base; + $motion->y += $base; + $motion->z += $z * $f * $base; + + if($motion->y > $base){ + $motion->y = $base; + } + + $this->setMotion($motion); + } + + public function kill(){ + if(!$this->isAlive()){ + return; + } + parent::kill(); + $this->server->getPluginManager()->callEvent($ev = new EntityDeathEvent($this, $this->getDrops())); + foreach($ev->getDrops() as $item){ + $this->getLevel()->dropItem($this, $item); + } + } + + public function entityBaseTick($tickDiff = 1, $EnchantL = 0){ + Timings::$timerLivingEntityBaseTick->startTiming(); + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BREATHING, !$this->isInsideOfWater()); + + $hasUpdate = parent::entityBaseTick($tickDiff); + + if($this->isAlive()){ + if($this->isInsideOfSolid()){ + $hasUpdate = true; + $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_SUFFOCATION, 1); + $this->attack($ev->getFinalDamage(), $ev); + } + + if(!$this->hasEffect(Effect::WATER_BREATHING) and $this->isInsideOfWater()){ + if($this instanceof WaterAnimal){ + $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 400); + }else{ + $hasUpdate = true; + $airTicks = $this->getDataProperty(self::DATA_AIR) - $tickDiff * (4 - $EnchantL); + if($airTicks <= -80){ + $airTicks = 0; + + $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_DROWNING, 2); + $this->attack($ev->getFinalDamage(), $ev); + } + $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, $airTicks); + } + }else{ + if($this instanceof WaterAnimal){ + $hasUpdate = true; + $airTicks = $this->getDataProperty(self::DATA_AIR) - $tickDiff * (4 - $EnchantL); + if($airTicks <= -80){ + $airTicks = 0; + + $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_SUFFOCATION, 2); + $this->attack($ev->getFinalDamage(), $ev); + } + $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, $airTicks); + }else{ + $this->setDataProperty(self::DATA_AIR, self::DATA_TYPE_SHORT, 400); + } + } + } + + if($this->attackTime > 0){ + $this->attackTime -= $tickDiff; + } + + Timings::$timerLivingEntityBaseTick->stopTiming(); + + return $hasUpdate; + } + + /** + * @return ItemItem[] + */ + public function getDrops(){ + return []; + } + + /** + * @param int $maxDistance + * @param int $maxLength + * @param array $transparent + * + * @return Block[] + */ + public function getLineOfSight($maxDistance, $maxLength = 0, array $transparent = []){ + if($maxDistance > 120){ + $maxDistance = 120; + } + + if(count($transparent) === 0){ + $transparent = null; + } + + $blocks = []; + $nextIndex = 0; + + $itr = new BlockIterator($this->level, $this->getPosition(), $this->getDirectionVector(), $this->getEyeHeight(), $maxDistance); + + while($itr->valid()){ + $itr->next(); + $block = $itr->current(); + $blocks[$nextIndex++] = $block; + + if($maxLength !== 0 and count($blocks) > $maxLength){ + array_shift($blocks); + --$nextIndex; + } + + $id = $block->getId(); + + if($transparent === null){ + if($id !== 0){ + break; + } + }else{ + if(!isset($transparent[$id])){ + break; + } + } + } + + return $blocks; + } + + /** + * @param int $maxDistance + * @param array $transparent + * + * @return Block + */ + public function getTargetBlock($maxDistance, array $transparent = []){ + try{ + $block = $this->getLineOfSight($maxDistance, 1, $transparent)[0]; + if($block instanceof Block){ + return $block; + } + }catch (\ArrayOutOfBoundsException $e){ + + } + + return null; + } +} diff --git a/src/devmine/server/calculations/entity/Minecart.php b/src/devmine/server/calculations/entity/Minecart.php new file mode 100644 index 0000000..9a0f7af --- /dev/null +++ b/src/devmine/server/calculations/entity/Minecart.php @@ -0,0 +1,496 @@ +setMaxHealth(1); + $this->setHealth($this->getMaxHealth()); + $this->moveVector[Entity::NORTH] = new Vector3(-1, 0, 0); + $this->moveVector[Entity::SOUTH] = new Vector3(1, 0, 0); + $this->moveVector[Entity::EAST] = new Vector3(0, 0, -1); + $this->moveVector[Entity::WEST] = new Vector3(0, 0, 1); + parent::initEntity(); + } + + public function getName() : string{ + return "Minecart"; + } + + public function getType() : int{ + return self::TYPE_NORMAL; + } + + public function onUpdate($currentTick){ + if($this->closed !== false){ + return false; + } + + $tickDiff = $currentTick - $this->lastUpdate; + if($tickDiff <= 1){ + return false; + } + + $this->lastUpdate = $currentTick; + + $this->timings->startTiming(); + + $hasUpdate = false; + //parent::onUpdate($currentTick); + + if($this->isAlive()){ + $p = $this->getLinkedEntity(); + if($p instanceof Player){ + if($this->state === Minecart::STATE_INITIAL){ + $this->checkIfOnRail(); + }elseif($this->state === Minecart::STATE_ON_RAIL){ + $hasUpdate = $this->forwardOnRail($p); + $this->updateMovement(); + } + } + } + $this->timings->stopTiming (); + + return $hasUpdate or ! $this->onGround or abs ( $this->motionX ) > 0.00001 or abs ( $this->motionY ) > 0.00001 or abs ( $this->motionZ ) > 0.00001; + } + + + /** + * Check if minecart is currently on a rail and if so center the cart. + */ + private function checkIfOnRail() { + for ($y = -1; $y !== 2 and $this->state === Minecart::STATE_INITIAL; $y++) { + $positionToCheck = $this->temporalVector->setComponents($this->x, $this->y + $y, $this->z); + $block = $this->level->getBlock($positionToCheck); + if($this->isRail($block)){ + $minecartPosition = $positionToCheck->floor()->add(0.5, 0, 0.5); + $this->setPosition($minecartPosition); // Move minecart to center of rail + $this->state = Minecart::STATE_ON_RAIL; + } + } + if($this->state !== Minecart::STATE_ON_RAIL){ + $this->state = Minecart::STATE_OFF_RAIL; + } + } + + private function isRail($rail) { + return ($rail !== null and in_array($rail->getId(), [Block::RAIL, Block::ACTIVATOR_RAIL, Block::DETECTOR_RAIL, Block::POWERED_RAIL])); + } + + private function getCurrentRail() { + $block = $this->getLevel()->getBlock($this); + if($this->isRail($block)){ + return $block; + } + // Rail could be one block below descending down + $down = $this->temporalVector->setComponents($this->x, $this->y - 1, $this->z); + $block = $this->getLevel()->getBlock($down); + if($this->isRail($block)){ + return $block; + } + return null; + } + + /** + * Attempt to move forward on rail given the direction the cart is already moving, or if not moving based + * on the direction the player is looking. + * @param Player $player Player riding the minecart. + * @return boolean True if minecart moved, false otherwise. + */ + private function forwardOnRail(Player $player) { + if($this->direction === -1){ + $candidateDirection = $player->getDirection(); + }else{ + $candidateDirection = $this->direction; + } + $rail = $this->getCurrentRail(); + if ($rail !== null) { + $railType = $rail->getDamage (); + $nextDirection = $this->getDirectionToMove($railType, $candidateDirection); + if ($nextDirection !== -1) { + $this->direction = $nextDirection; + $moved = $this->checkForVertical($railType, $nextDirection); + if(!$moved){ + return $this->moveIfRail(); + }else{ + return true; + } + }else{ + $this->direction = -1; // Was not able to determine direction to move, so wait for player to look in valid direction + } + }else{ + // Not able to find rail + $this->state = Minecart::STATE_INITIAL; + } + return false; + } + + /** + * Determine the direction the minecart should move based on the candidate direction (current direction + * minecart is moving, or the direction the player is looking) and the type of rail that the minecart is + * on. + * @param RailType $railType Type of rail the minecart is on. + * @param Direction $candidateDirection Direction minecart already moving, or direction player looking. + * @return Direction The direction the minecart should move. + */ + private function getDirectionToMove($railType, $candidateDirection) { + switch($railType){ + case Rail::STRAIGHT_NORTH_SOUTH: + case Rail::SLOPED_ASCENDING_NORTH: + case Rail::SLOPED_ASCENDING_SOUTH: + switch($candidateDirection){ + case Entity::NORTH: + case Entity::SOUTH: + return $candidateDirection; + } + break; + case Rail::STRAIGHT_EAST_WEST: + case Rail::SLOPED_ASCENDING_EAST: + case Rail::SLOPED_ASCENDING_WEST: + switch($candidateDirection){ + case Entity::WEST: + case Entity::EAST: + return $candidateDirection; + } + break; + case Rail::CURVED_SOUTH_EAST: + switch($candidateDirection){ + case Entity::SOUTH: + case Entity::EAST: + return $candidateDirection; + case Entity::NORTH: + return $this->checkForTurn($candidateDirection, Entity::EAST); + case Entity::WEST: + return $this->checkForTurn($candidateDirection, Entity::SOUTH); + } + break; + case Rail::CURVED_SOUTH_WEST: + switch($candidateDirection){ + case Entity::SOUTH: + case Entity::WEST: + return $candidateDirection; + case Entity::NORTH: + return $this->checkForTurn($candidateDirection, Entity::WEST); + case Entity::EAST: + return $this->checkForTurn($candidateDirection, Entity::SOUTH); + } + break; + case Rail::CURVED_NORTH_WEST: + switch ($candidateDirection) { + case Entity::NORTH: + case Entity::WEST: + return $candidateDirection; + case Entity::SOUTH: + return $this->checkForTurn($candidateDirection, Entity::WEST); + case Entity::EAST: + return $this->checkForTurn($candidateDirection, Entity::NORTH); + + } + break; + case Rail::CURVED_NORTH_EAST: + switch ($candidateDirection) { + case Entity::NORTH: + case Entity::EAST: + return $candidateDirection; + case Entity::SOUTH: + return $this->checkForTurn($candidateDirection, Entity::EAST); + case Entity::WEST: + return $this->checkForTurn($candidateDirection, Entity::NORTH); + } + break; + } + return -1; + } + + /** + * Need to alter direction on curves halfway through the turn and reset the minecart to be in the middle of + * the rail again so as not to collide with nearby blocks. + * @param Direction $currentDirection Direction minecart currently moving + * @param Direction $newDirection Direction minecart should turn once has hit the halfway point. + * @return Direction Either the current direction or the new direction depending on haw far across the rail the + * minecart is. + */ + private function checkForTurn($currentDirection, $newDirection) { + switch($currentDirection) { + case Entity::NORTH: + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff <= .5) { + $dx = ($this->getFloorX() + .5) - $this->x; + $this->move($dx, 0, 0); + return $newDirection; + } + break; + case Entity::SOUTH: + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff >= .5) { + $dx = ($this->getFloorX() + .5) - $this->x; + $this->move($dx, 0, 0); + return $newDirection; + } + break; + case Entity::EAST: + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff <= .5) { + $dz = ($this->getFloorZ() + .5) - $this->z; + $this->move(0, 0, $dz); + return $newDirection; + } + break; + case Entity::WEST: + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff >= .5) { + $dz = $dz = ($this->getFloorZ() + .5) - $this->z; + $this->move(0, 0, $dz); + return $newDirection; + } + break; + } + return $currentDirection; + } + + private function checkForVertical($railType, $currentDirection) { + switch ($railType) { + case Rail::SLOPED_ASCENDING_NORTH: + switch($currentDirection){ + case Entity::NORTH: + // Headed north up + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff <= .5) { + $dx = ($this->getFloorX() - .1) - $this->x; + $this->move($dx, 1, 0); + return true; + } + break; + case ENTITY::SOUTH: + // Headed south down + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff >= .5) { + $dx = ($this->getFloorX() + 1 ) - $this->x; + $this->move($dx, -1, 0); + return true; + } + break; + } + break; + case Rail::SLOPED_ASCENDING_SOUTH: + switch($currentDirection){ + case Entity::SOUTH: + // Headed south up + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff >= .5) { + $dx = ($this->getFloorX() + 1 ) - $this->x; + $this->move($dx, 1, 0); + return true; + } + break; + case Entity::NORTH: + // Headed north down + $diff = $this->x - $this->getFloorX(); + if ($diff !== 0 and $diff <= .5) { + $dx = ($this->getFloorX() - .1) - $this->x; + $this->move($dx, -1, 0); + return true; + } + break; + } + break; + case Rail::SLOPED_ASCENDING_EAST: + switch($currentDirection){ + case Entity::EAST: + // Headed east up + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff <= .5) { + $dz = ($this->getFloorZ() - .1) - $this->z; + $this->move(0, 1, $dz); + return true; + } + break; + case Entity::WEST: + // Headed west down + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff >= .5) { + $dz = ($this->getFloorZ() + 1) - $this->z; + $this->move(0, -1, $dz); + return true; + } + break; + } + break; + case Rail::SLOPED_ASCENDING_WEST: + switch($currentDirection){ + case Entity::WEST: + // Headed west up + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff >= .5) { + $dz = ($this->getFloorZ() + 1) - $this->z; + $this->move(0, 1, $dz); + return true; + } + break; + case Entity::EAST: + // Headed east down + $diff = $this->z - $this->getFloorZ(); + if ($diff !== 0 and $diff <= .5) { + $dz = ($this->getFloorZ() - .1) - $this->z; + $this->move(0, -1, $dz); + return true; + } + break; + } + break; + } + return false; + } + + /** + * Move the minecart as long as it will still be moving on to another piece of rail. + * @return boolean True if the minecart moved. + */ + private function moveIfRail(){ + $nextMoveVector = $this->moveVector[$this->direction]; + $nextMoveVector = $nextMoveVector->multiply($this->moveSpeed); + $newVector = $this->add($nextMoveVector->x, $nextMoveVector->y, $nextMoveVector->z); + $possibleRail = $this->getCurrentRail(); + if(in_array($possibleRail->getId(), [Block::RAIL, Block::ACTIVATOR_RAIL, Block::DETECTOR_RAIL, Block::POWERED_RAIL])) { + $this->moveUsingVector($newVector); + return true; + } + } + + /** + * Invoke the normal move code, but first need to convert the desired position vector into the + * delta values from the current position. + * @param Vector3 $desiredPosition + */ + private function moveUsingVector(Vector3 $desiredPosition){ + $dx = $desiredPosition->x - $this->x; + $dy = $desiredPosition->y - $this->y; + $dz = $desiredPosition->z - $this->z; + $this->move($dx, $dy, $dz); + } + + + /** + * @return Rail + */ + public function getNearestRail(){ + $minX = Math::floorFloat($this->boundingBox->minX); + $minY = Math::floorFloat($this->boundingBox->minY); + $minZ = Math::floorFloat($this->boundingBox->minZ); + $maxX = Math::ceilFloat($this->boundingBox->maxX); + $maxY = Math::ceilFloat($this->boundingBox->maxY); + $maxZ = Math::ceilFloat($this->boundingBox->maxZ); + + $rails = []; + + for($z = $minZ; $z <= $maxZ; ++$z){ + for($x = $minX; $x <= $maxX; ++$x){ + for($y = $minY; $y <= $maxY; ++$y){ + $block = $this->level->getBlock($this->temporalVector->setComponents($x, $y, $z)); + if(in_array($block->getId(), [Block::RAIL, Block::ACTIVATOR_RAIL, Block::DETECTOR_RAIL, Block::POWERED_RAIL])) $rails[] = $block; + } + } + } + + $minDistance = PHP_INT_MAX; + $nearestRail = null; + foreach($rails as $rail){ + $dis = $this->distance($rail); + if($dis < $minDistance){ + $nearestRail = $rail; + $minDistance = $dis; + } + } + return $nearestRail; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Minecart::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = 0; + $pk->speedY = 0; + $pk->speedZ = 0; + $pk->yaw = 0; + $pk->pitch = 0; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + /*public function attack($damage, EntityDamageEvent $source){ + parent::attack($damage, $source); + + if(!$source->isCancelled()){ + $pk = new EntityEventPacket(); + $pk->eid = $this->id; + $pk->event = EntityEventPacket::HURT_ANIMATION; + foreach($this->getLevel()->getPlayers() as $player){ + $player->dataPacket($pk); + } + } + } + + public function getSaveId(){ + $class = new \ReflectionClass(static::class); + return $class->getShortName(); + }*/ +} diff --git a/src/devmine/server/calculations/entity/MinecartChest.php b/src/devmine/server/calculations/entity/MinecartChest.php new file mode 100644 index 0000000..9a45075 --- /dev/null +++ b/src/devmine/server/calculations/entity/MinecartChest.php @@ -0,0 +1,55 @@ +eid = $this->getId(); + $pk->type = MinecartChest::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = 0; + $pk->speedY = 0; + $pk->speedZ = 0; + $pk->yaw = 0; + $pk->pitch = 0; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + Entity::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/MinecartHopper.php b/src/devmine/server/calculations/entity/MinecartHopper.php new file mode 100644 index 0000000..1d51587 --- /dev/null +++ b/src/devmine/server/calculations/entity/MinecartHopper.php @@ -0,0 +1,55 @@ +eid = $this->getId(); + $pk->type = MinecartHopper::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = 0; + $pk->speedY = 0; + $pk->speedZ = 0; + $pk->yaw = 0; + $pk->pitch = 0; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + Entity::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/MinecartTNT.php b/src/devmine/server/calculations/entity/MinecartTNT.php new file mode 100644 index 0000000..3522357 --- /dev/null +++ b/src/devmine/server/calculations/entity/MinecartTNT.php @@ -0,0 +1,55 @@ +eid = $this->getId(); + $pk->type = MinecartTNT::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = 0; + $pk->speedY = 0; + $pk->speedZ = 0; + $pk->yaw = 0; + $pk->pitch = 0; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + Entity::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Monster.php b/src/devmine/server/calculations/entity/Monster.php new file mode 100644 index 0000000..efe2edb --- /dev/null +++ b/src/devmine/server/calculations/entity/Monster.php @@ -0,0 +1,10 @@ +eid = $this->getId(); + $pk->type = Mooshroom::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $lootingL = 0; + $cause = $this->lastDamageCause; + if($cause instanceof EntityDamageByEntityEvent and $cause->getDamager() instanceof Player){ + $lootingL = $cause->getDamager()->getItemInHand()->getEnchantmentLevel(Enchantment::TYPE_WEAPON_LOOTING); + } + $drops = array(ItemItem::get(ItemItem::RAW_BEEF, 0, mt_rand(1, 3 + $lootingL))); + $drops[] = ItemItem::get(ItemItem::LEATHER, 0, mt_rand(0, 2 + $lootingL)); + return $drops; + } +} diff --git a/src/devmine/server/calculations/entity/NPC.php b/src/devmine/server/calculations/entity/NPC.php new file mode 100644 index 0000000..21d7dd5 --- /dev/null +++ b/src/devmine/server/calculations/entity/NPC.php @@ -0,0 +1,10 @@ +CatType)){ + $nbt->CatType = new ByteTag("CatType", mt_rand(0, 3)); + } + parent::__construct($chunk, $nbt); + + $this->setDataProperty(self::DATA_CAT_TYPE, self::DATA_TYPE_BYTE, $this->getCatType()); + } + + public function setCatType(int $type){ + $this->namedtag->CatType = new ByteTag("CatType", $type); + } + + public function getCatType() : int{ + return (int) $this->namedtag["CatType"]; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = self::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Painting.php b/src/devmine/server/calculations/entity/Painting.php new file mode 100644 index 0000000..2ac549c --- /dev/null +++ b/src/devmine/server/calculations/entity/Painting.php @@ -0,0 +1,58 @@ +setMaxHealth(1); + parent::initEntity(); + + if(isset($this->namedtag->Motive)){ + $this->motive = $this->namedtag["Motive"]; + }else $this->close(); + } + + public function attack($damage, EntityDamageEvent $source){ + parent::attack($damage, $source); + if($source->isCancelled()) return false; + $this->level->addParticle(new DestroyBlockParticle($this->add(0.5), Block::get(Block::LADDER))); + $this->kill(); + } + + public function spawnTo(Player $player){ + $pk = new AddPaintingPacket(); + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->direction = $this->getDirection(); + $pk->title = $this->motive; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + protected function updateMovement(){ + //Nothing to update, paintings cannot move. + } + + public function getDrops(){ + return [ItemItem::get(ItemItem::PAINTING, 0, 1)]; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Pig.php b/src/devmine/server/calculations/entity/Pig.php new file mode 100644 index 0000000..87ef364 --- /dev/null +++ b/src/devmine/server/calculations/entity/Pig.php @@ -0,0 +1,70 @@ +eid = $this->getId(); + $pk->type = Pig::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $lootingL = 0; + $cause = $this->lastDamageCause; + if($cause instanceof EntityDamageByEntityEvent and $cause->getDamager() instanceof Player){ + $lootingL = $cause->getDamager()->getItemInHand()->getEnchantmentLevel(Enchantment::TYPE_WEAPON_LOOTING); + } + $drops = array(ItemItem::get(ItemItem::RAW_PORKCHOP, 0, mt_rand(1, 3 + $lootingL))); + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/PigZombie.php b/src/devmine/server/calculations/entity/PigZombie.php new file mode 100644 index 0000000..db3e38a --- /dev/null +++ b/src/devmine/server/calculations/entity/PigZombie.php @@ -0,0 +1,69 @@ +eid = $this->getId(); + $pk->type = PigZombie::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + + $pk = new MobEquipmentPacket(); + $pk->eid = $this->getId(); + $pk->item = new ItemItem(283); + $pk->slot = 0; + $pk->selectedSlot = 0; + + $player->dataPacket($pk); + } + + public function getDrops(){ + $cause = $this->lastDamageCause; + $drops = []; + if($cause instanceof EntityDamageByEntityEvent and $cause->getDamager() instanceof Player){ + $lootingL = $cause->getDamager()->getItemInHand()->getEnchantmentLevel(Enchantment::TYPE_WEAPON_LOOTING); + if(mt_rand(1, 200) <= (5 + 2 * $lootingL)){ + $drops[] = ItemItem::get(ItemItem::GOLD_INGOT, 0, 1); + } + $drops[] = ItemItem::get(ItemItem::GOLD_NUGGET, 0, mt_rand(0, 1 + $lootingL)); + $drops[] = ItemItem::get(ItemItem::ROTTEN_FLESH, 0, mt_rand(0, 1 + $lootingL)); + } + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/PolarBear.php b/src/devmine/server/calculations/entity/PolarBear.php new file mode 100644 index 0000000..be6e7f8 --- /dev/null +++ b/src/devmine/server/calculations/entity/PolarBear.php @@ -0,0 +1,62 @@ +setMaxHealth(30); + return "Polar Bear"; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = PolarBear::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $cause = $this->lastDamageCause; + $drops = []; + if($cause instanceof EntityDamageByEntityEvent and $cause->getDamager() instanceof Player){ + $drops = []; + if (mt_rand(1, 4) === 1) { + $drops[] = ItemItem::get(ItemItem::RAW_SALMON, 0, mt_rand(0, 2));//yes.. 0,2 + } else { + $drops[] = ItemItem::get(ItemItem::RAW_FISH, 0, mt_rand(0, 2));//yes.. 0,2 + } + } + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/PrimedTNT.php b/src/devmine/server/calculations/entity/PrimedTNT.php new file mode 100644 index 0000000..6498919 --- /dev/null +++ b/src/devmine/server/calculations/entity/PrimedTNT.php @@ -0,0 +1,143 @@ +dropItem = $dropItem; + } + + + public function attack($damage, EntityDamageEvent $source){ + if($source->getCause() === EntityDamageEvent::CAUSE_VOID){ + parent::attack($damage, $source); + } + } + + protected function initEntity(){ + parent::initEntity(); + + if(isset($this->namedtag->Fuse)){ + $this->fuse = $this->namedtag["Fuse"]; + }else{ + $this->fuse = 80; + } + } + + + public function canCollideWith(Entity $entity){ + return false; + } + + public function saveNBT(){ + parent::saveNBT(); + $this->namedtag->Fuse = new ByteTag("Fuse", $this->fuse); + } + + public function onUpdate($currentTick){ + + if($this->closed){ + return false; + } + + $this->timings->startTiming(); + + $tickDiff = $currentTick - $this->lastUpdate; + if($tickDiff <= 0 and !$this->justCreated){ + return true; + } + $this->lastUpdate = $currentTick; + + $hasUpdate = $this->entityBaseTick($tickDiff); + + if($this->isAlive()){ + + $this->motionY -= $this->gravity; + + $this->move($this->motionX, $this->motionY, $this->motionZ); + + $friction = 1 - $this->drag; + + $this->motionX *= $friction; + $this->motionY *= $friction; + $this->motionZ *= $friction; + + $this->updateMovement(); + + if($this->onGround){ + $this->motionY *= -0.5; + $this->motionX *= 0.7; + $this->motionZ *= 0.7; + } + + $this->fuse -= $tickDiff; + + if($this->fuse <= 0){ + $this->kill(); + $this->explode(); + } + + } + + + return $hasUpdate or $this->fuse >= 0 or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + } + + public function explode(){ + $this->server->getPluginManager()->callEvent($ev = new ExplosionPrimeEvent($this, 4, $this->dropItem)); + + if(!$ev->isCancelled()){ + $explosion = new Explosion($this, $ev->getForce(), $this, $ev->dropItem()); + if($ev->isBlockBreaking()){ + $explosion->explodeA(); + } + $explosion->explodeB(); + } + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = PrimedTNT::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Projectile.php b/src/devmine/server/calculations/entity/Projectile.php new file mode 100644 index 0000000..ad2841c --- /dev/null +++ b/src/devmine/server/calculations/entity/Projectile.php @@ -0,0 +1,190 @@ +shootingEntity = $shootingEntity; + if($shootingEntity !== null){ + $this->setDataProperty(self::DATA_SHOOTER_ID, self::DATA_TYPE_LONG, $shootingEntity->getId()); + } + parent::__construct($chunk, $nbt); + } + + public function attack($damage, EntityDamageEvent $source){ + if($source->getCause() === EntityDamageEvent::CAUSE_VOID){ + parent::attack($damage, $source); + } + } + + protected function initEntity(){ + parent::initEntity(); + + $this->setMaxHealth(1); + $this->setHealth(1); + if(isset($this->namedtag->Age)){ + $this->age = $this->namedtag["Age"]; + } + + } + + public function canCollideWith(Entity $entity){ + return $entity instanceof Living and !$this->onGround; + } + + public function saveNBT(){ + parent::saveNBT(); + $this->namedtag->Age = new ShortTag("Age", $this->age); + } + + public function onUpdate($currentTick){ + if($this->closed){ + return false; + } + + + $tickDiff = $currentTick - $this->lastUpdate; + if($tickDiff <= 0 and !$this->justCreated){ + return true; + } + $this->lastUpdate = $currentTick; + + $hasUpdate = $this->entityBaseTick($tickDiff); + + if($this->isAlive()){ + + $movingObjectPosition = null; + + if(!$this->isCollided){ + $this->motionY -= $this->gravity; + } + + $moveVector = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ); + + $list = $this->getLevel()->getCollidingEntities($this->boundingBox->addCoord($this->motionX, $this->motionY, $this->motionZ)->expand(1, 1, 1), $this); + + $nearDistance = PHP_INT_MAX; + $nearEntity = null; + + foreach($list as $entity){ + if(/*!$entity->canCollideWith($this) or */ + ($entity === $this->shootingEntity and $this->ticksLived < 5) + ){ + continue; + } + + $axisalignedbb = $entity->boundingBox->grow(0.3, 0.3, 0.3); + $ob = $axisalignedbb->calculateIntercept($this, $moveVector); + + if($ob === null){ + continue; + } + + $distance = $this->distanceSquared($ob->hitVector); + + if($distance < $nearDistance){ + $nearDistance = $distance; + $nearEntity = $entity; + } + } + + if($nearEntity !== null){ + $movingObjectPosition = MovingObjectPosition::fromEntity($nearEntity); + } + + if($movingObjectPosition !== null){ + if($movingObjectPosition->entityHit !== null){ + + $this->server->getPluginManager()->callEvent(new ProjectileHitEvent($this)); + + $motion = sqrt($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2); + $damage = ceil($motion * $this->damage); + + if($this instanceof Arrow and $this->isCritical){ + $damage += mt_rand(0, (int) ($damage / 2) + 1); + } + + if($this->shootingEntity === null){ + $ev = new EntityDamageByEntityEvent($this, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage); + }else{ + $ev = new EntityDamageByChildEntityEvent($this->shootingEntity, $this, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage); + } + + if($movingObjectPosition->entityHit->attack($ev->getFinalDamage(), $ev) === true){ + if($this instanceof Arrow and $this->getPotionId() != 0){ + foreach(Potion::getEffectsById($this->potionId - 1) as $effect){ + $movingObjectPosition->entityHit->addEffect($effect->setDuration($effect->getDuration() / 8)); + } + } + $ev->useArmors(); + } + + $this->hadCollision = true; + + if($this->fireTicks > 0){ + $ev = new EntityCombustByEntityEvent($this, $movingObjectPosition->entityHit, 5); + $this->server->getPluginManager()->callEvent($ev); + if(!$ev->isCancelled()){ + $movingObjectPosition->entityHit->setOnFire($ev->getDuration()); + } + } + + $this->kill(); + return true; + } + } + + $this->move($this->motionX, $this->motionY, $this->motionZ); + + if($this->isCollided and !$this->hadCollision){ + $this->hadCollision = true; + + $this->motionX = 0; + $this->motionY = 0; + $this->motionZ = 0; + + $this->server->getPluginManager()->callEvent(new ProjectileHitEvent($this)); + }elseif(!$this->isCollided and $this->hadCollision){ + $this->hadCollision = false; + } + + if(!$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001){ + $f = sqrt(($this->motionX ** 2) + ($this->motionZ ** 2)); + $this->yaw = (atan2($this->motionX, $this->motionZ) * 180 / M_PI); + $this->pitch = (atan2($this->motionY, $f) * 180 / M_PI); + $hasUpdate = true; + } + + $this->updateMovement(); + + } + + return $hasUpdate; + } + +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/ProjectileSource.php b/src/devmine/server/calculations/entity/ProjectileSource.php new file mode 100644 index 0000000..872699e --- /dev/null +++ b/src/devmine/server/calculations/entity/ProjectileSource.php @@ -0,0 +1,10 @@ +setMaxHealth(3); + parent::initEntity(); + } + + public function __construct(Chunk $chunk, CompoundTag $nbt){ + if(!isset($nbt->RabbitType)){ + $nbt->RabbitType = new ByteTag("RabbitType", $this->getRandomRabbitType()); + } + parent::__construct($chunk, $nbt); + + $this->setDataProperty(self::DATA_RABBIT_TYPE, self::DATA_TYPE_BYTE, $this->getRabbitType()); + } + + public function getRandomRabbitType() : int{ + $arr = [0, 1, 2, 3, 4, 5, 99]; + return $arr[mt_rand(0, count($arr) - 1)]; + } + + public function setRabbitType(int $type){ + $this->namedtag->RabbitType = new ByteTag("RabbitType", $type); + } + + public function getRabbitType() : int{ + return (int) $this->namedtag["RabbitType"]; + } + + public function getName() : string{ + return "Rabbit"; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Rabbit::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $lootingL = 0; + $cause = $this->lastDamageCause; + if($cause instanceof EntityDamageByEntityEvent and $cause->getDamager() instanceof Player){ + $lootingL = $cause->getDamager()->getItemInHand()->getEnchantmentLevel(Enchantment::TYPE_WEAPON_LOOTING); + } + $drops = [ItemItem::get(ItemItem::RABBIT_HIDE, 0, mt_rand(0, 1))]; + if($this->getLastDamageCause() === EntityDamageEvent::CAUSE_FIRE){ + $drops[] = ItemItem::get(ItemItem::COOKED_RABBIT, 0, mt_rand(0, 1)); + }else{ + $drops[] = ItemItem::get(ItemItem::RAW_RABBIT, 0, mt_rand(0, 1)); + } + //Rare drop + if(mt_rand(1, 200) <= (5 + 2 * $lootingL)){ + $drops[] = ItemItem::get(ItemItem::RABBIT_FOOT, 0, 1); + } + return $drops; + } + + +} diff --git a/src/devmine/server/calculations/entity/Rideable.php b/src/devmine/server/calculations/entity/Rideable.php new file mode 100644 index 0000000..cb19eb8 --- /dev/null +++ b/src/devmine/server/calculations/entity/Rideable.php @@ -0,0 +1,10 @@ +Color)){ + $nbt->Color = new ByteTag("Color", self::getRandomColor()); + } + parent::__construct($chunk, $nbt); + + $this->setDataProperty(self::DATA_COLOR_INFO, self::DATA_TYPE_BYTE, $this->getColor()); + } + + public static function getRandomColor() : int{ + $rand = ""; + $rand .= str_repeat(Wool::WHITE . " ", 20); + $rand .= str_repeat(Wool::ORANGE . " ", 5); + $rand .= str_repeat(Wool::MAGENTA . " ", 5); + $rand .= str_repeat(Wool::LIGHT_BLUE . " ", 5); + $rand .= str_repeat(Wool::YELLOW . " ", 5); + $rand .= str_repeat(Wool::GRAY . " ", 10); + $rand .= str_repeat(Wool::LIGHT_GRAY . " ", 10); + $rand .= str_repeat(Wool::CYAN . " ", 5); + $rand .= str_repeat(Wool::PURPLE . " ", 5); + $rand .= str_repeat(Wool::BLUE . " ", 5); + $rand .= str_repeat(Wool::BROWN . " ", 5); + $rand .= str_repeat(Wool::GREEN . " ", 5); + $rand .= str_repeat(Wool::RED . " ", 5); + $rand .= str_repeat(Wool::BLACK . " ", 10); + $arr = explode(" ", $rand); + return intval($arr[mt_rand(0, count($arr) - 1)]); + } + + public function getColor() : int{ + return (int) $this->namedtag["Color"]; + } + + public function setColor(int $color){ + $this->namedtag->Color = new ByteTag("Color", $color); + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Sheep::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $drops = [ + ItemItem::get(ItemItem::WOOL, $this->getColor(), 1) + ]; + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Shulker.php b/src/devmine/server/calculations/entity/Shulker.php new file mode 100644 index 0000000..9fa6944 --- /dev/null +++ b/src/devmine/server/calculations/entity/Shulker.php @@ -0,0 +1,66 @@ +eid = $this->getId(); + $pk->type = Shulker::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + parent::spawnTo($player); + } + + public function getDrops(){ + $drops = []; + if ($this->lastDamageCause instanceof EntityDamageByEntityEvent and $this->lastDamageCause->getEntity() instanceof Player) { + if (mt_rand(0, 1) === 1) $drops[] = ItemItem::get(ItemItem::SHULKER_SHELL, 0, 1); + } + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/ShulkerBullet.php b/src/devmine/server/calculations/entity/ShulkerBullet.php new file mode 100644 index 0000000..1047893 --- /dev/null +++ b/src/devmine/server/calculations/entity/ShulkerBullet.php @@ -0,0 +1,61 @@ +closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = ShulkerBullet::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Silverfish.php b/src/devmine/server/calculations/entity/Silverfish.php new file mode 100644 index 0000000..2cb8959 --- /dev/null +++ b/src/devmine/server/calculations/entity/Silverfish.php @@ -0,0 +1,36 @@ +eid = $this->getId(); + $pk->type = Silverfish::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Skeleton.php b/src/devmine/server/calculations/entity/Skeleton.php new file mode 100644 index 0000000..7ee539d --- /dev/null +++ b/src/devmine/server/calculations/entity/Skeleton.php @@ -0,0 +1,64 @@ +eid = $this->getId(); + $pk->type = Skeleton::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + + $pk = new MobEquipmentPacket(); + $pk->eid = $this->getId(); + $pk->item = new ItemItem(ItemItem::BOW); + $pk->slot = 0; + $pk->selectedSlot = 0; + + $player->dataPacket($pk); + } +} diff --git a/src/devmine/server/calculations/entity/Slime.php b/src/devmine/server/calculations/entity/Slime.php new file mode 100644 index 0000000..b38598a --- /dev/null +++ b/src/devmine/server/calculations/entity/Slime.php @@ -0,0 +1,80 @@ +eid = $this->getId(); + $pk->type = Slime::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + parent::spawnTo($player); + } + + public function getDrops(){ + $drops = array(ItemItem::get(ItemItem::SLIMEBALL, 0, 1)); + if ($this->lastDamageCause instanceof EntityDamageByEntityEvent and $this->lastDamageCause->getEntity() instanceof Player) { + if (\mt_rand(0, 199) < 5) { + switch (\mt_rand(0, 2)) { + case 0: + $drops[] = ItemItem::get(ItemItem::IRON_INGOT, 0, 1); + break; + case 1: + $drops[] = ItemItem::get(ItemItem::CARROT, 0, 1); + break; + case 2: + $drops[] = ItemItem::get(ItemItem::POTATO, 0, 1); + break; + } + } + } + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/SnowGolem.php b/src/devmine/server/calculations/entity/SnowGolem.php new file mode 100644 index 0000000..1fab7da --- /dev/null +++ b/src/devmine/server/calculations/entity/SnowGolem.php @@ -0,0 +1,60 @@ +setMaxHealth(4); + parent::initEntity(); + } + + public function getName() { + return "Snow Golem"; + } + + public function spawnTo(Player $player) { + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = self::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Snowball.php b/src/devmine/server/calculations/entity/Snowball.php new file mode 100644 index 0000000..4d35523 --- /dev/null +++ b/src/devmine/server/calculations/entity/Snowball.php @@ -0,0 +1,61 @@ +closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = Snowball::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Spider.php b/src/devmine/server/calculations/entity/Spider.php new file mode 100644 index 0000000..54175ac --- /dev/null +++ b/src/devmine/server/calculations/entity/Spider.php @@ -0,0 +1,79 @@ +eid = $this->getId(); + $pk->type = Spider::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + + parent::spawnTo($player); + } + + public function getDrops(){ + $drops = array(ItemItem::get(ItemItem::STRING, 0, 1)); + if ($this->lastDamageCause instanceof EntityDamageByEntityEvent and $this->lastDamageCause->getEntity() instanceof Player) { + if (mt_rand(0, 199) < 5) { + switch (mt_rand(0, 2)) { + case 0: + $drops[] = ItemItem::get(ItemItem::IRON_INGOT, 0, 1); + break; + case 1: + $drops[] = ItemItem::get(ItemItem::CARROT, 0, 1); + break; + case 2: + $drops[] = ItemItem::get(ItemItem::POTATO, 0, 1); + break; + } + } + } + return $drops; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Squid.php b/src/devmine/server/calculations/entity/Squid.php new file mode 100644 index 0000000..8a0aa48 --- /dev/null +++ b/src/devmine/server/calculations/entity/Squid.php @@ -0,0 +1,163 @@ +setMaxHealth(5); + } + + public function getName() : string{ + return "Squid"; + } + + public function attack($damage, EntityDamageEvent $source){ + parent::attack($damage, $source); + if($source->isCancelled()){ + return; + } + + if($source instanceof EntityDamageByEntityEvent){ + $this->swimSpeed = mt_rand(150, 350) / 2000; + $e = $source->getDamager(); + $this->swimDirection = (new Vector3($this->x - $e->x, $this->y - $e->y, $this->z - $e->z))->normalize(); + + $pk = new EntityEventPacket(); + $pk->eid = $this->getId(); + $pk->event = EntityEventPacket::SQUID_INK_CLOUD; + Server::broadcastPacket($this->hasSpawned, $pk); + } + } + + private function generateRandomDirection(){ + return new Vector3(mt_rand(-1000, 1000) / 1000, mt_rand(-500, 500) / 1000, mt_rand(-1000, 1000) / 1000); + } + + + public function onUpdate($currentTick){ + if($this->closed !== false){ + return false; + } + + if(++$this->switchDirectionTicker === 100){ + $this->switchDirectionTicker = 0; + if(mt_rand(0, 100) < 50){ + $this->swimDirection = null; + } + } + + $this->lastUpdate = $currentTick; + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->isAlive()){ + + if($this->y > 62 and $this->swimDirection !== null){ + $this->swimDirection->y = -0.5; + } + + $inWater = $this->isInsideOfWater(); + if(!$inWater){ + $this->motionY -= $this->gravity; + $this->swimDirection = null; + }elseif($this->swimDirection !== null){ + if($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2 <= $this->swimDirection->lengthSquared()){ + $this->motionX = $this->swimDirection->x * $this->swimSpeed; + $this->motionY = $this->swimDirection->y * $this->swimSpeed; + $this->motionZ = $this->swimDirection->z * $this->swimSpeed; + } + }else{ + $this->swimDirection = $this->generateRandomDirection(); + $this->swimSpeed = mt_rand(50, 100) / 2000; + } + + $expectedPos = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ); + + $this->move($this->motionX, $this->motionY, $this->motionZ); + + if($expectedPos->distanceSquared($this) > 0){ + $this->swimDirection = $this->generateRandomDirection(); + $this->swimSpeed = mt_rand(50, 100) / 2000; + } + + $friction = 1 - $this->drag; + + $this->motionX *= $friction; + $this->motionY *= 1 - $this->drag; + $this->motionZ *= $friction; + + $f = sqrt(($this->motionX ** 2) + ($this->motionZ ** 2)); + $this->yaw = (-atan2($this->motionX, $this->motionZ) * 180 / M_PI); + $this->pitch = (-atan2($f, $this->motionY) * 180 / M_PI); + + if($this->onGround){ + $this->motionY *= -0.5; + } + + } + + $this->timings->stopTiming(); + + return $hasUpdate or !$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + } + + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Squid::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $lootingL = 0; + $cause = $this->lastDamageCause; + if($cause instanceof EntityDamageByEntityEvent and $cause->getDamager() instanceof Player){ + $lootingL = $cause->getDamager()->getItemInHand()->getEnchantmentLevel(Enchantment::TYPE_WEAPON_LOOTING); + } + return [ + ItemItem::get(ItemItem::DYE, 0, mt_rand(1, 3 + $lootingL)) + ]; + } +} diff --git a/src/devmine/server/calculations/entity/Stray.php b/src/devmine/server/calculations/entity/Stray.php new file mode 100644 index 0000000..95ca569 --- /dev/null +++ b/src/devmine/server/calculations/entity/Stray.php @@ -0,0 +1,64 @@ +eid = $this->getId(); + $pk->type = Stray::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + Entity::spawnTo($player); + + $pk = new MobEquipmentPacket(); + $pk->eid = $this->getId(); + $pk->item = new ItemItem(ItemItem::BOW); + $pk->slot = 0; + $pk->selectedSlot = 0; + + $player->dataPacket($pk); + } +} diff --git a/src/devmine/server/calculations/entity/Tameable.php b/src/devmine/server/calculations/entity/Tameable.php new file mode 100644 index 0000000..6b85e74 --- /dev/null +++ b/src/devmine/server/calculations/entity/Tameable.php @@ -0,0 +1,10 @@ +closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + $this->age++; + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $this->close(); + $this->getLevel()->addParticle(new SpellParticle($this, 46, 82, 153)); + if($this->getLevel()->getServer()->expEnabled){ + $this->getLevel()->spawnXPOrb($this->add(0, -0.2, 0), mt_rand(1, 4)); + $this->getLevel()->spawnXPOrb($this->add(-0.1, -0.2, 0), mt_rand(1, 4)); + $this->getLevel()->spawnXPOrb($this->add(0, -0.2, -0.1), mt_rand(1, 4)); + } + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = ThrownExpBottle::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/ThrownPotion.php b/src/devmine/server/calculations/entity/ThrownPotion.php new file mode 100644 index 0000000..ad4643b --- /dev/null +++ b/src/devmine/server/calculations/entity/ThrownPotion.php @@ -0,0 +1,113 @@ +PotionId)){ + $nbt->PotionId = new ShortTag("PotionId", Potion::AWKWARD); + } + + parent::__construct($chunk, $nbt, $shootingEntity); + + unset($this->dataProperties[self::DATA_SHOOTER_ID]); + $this->setDataProperty(self::DATA_POTION_ID, self::DATA_TYPE_SHORT, $this->getPotionId()); + } + + public function getPotionId() : int{ + return (int) $this->namedtag["PotionId"]; + } + + public function kill(){ + if($this->isAlive()) { + $color = Potion::getColor($this->getPotionId()); + $this->getLevel()->addParticle(new SpellParticle($this, $color[0], $color[1], $color[2])); + $players = $this->getViewers(); + foreach($players as $p) { + if($p->distance($this) <= 6) { + foreach(Potion::getEffectsById($this->getPotionId()) as $effect) { + $p->addEffect($effect); + } + } + } + + parent::kill(); + } + } + + public function onUpdate($currentTick){ + if($this->closed){ + return false; + } + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + $this->age++; + + if($this->age > 1200 or $this->isCollided){ + $this->kill(); + $this->close(); + $hasUpdate = true; + } + + $this->timings->stopTiming(); + + return $hasUpdate; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = ThrownPotion::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Vehicle.php b/src/devmine/server/calculations/entity/Vehicle.php new file mode 100644 index 0000000..3123cb9 --- /dev/null +++ b/src/devmine/server/calculations/entity/Vehicle.php @@ -0,0 +1,10 @@ +Profession)){ + $nbt->Profession = new ByteTag("Profession", mt_rand(0, 4)); + } + + parent::__construct($chunk, $nbt); + + $this->setDataProperty(self::DATA_PROFESSION_ID, self::DATA_TYPE_BYTE, $this->getProfession()); + } + + protected function initEntity(){ + parent::initEntity(); + if(!isset($this->namedtag->Profession)){ + $this->setProfession(self::PROFESSION_FARMER); + } + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Villager::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + /** + * Sets the villager profession + * + * @param int $profession + */ + public function setProfession(int $profession){ + $this->namedtag->Profession = new ByteTag("Profession", $profession); + } + + public function getProfession() : int{ + $pro = (int) $this->namedtag["Profession"]; + return min(4, max(0, $pro)); + } + + public function isBaby(){ + return $this->getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BABY); + } +} diff --git a/src/devmine/server/calculations/entity/WaterAnimal.php b/src/devmine/server/calculations/entity/WaterAnimal.php new file mode 100644 index 0000000..8b0e772 --- /dev/null +++ b/src/devmine/server/calculations/entity/WaterAnimal.php @@ -0,0 +1,12 @@ +getDataFlag(self::DATA_FLAGS, self::DATA_FLAG_BABY); + } +} diff --git a/src/devmine/server/calculations/entity/Witch.php b/src/devmine/server/calculations/entity/Witch.php new file mode 100644 index 0000000..5093699 --- /dev/null +++ b/src/devmine/server/calculations/entity/Witch.php @@ -0,0 +1,62 @@ +setMaxHealth(26); + parent::initEntity(); + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Witch::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + parent::spawnTo($player); + } + + public function getDrops(){ + //TODO + return []; + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/WitherSkeleton.php b/src/devmine/server/calculations/entity/WitherSkeleton.php new file mode 100644 index 0000000..bfc2293 --- /dev/null +++ b/src/devmine/server/calculations/entity/WitherSkeleton.php @@ -0,0 +1,46 @@ +eid = $this->getId(); + $pk->type = WitherSkeleton::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + + $pk = new MobEquipmentPacket(); + $pk->eid = $this->getId(); + $pk->item = new ItemItem(ItemItem::STONE_SWORD); + $pk->slot = 0; + $pk->selectedSlot = 0; + + $player->dataPacket($pk); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/Wolf.php b/src/devmine/server/calculations/entity/Wolf.php new file mode 100644 index 0000000..c4dbf8e --- /dev/null +++ b/src/devmine/server/calculations/entity/Wolf.php @@ -0,0 +1,57 @@ +eid = $this->getId(); + $pk->type = Wolf::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/calculations/entity/XPOrb.php b/src/devmine/server/calculations/entity/XPOrb.php new file mode 100644 index 0000000..345b050 --- /dev/null +++ b/src/devmine/server/calculations/entity/XPOrb.php @@ -0,0 +1,160 @@ +namedtag->Experience)){ + $this->experience = $this->namedtag["Experience"]; + }else $this->close(); + } + + public function onUpdate($currentTick){ + if($this->closed){ + return false; + } + + $tickDiff = $currentTick - $this->lastUpdate; + + $this->lastUpdate = $currentTick; + + $this->timings->startTiming(); + + $hasUpdate = $this->entityBaseTick($tickDiff); + + $this->age++; + + if($this->age > 1200){ + $this->kill(); + $this->close(); + $hasUpdate = true; + } + + $minDistance = PHP_INT_MAX; + $target = null; + foreach($this->getViewers() as $p){ + if(!$p->isSpectator() and $p->isAlive()){ + if(($dist = $p->distance($this)) < $minDistance and $dist < $this->range){ + $target = $p; + $minDistance = $dist; + } + } + } + + if($target !== null){ + $moveSpeed = 0.7; + $motX = ($target->getX() - $this->x) / 8; + $motY = ($target->getY() + $target->getEyeHeight() - $this->y) / 8; + $motZ = ($target->getZ() - $this->z) / 8; + $motSqrt = sqrt($motX * $motX + $motY * $motY + $motZ * $motZ); + $motC = 1 - $motSqrt; + + if($motC > 0){ + $motC *= $motC; + $this->motionX = $motX / $motSqrt * $motC * $moveSpeed; + $this->motionY = $motY / $motSqrt * $motC * $moveSpeed; + $this->motionZ = $motZ / $motSqrt * $motC * $moveSpeed; + } + + $this->motionY -= $this->gravity; + + if($this->checkObstruction($this->x, $this->y, $this->z)){ + $hasUpdate = true; + } + + if($this->isInsideOfSolid()){ + $this->setPosition($target); + } + + if($minDistance <= 1.3){ + if($this->getLevel()->getServer()->expEnabled and $target->canPickupXp()){ + $this->getLevel()->getServer()->getPluginManager()->callEvent($ev = new PlayerPickupExpOrbEvent($target, $this->getExperience())); + if(!$ev->isCancelled()){ + $this->kill(); + $this->close(); + if($this->getExperience() > 0){ + $this->level->addSound(new ExpPickupSound($target, mt_rand(0, 1000))); + $target->addXp($this->getExperience()); + $target->resetXpCooldown(); + } + } + } + } + } + + $this->move($this->motionX, $this->motionY, $this->motionZ); + + $this->updateMovement(); + + $this->timings->stopTiming(); + + return $hasUpdate or !$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + } + + public function canCollideWith(Entity $entity){ + return false; + } + + public function setExperience($exp){ + $this->experience = $exp; + } + + public function getExperience(){ + return $this->experience; + } + + public function spawnTo(Player $player){ + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_NO_AI, true); + $pk = new AddEntityPacket(); + $pk->type = XPOrb::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} diff --git a/src/devmine/server/calculations/entity/Zombie.php b/src/devmine/server/calculations/entity/Zombie.php new file mode 100644 index 0000000..128ea98 --- /dev/null +++ b/src/devmine/server/calculations/entity/Zombie.php @@ -0,0 +1,245 @@ +setMaxHealth(20); + parent::initEntity(); + } + + public function attack($damage, EntityDamageEvent $source){ + parent::attack($damage, $source); + + if($source instanceof EntityDamageByEntityEvent){ + $e = $source->getDamager(); + + $deltaX = $this->x - $e->x; + $deltaZ = $this->z - $e->z; + $this->knockBack($e, $damage, $deltaX / 100, $deltaZ / 100, $source->getKnockBack()); + } + } + + + private function generateRandomDirection(){ + return new Vector3(mt_rand(-1000, 1000) / 1000, 0, mt_rand(-1000, 1000) / 1000); + } + + /* + * 返回一个一位小数 + */ + private function toFloat($num){ + while(((abs($num) > 1) or (abs($num) < 0.1)) and (abs($num) > 0)) { + if(abs($num) > 1) $num /= 10; + if(abs($num) < 0.1) $num *= 10; + } + return $num; + } + + private function generateDirection(Vector3 $pos){ + return new Vector3($this->toFloat($pos->x - $this->x), 0, $this->toFloat($pos->z - $this->z)); + } + + private function getNearestPlayer(){ + $dis = PHP_INT_MAX; + $player = false; + foreach($this->getViewers() as $p){ + if($p->distance($this) < $dis){ + $dis = $p->distance($this); + $player = $p; + } + } + return (($dis <= $this->hate_r) ? $p : false); + } + + private function getVelY(){ + $expectedPos = (new Vector3($this->x + $this->moveDirection->x * $this->moveSpeed, $this->y + $this->motionY, $this->z + $this->moveDirection->z * $this->moveSpeed))->round(); + $block0 = $this->getLevel()->getBlock($expectedPos); + $block1 = $this->getLevel()->getBlock($expectedPos->add(0, 1, 0)); + if($block1->getId() != 0) return 1.2; + return 0; + } + + public function onUpdate($currentTick){ + if($this->closed !== false){ + return false; + } + + return parent::onUpdate($currentTick); + + $this->lastUpdate = $currentTick; + + $this->timings->startTiming(); + + $hasUpdate = parent::onUpdate($currentTick); + + if($this->isAlive()){ + /* Don't use time directly + * Instead, get remainder of current time divided by 24,000 + * This tells us the time of day, which is what we really need + */ + $timeOfDay = abs($this->getLevel()->getTime() % 24000); + if(0 < $timeOfDay and $timeOfDay < 13000) $this->setOnFire(2); //僵尸起火 + + $p = $this->getNearestPlayer();//找到最近的可以被仇恨的玩家 + if(!$p) { + $this->hated = false; + if(++$this->moveTicker >= 100) { + $this->moveDirection = $this->generateRandomDirection(); + $this->moveTicker = 0; + } + }else{ + $this->hated = $p; + if($p->distance($this) <= $this->fire_r) $p->setOnFire(2); //点燃玩家 + if(!$this->tempTicking){ + if(++$this->hateTicker >= 10 or $this->moveDirection == null) { //每0.5秒获取僵尸前进的新方向 + $this->moveDirection = $this->generateDirection($p); + $this->hateTicker = 0; + } + } + } + + + if($this->tempTicking) { //帮助僵尸寻找新的方向走出困境 + if(++$this->tempTicker >= 20) { + $this->tempTicking = false; + $this->tempTicker = 0; + } + } + + if($this->hated instanceof Player){ //攻击玩家 + if($this->hated->distance($this) < $this->attack_r) $this->hated->attack(2, new EntityDamageByEntityEvent($this, $this->hated, EntityDamageEvent::CAUSE_ENTITY_ATTACK, 2)); + } + + if($this->moveDirection != null){ + if($this->motionX ** 2 + $this->motionZ ** 2 <= $this->moveDirection->lengthSquared()){ + $motionY = $this->getVelY(); //僵尸运动计算 + if($motionY >= 0){ + $this->motionX = $this->moveDirection->x * $this->moveSpeed; + $this->motionZ = $this->moveDirection->z * $this->moveSpeed; + $this->motionY = $motionY; + }else{ + $this->moveDirection = $this->generateRandomDirection(); //生成随机运动方向 + $this->moveTicker = 0; + $this->tempTicking = true; + } + } + }else{ + $this->moveDirection = $this->generateRandomDirection(); + $this->moveTicker = 0; + } + + //var_dump($this->moveDirection,$this->motionX,$this->motionZ); + + $expectedPos = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ); + + if($this->motionY == 0) $this->motionY -= $this->gravity; //重力计算 + + $this->move($this->motionX, $this->motionY, $this->motionZ); + + if($expectedPos->distanceSquared($this) > 0){ + $this->moveDirection = $this->generateRandomDirection(); + } + + $friction = 1 - $this->drag; + + $this->motionX *= $friction; + //$this->motionY *= 1 - $this->drag; + $this->motionZ *= $friction; + + $f = sqrt(($this->motionX ** 2) + ($this->motionZ ** 2)); + $this->yaw = (-atan2($this->motionX, $this->motionZ) * 180 / M_PI); //视角计算 + //$this->pitch = (-atan2($f, $this->motionY) * 180 / M_PI); + + $this->updateMovement(); + } + + $this->timings->stopTiming(); + + return $hasUpdate or !$this->onGround or abs($this->motionX) > 0.00001 or abs($this->motionY) > 0.00001 or abs($this->motionZ) > 0.00001; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->eid = $this->getId(); + $pk->type = Zombie::NETWORK_ID; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } + + public function getDrops(){ + $lootingL = 0; + $cause = $this->lastDamageCause; + $drops = []; + if($cause instanceof EntityDamageByEntityEvent and $cause->getDamager() instanceof Player){ + $lootingL = $cause->getDamager()->getItemInHand()->getEnchantmentLevel(Enchantment::TYPE_WEAPON_LOOTING); + if(mt_rand(0, 199) < (5 + 2 * $lootingL)){ + switch(mt_rand(0, 3)){ + case 0: + $drops[] = ItemItem::get(ItemItem::IRON_INGOT, 0, 1); + break; + case 1: + $drops[] = ItemItem::get(ItemItem::CARROT, 0, 1); + break; + case 2: + $drops[] = ItemItem::get(ItemItem::POTATO, 0, 1); + break; + } + } + $count = mt_rand(0, 2 + $lootingL); + if($count > 0){ + $drops[] = ItemItem::get(ItemItem::ROTTEN_FLESH, 0, $count); + } + } + + return $drops; + } +} diff --git a/src/devmine/server/calculations/entity/ZombieVillager.php b/src/devmine/server/calculations/entity/ZombieVillager.php new file mode 100644 index 0000000..7b3f7e6 --- /dev/null +++ b/src/devmine/server/calculations/entity/ZombieVillager.php @@ -0,0 +1,58 @@ +setMaxHealth(20); + parent::initEntity(); + } + + public function getName() : string{ + return "Zombie Villager"; + } + + public function spawnTo(Player $player){ + $pk = new AddEntityPacket(); + $pk->type = ZombieVillager::NETWORK_ID; + $pk->eid = $this->getId(); + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $pk->metadata = $this->dataProperties; + $player->dataPacket($pk); + + parent::spawnTo($player); + } +} \ No newline at end of file diff --git a/src/devmine/server/commands/Command.php b/src/devmine/server/commands/Command.php index cc49e37..0b10b12 100644 --- a/src/devmine/server/commands/Command.php +++ b/src/devmine/server/commands/Command.php @@ -7,15 +7,21 @@ */ namespace devmine\server\commands; -use devmine\server\events\TextContainer; -use devmine\server\events\TimingsHandler; -use devmine\server\events\TranslationContainer; -use devmine\Server; +use devmine\events\TextContainer; +use devmine\events\TimingsHandler; +use devmine\events\TranslationContainer; +use devmine\creatures\player; +use devmine\server\server; use devmine\utilities\main\TextFormat; abstract class Command{ + /** @var \stdClass */ + private static $defaultDataTemplate = null; + /** @var string */ private $name; + /** @var \stdClass */ + protected $commandData = null; /** @var string */ private $nextLabel; @@ -58,16 +64,50 @@ abstract class Command{ * @param string[] $aliases */ public function __construct($name, $description = "", $usageMessage = null, array $aliases = []){ - $this->name = $name; - $this->nextLabel = $name; - $this->label = $name; - $this->description = $description; + $this->commandData = self::generateDefaultData(); + $this->name = $this->nextLabel = $this->label = $name; + $this->setDescription($description); $this->usageMessage = $usageMessage === null ? "/" . $name : $usageMessage; - $this->aliases = $aliases; - $this->activeAliases = (array) $aliases; + $this->setAliases($aliases); $this->timings = new TimingsHandler("** Command: " . $name); } + /** + * Returns an \stdClass containing command data + * + * @return \stdClass + */ + public function getDefaultCommandData() : \stdClass{ + return $this->commandData; + } + + /** + * Generates modified command data for the specified player + * for AvailableCommandsPacket. + * + * @param Player $player + * + * @return \stdClass|null + */ + public function generateCustomCommandData(Player $player){ + //TODO: fix command permission filtering on join + /*if(!$this->testPermission($player)){ + return null; + }*/ + $customData = clone $this->commandData; + $customData->aliases = $this->getAliases(); + /*foreach($customData->overloads as &$overload){ + if(($p = @$overload->DevMinePermission) !== null and !$player->hasPermission($p)){ + unset($overload); + } + }*/ + return $customData; + } + + public function getOverloads(): \stdClass{ + return $this->commandData->overloads; + } + /** * @param CommandSender $sender * @param string $commandLabel @@ -88,14 +128,19 @@ public function getName() : string{ * @return string */ public function getPermission(){ - return $this->permission; + return $this->commandData->DevMinePermission ?? null; } + /** * @param string|null $permission */ public function setPermission($permission){ - $this->permission = $permission; + if($permission !== null){ + $this->commandData->DevMinePermission = $permission; + }else{ + unset($this->commandData->DevMinePermission); + } } /** @@ -111,7 +156,7 @@ public function testPermission(CommandSender $target){ if($this->permissionMessage === null){ $target->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission")); }elseif($this->permissionMessage !== ""){ - $target->sendMessage(str_replace("", $this->permission, $this->permissionMessage)); + $target->sendMessage(str_replace("", $this->getPermission(), $this->permissionMessage)); } return false; @@ -123,11 +168,11 @@ public function testPermission(CommandSender $target){ * @return bool */ public function testPermissionSilent(CommandSender $target){ - if($this->permission === null or $this->permission === ""){ + if(($perm = $this->getPermission()) === null or $perm === ""){ return true; } - foreach(explode(";", $this->permission) as $permission){ + foreach(explode(";", $perm) as $permission){ if($target->hasPermission($permission)){ return true; } @@ -180,7 +225,7 @@ public function register(CommandMap $commandMap){ public function unregister(CommandMap $commandMap){ if($this->allowChangesFrom($commandMap)){ $this->commandMap = null; - $this->activeAliases = $this->aliases; + $this->activeAliases = $this->commandData->aliases; $this->label = $this->nextLabel; return true; @@ -223,7 +268,7 @@ public function getPermissionMessage(){ * @return string */ public function getDescription(){ - return $this->description; + return $this->commandData->description; } /** @@ -237,7 +282,7 @@ public function getUsage(){ * @param string[] $aliases */ public function setAliases(array $aliases){ - $this->aliases = $aliases; + $this->commandData->aliases = $aliases; if(!$this->isRegistered()){ $this->activeAliases = (array) $aliases; } @@ -247,7 +292,7 @@ public function setAliases(array $aliases){ * @param string $description */ public function setDescription($description){ - $this->description = $description; + $this->commandData->description = $description; } /** @@ -264,6 +309,13 @@ public function setUsage($usage){ $this->usageMessage = $usage; } + public static final function generateDefaultData() : \stdClass{ + if(self::$defaultDataTemplate === null){ + self::$defaultDataTemplate = json_decode(file_get_contents(Server::getInstance()->getFilePath() . "src/devmine/server/resources/command_default.json")); + } + return clone self::$defaultDataTemplate; + } + /** * @param CommandSender $source * @param string $message diff --git a/src/devmine/server/commands/CommandReader.php b/src/devmine/server/commands/CommandReader.php index fb1f246..012dc41 100644 --- a/src/devmine/server/commands/CommandReader.php +++ b/src/devmine/server/commands/CommandReader.php @@ -4,7 +4,7 @@ namespace devmine\server\commands; -use devmine\Thread; +use devmine\server\Thread; use devmine\utilities\main\MainLogger; use devmine\utilities\main\Utils; @@ -68,14 +68,14 @@ public function getLine(){ public function quit(){ $this->shutdown(); // Windows sucks - if(Utils::getOS() != "win"){ + if(Utils::getOS() !== "win"){ parent::quit(); } } public function run(){ if($this->readline){ - readline_callback_handler_install("devmine> ", [$this, "readline_callback"]); + readline_callback_handler_install("DevMine> ", [$this, "readline_callback"]); $this->logger->setConsoleCallback("readline_redisplay"); } diff --git a/src/devmine/server/commands/CommandSender.php b/src/devmine/server/commands/CommandSender.php index 2630656..c513a03 100644 --- a/src/devmine/server/commands/CommandSender.php +++ b/src/devmine/server/commands/CommandSender.php @@ -4,7 +4,7 @@ namespace devmine\server\commands; -use devmine\server\permissions\Permissible; +use devmine\server\perms\Permissible; interface CommandSender extends Permissible{ @@ -14,7 +14,7 @@ interface CommandSender extends Permissible{ public function sendMessage($message); /** - * @return \devmine\Server + * @return \devmine\server\server */ public function getServer(); diff --git a/src/devmine/server/commands/ConsoleCommandSender.php b/src/devmine/server/commands/ConsoleCommandSender.php index 92abdd1..a707d96 100644 --- a/src/devmine/server/commands/ConsoleCommandSender.php +++ b/src/devmine/server/commands/ConsoleCommandSender.php @@ -4,11 +4,11 @@ namespace devmine\server\commands; -use devmine\server\events\TextContainer; -use devmine\server\permissions\PermissibleBase; -use devmine\server\permissions\PermissionAttachment; -use devmine\pluginfeatures\Plugin; -use devmine\Server; +use devmine\events\TextContainer; +use devmine\server\perms\PermissibleBase; +use devmine\server\perms\PermissionAttachment; +use devmine\consumer\plugin\Plugin; +use devmine\server\server; use devmine\utilities\main\MainLogger; class ConsoleCommandSender implements CommandSender{ @@ -20,7 +20,7 @@ public function __construct(){ } /** - * @param \devmine\server\permissions\Permission|string $name + * @param \devmine\server\perms\Permission|string $name * * @return bool */ @@ -29,7 +29,7 @@ public function isPermissionSet($name){ } /** - * @param \devmine\server\permissions\Permission|string $name + * @param \devmine\server\perms\Permission|string $name * * @return bool */ @@ -42,7 +42,7 @@ public function hasPermission($name){ * @param string $name * @param bool $value * - * @return \devmine\server\permissions\PermissionAttachment + * @return \devmine\server\perms\PermissionAttachment */ public function addAttachment(Plugin $plugin, $name = null, $value = null){ return $this->perm->addAttachment($plugin, $name, $value); @@ -62,7 +62,7 @@ public function recalculatePermissions(){ } /** - * @return \devmine\server\permissions\PermissionAttachmentInfo[] + * @return \devmine\server\perms\PermissionAttachmentInfo[] */ public function getEffectivePermissions(){ return $this->perm->getEffectivePermissions(); @@ -76,7 +76,7 @@ public function isPlayer(){ } /** - * @return \devmine\Server + * @return \devmine\server\server */ public function getServer(){ return Server::getInstance(); diff --git a/src/devmine/server/commands/FormattedCommandAlias.php b/src/devmine/server/commands/FormattedCommandAlias.php index 6359fd5..b6f2c30 100644 --- a/src/devmine/server/commands/FormattedCommandAlias.php +++ b/src/devmine/server/commands/FormattedCommandAlias.php @@ -4,8 +4,8 @@ namespace devmine\server\commands; -use devmine\server\events\TranslationContainer; -use devmine\Server; +use devmine\events\TranslationContainer; +use devmine\server\server; use devmine\utilities\main\MainLogger; use devmine\utilities\main\TextFormat; diff --git a/src/devmine/server/commands/PluginCommand.php b/src/devmine/server/commands/PluginCommand.php index 9428665..a5bb8fb 100644 --- a/src/devmine/server/commands/PluginCommand.php +++ b/src/devmine/server/commands/PluginCommand.php @@ -4,8 +4,8 @@ namespace devmine\server\commands; -use devmine\server\events\TranslationContainer; -use devmine\pluginfeatures\Plugin; +use devmine\events\TranslationContainer; +use devmine\consumer\plugin\Plugin; class PluginCommand extends Command implements PluginIdentifiableCommand{ diff --git a/src/devmine/server/commands/PluginIdentifiableCommand.php b/src/devmine/server/commands/PluginIdentifiableCommand.php index c8ecc3b..60b100f 100644 --- a/src/devmine/server/commands/PluginIdentifiableCommand.php +++ b/src/devmine/server/commands/PluginIdentifiableCommand.php @@ -7,7 +7,7 @@ interface PluginIdentifiableCommand{ /** - * @return \devmine\pluginfeatures\Plugin + * @return \devmine\consumer\plugin\Plugin */ public function getPlugin(); } diff --git a/src/devmine/server/commands/RemoteConsoleCommandSender.php b/src/devmine/server/commands/RemoteConsoleCommandSender.php index 9a28e26..17a9f2a 100644 --- a/src/devmine/server/commands/RemoteConsoleCommandSender.php +++ b/src/devmine/server/commands/RemoteConsoleCommandSender.php @@ -5,7 +5,7 @@ namespace devmine\server\commands; -use devmine\server\events\TextContainer; +use devmine\events\TextContainer; class RemoteConsoleCommandSender extends ConsoleCommandSender{ diff --git a/src/devmine/server/commands/SimpleCommandMap.php b/src/devmine/server/commands/SimpleCommandMap.php index fa41646..7bac19f 100644 --- a/src/devmine/server/commands/SimpleCommandMap.php +++ b/src/devmine/server/commands/SimpleCommandMap.php @@ -4,12 +4,12 @@ namespace devmine\server\commands; +use devmine\server\commands\defaults\BanCidByNameCommand; +use devmine\server\commands\defaults\BanCidCommand; use devmine\server\commands\defaults\BanCommand; +use devmine\server\commands\defaults\BanIpByNameCommand; use devmine\server\commands\defaults\BanIpCommand; use devmine\server\commands\defaults\BanListCommand; -use devmine\server\commands\defaults\BiomeCommand; -use devmine\server\commands\defaults\CaveCommand; -use devmine\server\commands\defaults\ChunkInfoCommand; use devmine\server\commands\defaults\DefaultGamemodeCommand; use devmine\server\commands\defaults\DeopCommand; use devmine\server\commands\defaults\DifficultyCommand; @@ -23,11 +23,10 @@ use devmine\server\commands\defaults\KickCommand; use devmine\server\commands\defaults\KillCommand; use devmine\server\commands\defaults\ListCommand; -use devmine\server\commands\defaults\LoadPluginCommand; -use devmine\server\commands\defaults\LvdatCommand; use devmine\server\commands\defaults\MeCommand; use devmine\server\commands\defaults\OpCommand; use devmine\server\commands\defaults\PardonCommand; +use devmine\server\commands\defaults\PardonCidCommand; use devmine\server\commands\defaults\PardonIpCommand; use devmine\server\commands\defaults\ParticleCommand; use devmine\server\commands\defaults\PluginsCommand; @@ -49,107 +48,90 @@ use devmine\server\commands\defaults\TimingsCommand; use devmine\server\commands\defaults\VanillaCommand; use devmine\server\commands\defaults\VersionCommand; +use devmine\server\commands\defaults\WeatherCommand; use devmine\server\commands\defaults\WhitelistCommand; use devmine\server\commands\defaults\XpCommand; -use devmine\server\commands\defaults\FillCommand; -use devmine\server\events\TranslationContainer; -use devmine\Player; -use devmine\Server; +use devmine\server\commands\defaults\MakePharCommand; + +use devmine\events\TranslationContainer; +use devmine\creatures\player; +use devmine\server\server; use devmine\utilities\main\MainLogger; use devmine\utilities\main\TextFormat; -use devmine\server\commands\defaults\MakeServerCommand; -use devmine\server\commands\defaults\ExtractPluginCommand; -use devmine\server\commands\defaults\ExtractPharCommand; -use devmine\server\commands\defaults\MakePluginCommand; -use devmine\server\commands\defaults\BancidbynameCommand; -use devmine\server\commands\defaults\BanipbynameCommand; -use devmine\server\commands\defaults\BanCidCommand; -use devmine\server\commands\defaults\PardonCidCommand; -use devmine\server\commands\defaults\WeatherCommand; - class SimpleCommandMap implements CommandMap{ /** * @var Command[] */ protected $knownCommands = []; + + /** + * @var bool[] + */ + protected $commandConfig = []; /** @var Server */ private $server; public function __construct(Server $server){ $this->server = $server; + /** @var bool[] */ + $this->commandConfig = $this->server->getProperty("commands"); $this->setDefaultCommands(); } private function setDefaultCommands(){ - $this->register("devmine", new WeatherCommand("weather")); - - $this->register("devmine", new BanCidCommand("bancid")); - $this->register("devmine", new PardonCidCommand("pardoncid")); - $this->register("devmine", new BancidbynameCommand("bancidbyname")); - $this->register("devmine", new BanipbynameCommand("banipbyname")); - - $this->register("devmine", new ExtractPharCommand("extractphar")); - $this->register("devmine", new ExtractPluginCommand("extractplugin")); - $this->register("devmine", new MakePluginCommand("makeplugin")); - $this->register("devmine", new MakeServerCommand("ms")); - //$this->register("devmine", new MakeServerCommand("makeserver")); - $this->register("devmine", new ExtractPluginCommand("ep")); - $this->register("devmine", new MakePluginCommand("mp")); - - $this->register("devmine", new LoadPluginCommand("loadplugin")); - - $this->register("devmine", new LvdatCommand("lvdat")); - $this->register("devmine", new BiomeCommand("biome")); - $this->register("devmine", new CaveCommand("cave")); - $this->register("devmine", new ChunkInfoCommand("chunkinfo")); - - $this->register("devmine", new VersionCommand("version")); - $this->register("devmine", new FillCommand("fill")); - $this->register("devmine", new PluginsCommand("plugins")); - $this->register("devmine", new SeedCommand("seed")); - $this->register("devmine", new HelpCommand("help")); - $this->register("devmine", new StopCommand("stop")); - $this->register("devmine", new TellCommand("tell")); - $this->register("devmine", new DefaultGamemodeCommand("defaultgamemode")); - $this->register("devmine", new BanCommand("ban")); - $this->register("devmine", new BanIpCommand("ban-ip")); - $this->register("devmine", new BanListCommand("banlist")); - $this->register("devmine", new PardonCommand("pardon")); - $this->register("devmine", new PardonIpCommand("pardon-ip")); - $this->register("devmine", new SayCommand("say")); - $this->register("devmine", new MeCommand("me")); - $this->register("devmine", new ListCommand("list")); - $this->register("devmine", new DifficultyCommand("difficulty")); - $this->register("devmine", new KickCommand("kick")); - $this->register("devmine", new OpCommand("op")); - $this->register("devmine", new DeopCommand("deop")); - $this->register("devmine", new WhitelistCommand("whitelist")); - $this->register("devmine", new SaveOnCommand("save-on")); - $this->register("devmine", new SaveOffCommand("save-off")); - $this->register("devmine", new SaveCommand("save-all")); - $this->register("devmine", new GiveCommand("give")); - $this->register("devmine", new EffectCommand("effect")); - $this->register("devmine", new EnchantCommand("enchant")); - $this->register("devmine", new ParticleCommand("particle")); - $this->register("devmine", new GamemodeCommand("gamemode")); - $this->register("devmine", new KillCommand("kill")); - $this->register("devmine", new SpawnpointCommand("spawnpoint")); - $this->register("devmine", new SetWorldSpawnCommand("setworldspawn")); - $this->register("devmine", new SummonCommand("summon")); - $this->register("devmine", new TeleportCommand("tp")); - $this->register("devmine", new TimeCommand("time")); - $this->register("devmine", new TimingsCommand("timings")); - $this->register("devmine", new ReloadCommand("reload")); - $this->register("devmine", new XpCommand("xp")); - $this->register("devmine", new SetBlockCommand("setblock")); + $this->register("DevMine", new WeatherCommand("weather")); + + $this->register("DevMine", new BanCidCommand("bancid")); + $this->register("DevMine", new PardonCidCommand("pardoncid")); + $this->register("DevMine", new BanCidByNameCommand("bancidbyname")); + $this->register("DevMine", new BanIpByNameCommand("banipbyname")); + + $this->register("DevMine", new VersionCommand("version")); + $this->register("DevMine", new PluginsCommand("plugins")); + $this->register("DevMine", new SeedCommand("seed")); + $this->register("DevMine", new HelpCommand("help"), null, true); + $this->register("DevMine", new StopCommand("stop"), null, true); + $this->register("DevMine", new TellCommand("tell")); + $this->register("DevMine", new DefaultGamemodeCommand("defaultgamemode")); + $this->register("DevMine", new BanCommand("ban")); + $this->register("DevMine", new BanIpCommand("ban-ip")); + $this->register("DevMine", new BanListCommand("banlist")); + $this->register("DevMine", new PardonCommand("pardon")); + $this->register("DevMine", new PardonIpCommand("pardon-ip")); + $this->register("DevMine", new SayCommand("say")); + $this->register("DevMine", new MeCommand("me")); + $this->register("DevMine", new ListCommand("list")); + $this->register("DevMine", new DifficultyCommand("difficulty")); + $this->register("DevMine", new KickCommand("kick")); + $this->register("DevMine", new OpCommand("op")); + $this->register("DevMine", new DeopCommand("deop")); + $this->register("DevMine", new WhitelistCommand("whitelist")); + $this->register("DevMine", new SaveOnCommand("save-on")); + $this->register("DevMine", new SaveOffCommand("save-off")); + $this->register("DevMine", new SaveCommand("save-all"), null, true); + $this->register("DevMine", new GiveCommand("give")); + $this->register("DevMine", new EffectCommand("effect")); + $this->register("DevMine", new EnchantCommand("enchant")); + $this->register("DevMine", new ParticleCommand("particle")); + $this->register("DevMine", new GamemodeCommand("gamemode")); + $this->register("DevMine", new KillCommand("kill")); + $this->register("DevMine", new SpawnpointCommand("spawnpoint")); + $this->register("DevMine", new SetWorldSpawnCommand("setworldspawn")); + $this->register("DevMine", new SummonCommand("summon")); + $this->register("DevMine", new TeleportCommand("tp")); + $this->register("DevMine", new TimeCommand("time")); + $this->register("DevMine", new TimingsCommand("timings")); + $this->register("DevMine", new ReloadCommand("reload"), null, true); + $this->register("DevMine", new XpCommand("xp")); + $this->register("DevMine", new SetBlockCommand("setblock")); if($this->server->getProperty("debug.commands", false)){ - $this->register("devmine", new StatusCommand("status")); - $this->register("devmine", new GarbageCollectorCommand("gc")); - $this->register("devmine", new DumpMemoryCommand("dumpmemory")); + $this->register("DevMine", new StatusCommand("status"), null, true); + $this->register("DevMine", new GarbageCollectorCommand("gc"), null, true); + $this->register("DevMine", new DumpMemoryCommand("dumpmemory"), null, true); } } @@ -160,11 +142,16 @@ public function registerAll($fallbackPrefix, array $commands){ } } - public function register($fallbackPrefix, Command $command, $label = null){ + public function register($fallbackPrefix, Command $command, $label = null, $overrideConfig = false){ if($label === null){ $label = $command->getName(); } $label = strtolower(trim($label)); + + //Check if command was disabled in config and for override + if(!(($this->commandConfig[$label] ?? $this->commandConfig["default"] ?? true) or $overrideConfig)){ + return false; + } $fallbackPrefix = strtolower(trim($fallbackPrefix)); $registered = $this->registerAlias($command, false, $fallbackPrefix, $label); @@ -264,7 +251,7 @@ public function dispatch(CommandSender $sender, $commandLine){ } }catch(\Throwable $e){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.exception")); - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("devmine.command.exception", [$commandLine, (string) $target, $e->getMessage()])); + $this->server->getLogger()->critical($this->server->getLanguage()->translateString("DevMine.command.exception", [$commandLine, (string) $target, $e->getMessage()])); $logger = $sender->getServer()->getLogger(); if($logger instanceof MainLogger){ $logger->logException($e); @@ -307,7 +294,7 @@ public function registerServerAliases(){ foreach($values as $alias => $commandStrings){ if(strpos($alias, ":") !== false or strpos($alias, " ") !== false){ - $this->server->getLogger()->warning($this->server->getLanguage()->translateString("devmine.command.alias.illegal", [$alias])); + $this->server->getLogger()->warning($this->server->getLanguage()->translateString("DevMine.command.alias.illegal", [$alias])); continue; } @@ -329,7 +316,7 @@ public function registerServerAliases(){ } if(strlen($bad) > 0){ - $this->server->getLogger()->warning($this->server->getLanguage()->translateString("devmine.command.alias.notFound", [$alias, $bad])); + $this->server->getLogger()->warning($this->server->getLanguage()->translateString("DevMine.command.alias.notFound", [$alias, $bad])); continue; } diff --git a/src/devmine/server/commands/defaults/BanCidCommand.php b/src/devmine/server/commands/defaults/BanCidCommand.php index 6828db2..326980b 100644 --- a/src/devmine/server/commands/defaults/BanCidCommand.php +++ b/src/devmine/server/commands/defaults/BanCidCommand.php @@ -1,10 +1,30 @@ setPermission("devmine.command.bancid"); + $this->setPermission("DevMine.command.bancid"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/BanCommand.php b/src/devmine/server/commands/defaults/BanCommand.php index 17afdc0..6e795fd 100644 --- a/src/devmine/server/commands/defaults/BanCommand.php +++ b/src/devmine/server/commands/defaults/BanCommand.php @@ -6,8 +6,8 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; class BanCommand extends VanillaCommand{ @@ -15,10 +15,10 @@ class BanCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.ban.player.description", + "%DevMine.command.ban.player.description", "%commands.ban.usage" ); - $this->setPermission("devmine.command.ban.player"); + $this->setPermission("DevMine.command.ban.player"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -36,14 +36,15 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ if(isset($args[0]) and isset($args[1])){ $reason = $args[0]; if($args[1] != null and is_numeric($args[1])){ - $until = $args[1] * 86400 + time(); + $until = new \DateTime('@' . ($args[1] * 86400 + time())); }else{ $until = null; } $sender->getServer()->getNameBans()->addBan($name, $reason, $until, $sender->getName()); + }else{ + $sender->getServer()->getNameBans()->addBan($name, $reason = implode(" ", $args), null, $sender->getName()); } - $sender->getServer()->getNameBans()->addBan($name, $reason = implode(" ", $args), null, $sender->getName()); if(($player = $sender->getServer()->getPlayerExact($name)) instanceof Player){ @@ -54,4 +55,4 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ return true; } -} \ No newline at end of file +} diff --git a/src/devmine/server/commands/defaults/BanIpCommand.php b/src/devmine/server/commands/defaults/BanIpCommand.php index b1c5f16..914b202 100644 --- a/src/devmine/server/commands/defaults/BanIpCommand.php +++ b/src/devmine/server/commands/defaults/BanIpCommand.php @@ -6,8 +6,8 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; class BanIpCommand extends VanillaCommand{ @@ -15,10 +15,10 @@ class BanIpCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.ban.ip.description", + "%DevMine.command.ban.ip.description", "%commands.banip.usage" ); - $this->setPermission("devmine.command.ban.ip"); + $this->setPermission("DevMine.command.ban.ip"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/BanListCommand.php b/src/devmine/server/commands/defaults/BanListCommand.php index de3979a..92b2a85 100644 --- a/src/devmine/server/commands/defaults/BanListCommand.php +++ b/src/devmine/server/commands/defaults/BanListCommand.php @@ -5,8 +5,8 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Server; +use devmine\events\TranslationContainer; +use devmine\server\server; class BanListCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class BanListCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.banlist.description", + "%DevMine.command.banlist.description", "%commands.banlist.usage" ); - $this->setPermission("devmine.command.ban.list"); + $this->setPermission("DevMine.command.ban.list"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/BancidbynameCommand.php b/src/devmine/server/commands/defaults/BancidbynameCommand.php index 5bd1b18..60836f6 100644 --- a/src/devmine/server/commands/defaults/BancidbynameCommand.php +++ b/src/devmine/server/commands/defaults/BancidbynameCommand.php @@ -1,21 +1,41 @@ setPermission("devmine.command.bancidbyname"); + $this->setPermission("DevMine.command.bancidbyname"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/BanipbynameCommand.php b/src/devmine/server/commands/defaults/BanipbynameCommand.php index 0dc4908..684dbbc 100644 --- a/src/devmine/server/commands/defaults/BanipbynameCommand.php +++ b/src/devmine/server/commands/defaults/BanipbynameCommand.php @@ -1,21 +1,41 @@ setPermission("devmine.command.banipbyname"); + $this->setPermission("DevMine.command.banipbyname"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/BiomeCommand.php b/src/devmine/server/commands/defaults/BiomeCommand.php deleted file mode 100644 index d619a97..0000000 --- a/src/devmine/server/commands/defaults/BiomeCommand.php +++ /dev/null @@ -1,117 +0,0 @@ -" - ); - $this->setPermission("devmine.command.biome"); - } - - public function execute(CommandSender $sender, $currentAlias, array $args){ - if(!$this->testPermission($sender)){ - return true; - } - - if(count($args) === 0){ - $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); - return false; - } - - if($sender instanceof Player){ - if($args[0] == "set"){ - $biome = isset($args[1]) ? $args[1] : 1;//默认改成草原 - if(isset($sender->selectedPos[0]) and isset($sender->selectedPos[1])){ - if(is_numeric($biome) === false){ - $sender->sendMessage(TextFormat::RED . new TranslationContainer("devmine.command.biome.wrongBio")); - return false; - } - $biome = (int) $biome; - if($sender->selectedLev[0] !== $sender->selectedLev[1]){ - $sender->sendMessage(TextFormat::RED . new TranslationContainer("devmine.command.biome.wrongLev")); - return false; - } - $x1 = min($sender->selectedPos[0][0], $sender->selectedPos[1][0]); - $z1 = min($sender->selectedPos[0][1], $sender->selectedPos[1][1]); - $x2 = max($sender->selectedPos[0][0], $sender->selectedPos[1][0]); - $z2 = max($sender->selectedPos[0][1], $sender->selectedPos[1][1]); - $level = $sender->selectedLev[0]; - for($x = $x1; $x <= $x2; $x++){ - for($z = $z1; $z <= $z2; $z++){ - $level->setBiomeId($x, $z, $biome); - } - } - $sender->sendMessage(new TranslationContainer("devmine.command.biome.set", [$biome])); - }else{ - $sender->sendMessage(new TranslationContainer("devmine.command.biome.noPos")); - } - }elseif($args[0] == "color"){ - $color = isset($args[1]) ? $args[1] : "146,188,89";//1=草原("146,188,89"),2=沙漠(251,183,19)"130,180,147" - $a = explode(",", $color); - //var_dump($a); - if(count($a) != 3){ - $sender->sendMessage(TextFormat::RED . new TranslationContainer("devmine.command.biome.wrongCol")); - return false; - } - if(isset($sender->selectedPos[0]) and isset($sender->selectedPos[1])){ - if($sender->selectedLev[0] !== $sender->selectedLev[1]){ - $sender->sendMessage(TextFormat::RED . new TranslationContainer("devmine.command.biome.wrongLev")); - return false; - } - $x1 = min($sender->selectedPos[0][0], $sender->selectedPos[1][0]); - $z1 = min($sender->selectedPos[0][1], $sender->selectedPos[1][1]); - $x2 = max($sender->selectedPos[0][0], $sender->selectedPos[1][0]); - $z2 = max($sender->selectedPos[0][1], $sender->selectedPos[1][1]); - for($x = $x1; $x <= $x2; $x++){ - for($z = $z1; $z <= $z2; $z++){ - $level = $sender->getLevel(); - $level->setBiomeColor($x, $z, $a[0], $a[1], $a[2]); - } - } - //$sender->selectedPos = array(); - $sender->sendMessage(new TranslationContainer("devmine.command.biome.color", [$a[0], $a[1], $a[2]])); - }else{ - $sender->sendMessage(new TranslationContainer("devmine.command.biome.noPos")); - } - }elseif($args[0] == "pos1"){ - $x = floor($sender->getX()); - $z = floor($sender->getZ()); - $sender->selectedLev[0] = $sender->getlevel(); - $sender->selectedPos[0][0] = $x; - $sender->selectedPos[0][1] = $z; - $sender->sendMessage(new TranslationContainer("devmine.command.biome.posset", [$sender->selectedLev[0]->getName(), $x, $z, "1"])); - }elseif($args[0] == "pos2"){ - $x = floor($sender->getX()); - $z = floor($sender->getZ()); - $sender->selectedLev[1] = $sender->getlevel(); - $sender->selectedPos[1][0] = $x; - $sender->selectedPos[1][1] = $z; - $sender->sendMessage(new TranslationContainer("devmine.command.biome.posset", [$sender->selectedLev[1]->getname(), $x, $z, "2"])); - }elseif($args[0] == "get"){ - $x = floor($sender->getX()); - $z = floor($sender->getZ()); - $biome = $sender->getLevel()->getBiomeId($x, $z); - $color = $sender->getLevel()->getBiomeColor($x, $z); - $sender->sendMessage(new TranslationContainer("devmine.command.biome.get", [$biome, $color[0], $color[1], $color[2]])); - }else{ - $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); - return true; - } - }else{ - $sender->sendMessage(new TranslationContainer("commands.generic.runingame")); - return false; - } - } -} diff --git a/src/devmine/server/commands/defaults/CaveCommand.php b/src/devmine/server/commands/defaults/CaveCommand.php deleted file mode 100644 index 71159cf..0000000 --- a/src/devmine/server/commands/defaults/CaveCommand.php +++ /dev/null @@ -1,335 +0,0 @@ -setPermission("devmine.command.cave"); - } - - public function execute(CommandSender $sender, $commandLabel, array $args){ - if(!$this->testPermission($sender)){ - return true; - } - - if($sender instanceof Player and $args[0] == "getmypos"){ - $sender->sendMessage("You position ({$sender->getX()}, {$sender->getY()}, {$sender->getZ()}, {$sender->getLevel()->getFolderName()})"); - return true; - } - - //0:旋转角度 1:洞穴长度 2:分叉数 3:洞穴强度 - if(count($args) != 8){ - $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); - - return false; - } - $level = $sender->getServer()->getLevelByName($args[7]); - if(!$level instanceof Level){ - $sender->sendMessage(TextFormat::RED ."Wrong LevelName"); - return false; - } - $pos = new Position($args[4], $args[5], $args[6], $level); - $caves[0] = isset($args[0]) ? $args[0] : mt_rand(1, 360); - $caves[1] = isset($args[1]) ? $args[1] : mt_rand(10, 300); - $caves[2] = isset($args[2]) ? $args[2] : mt_rand(1, 6); - $caves[4] = isset($args[3]) ? $args[3] : mt_rand(1, 10); - $caves[3] = [false, true, true]; - $sender->sendMessage(new TranslationContainer("commands.cave.info", [$caves[0], $caves[1], $caves[2], $caves[3]])); - $sender->sendMessage("[Caves] " . TextFormat::YELLOW . "%commands.cave.start"); - $sender->sendMessage($pos->x . " " . $pos->y . " " . $pos->z); - $this->caves($pos, $caves); - $sender->sendMessage("[Caves] " . TextFormat::GREEN . "%commands.cave.success"); - return true; - } - - public function chu($v1, $v2){ - if($v2 == 0) return 0; - return $v1 / $v2; - } - - public function getDirectionVector($yaw, $pitch){ - $y = -\sin(\deg2rad($pitch)); - $xz = \cos(\deg2rad($pitch)); - $x = -$xz * \sin(\deg2rad($yaw)); - $z = $xz * \cos(\deg2rad($yaw)); - - $temporalVector = new Vector3($x, $y, $z); - return $temporalVector->normalize(); - } - - public function caves(Position $pos, $cave, $tt = false){ - $x = $pos->x; - $y = $pos->y; - $z = $pos->z; - $level = $pos->getLevel(); - $ls = $cave[1]; //长度 - $cv = $cave[2]; //分叉数 - $lofs = $ls / $cave[2]; - $ls2 = $lofs; - $yaw = $cave[0]; - if($cave[0] >= 0 || $cave[0] < 0){ - }else{ - $yaw = mt_rand(0, 100) * 72; - } - $pitch = -45; - //$pi = M_PI / 180; - $s1 = [$x, $y, $z]; - $s2 = [$x, $y, $z]; - //$i = -10 + mt_rand(0, 100) * 0.2; - //$i = mt_rand(8, 25) / 10; - $i = 1; - for($u = 0; $u <= $ls; $u += $i){ - if($pitch > 12) $pitch = -45; - $pitch += 5 + mt_rand(0, 5); - $pos->getLevel()->getServer()->getLogger()->debug("[Caves] ".TextFormat::YELLOW . "yaw: $yaw pitch: $pitch"); - if($tt) $pitch = mt_rand(0, 100) * 0.05; - //$s2[0] = $s1[0] -\sin($yaw / 180 * M_PI) * \cos($pitch / 180 * M_PI) * $i; - //$s2[1] = $s1[1] +\sin($pitch / 180 * M_PI) * $i; - //$s2[2] = $s1[2] + \cos($yaw / 180 * M_PI) * \cos($pitch / 180 * M_PI) * $i; - - #echo "s1: "; - //var_dump($s1); - $see = $this->getDirectionVector($yaw, $pitch); - $s2[0] = $s1[0] + $see->x * $i; - $s2[1] = $s1[1] - $see->y * $i; - $s2[2] = $s1[2] + $see->z * $i; - //echo "s2: "; - //var_dump($s2); - if($s2[1] < 10){ - $s2[1] = 10 + mt_rand(0, 10); - } - if($u > $lofs){ - $cv--; - if($cave[3][1] === false) $cv = 0; - $lofs += $ls2; - $newPos = new Position($s2[0], $s2[1], $s2[2], $level); - $this->caves($newPos, [$yaw + 90 * (round(mt_rand(0, 100) / 100) * 2 - 1), $ls - $u, $cv, [false, $cave[3][1], $cave[3][2]], 0], $tt); - } - - //$exPos = new Position($s2[0], $s2[1], $s2[2], $level); - //$this->explodeBlocks($exPos, mt_rand(2, 4), mt_rand(1, 4)); - - if(mt_rand(0, 100) > 80){ - $add = mt_rand(-10, 10); - }else{ - $add = mt_rand(-45, 45); - } - $yaw = $yaw + $add; - $yaw = $yaw % 360; - $yaw = $yaw >= 0 ? $yaw : 360 + $yaw; - - //$i = 5 + mt_rand(0, 100) * 0.05; - $x = $s1[0]; - $y = $s1[1]; - $z = $s1[2]; - $x2 = $s2[0]; - $y2 = $s2[1]; - $z2 = $s2[2]; - $l = max(abs($x - $x2), abs($y - $y2), abs($z - $z2)); - for($m = 0; $m <= $l; $m++){ - //$v = $level->getBlock(new Vector3(round($this->chu($x + $m, $l * ($x2 - $x))), round($y + $this->chu($m, $l * ($y2 - $y))), round($z + $this->chu($m, $l * ($z2 - $z)))))->getId(); - //if ($v != 0 and $v != 95) - $liu = mt_rand(0, 200) == 100; - $this->fdx(round($x + $this->chu($m, $l * ($x2 - $x))), round($y + $this->chu($m, $l * ($y2 - $y))), round($z + $this->chu($m, $l * ($z2 - $z))), $level, $liu); - } - $s1 = [$s2[0], $s2[1], $s2[2]]; - } - if(mt_rand(0, 10) >= 5 and $s2[1] <= 40){ - $this->lavaSpawn($level, $s2[0], $s2[1], $s2[2]); - } - /* - if ($cave[3][0]) { - $l = $cave[4]; - $x = $s2[0]; - $y = $s2[1]; - $z = $s2[2]; - for ($i = -$l; $i <= $l; $i += 2) { - for ($j = -$l; $j <= $l; $j += 2) { - if ($i * $i + $j * $j <= pow($l - 0.3 * $l * mt_rand(0, 1000) / 1000, 2)) { - if ($level->getBlock(new Vector3($x + $i, $y - 1, $z + $j))->getId() != 0) { - $this->fdx($x + $i, $y - 1 + 2 * mt_rand(0, 1000) / 1000, $z + $j, $level); - } - } - if ($i * $i + $j * $j <= pow($l - 0.5 * $l * mt_rand(0, 1000) / 1000, 2)) { - if ($level->getBlock(new Vector3($x + $i, $y + 3, $z + $j))->getId() != 0) { - $this->fdx($x + $i, $y + 3 + 2 * mt_rand(0, 1000) / 1000, $z + $j, $level); - } - } - } - } - - //if ($level->getBlock(new Vector3($s2[0], $s2[1] - 4, $s2[2]))->getId() != 0 && $cave[3][2] && mt_rand(0, 100) / 100 > 0.5) $this->tiankengy($level, $s2[0], $s2[1], $s2[2], $l * 0.6, 11, 0); - } else if ($cave[3][2]) { - $l = $cave[4]; - if ($pitch < -10 && $pitch > -45 && $level->getBlock(new Vector3($s2[0], $s2[1] - 3, $s2[2]))->getId() != 0) $this->tiankengy($level, $s2[0], $s2[1], $s2[2], $l / 2, 11, 0); - }*/ - //echo "\n 矿洞生成完成\n"; - - } - - public function lavaSpawn(Level $level, $x, $y, $z){ - $level->getServer()->getLogger()->info("生成岩浆中 " . "floor($x)" . ", " . "floor($y)" . ", " . floor($z)); - for($xx = $x - 20; $xx <= $x + 20; $xx++){ - for($zz = $z - 20; $zz <= $z + 20; $zz++){ - for($yy = $y; $yy > $y - 4; $yy--){ - $id = $level->getBlockIdAt($xx, $yy, $zz); - if($id == 0){ - $level->setBlockIdAt($xx, $yy, $zz, 10); - $level->setBlockDataAt($xx, $yy, $zz, 0); - } - } - } - } - $level->setBlock(new Vector3($x, $y, $z), new Lava()); - } - - public function explodeBlocks(Position $source, $rays = 16, $size = 4){ - $vector = new Vector3(0, 0, 0); - $vBlock = new Vector3(0, 0, 0); - $stepLen = 0.3; - $mRays = \intval($rays - 1); - $affectedBlocks = array(); - for($i = 0; $i < $rays; ++$i){ - for($j = 0; $j < $rays; ++$j){ - for($k = 0; $k < $rays; ++$k){ - if($i === 0 or $i === $mRays or $j === 0 or $j === $mRays or $k === 0 or $k === $mRays){ - $vector->setComponents($i / $mRays * 2 - 1, $j / $mRays * 2 - 1, $k / $mRays * 2 - 1); - $vector->setComponents(($vector->x / ($len = $vector->length())) * $stepLen, ($vector->y / $len) * $stepLen, ($vector->z / $len) * $stepLen); - $pointerX = $source->x; - $pointerY = $source->y; - $pointerZ = $source->z; - - for($blastForce = $size * (\mt_rand(700, 1300) / 1000); $blastForce > 0; $blastForce -= $stepLen * 0.75){ - $x = (int) $pointerX; - $y = (int) $pointerY; - $z = (int) $pointerZ; - $vBlock->x = $pointerX >= $x ? $x : $x - 1; - $vBlock->y = $pointerY >= $y ? $y : $y - 1; - $vBlock->z = $pointerZ >= $z ? $z : $z - 1; - if($vBlock->y < 0 or $vBlock->y > 127){ - break; - } - $block = $source->getLevel()->getBlock($vBlock); - - if($block->getId() !== 0){ - $blastForce -= (mt_rand(1, 3) / 5 + 0.3) * $stepLen; - if($blastForce > 0){ - if(!isset($affectedBlocks[$index = (\PHP_INT_SIZE === 8 ? ((($block->x) & 0xFFFFFFF) << 35) | ((($block->y) & 0x7f) << 28) | (($block->z) & 0xFFFFFFF) : ($block->x) . ":" . ($block->y) . ":" . ($block->z))])){ - $affectedBlocks[$index] = $block; - } - } - } - $pointerX += $vector->x; - $pointerY += $vector->y; - $pointerZ += $vector->z; - } - } - } - } - } - foreach($affectedBlocks as $block){ - if($block instanceof Block){ - $block->getLevel()->setBlock($block, new Air(), false, false); - } - } - } - - public function fdx($x, $y, $z, Level $level, $liu = false){ - //$this->getLogger()->info(TextFormat::GREEN."fdx!"); - for($i = 1; $i < mt_rand(2, 4); $i++){ - $level->setBlockIdAt($x + $i - 2, $y - 1, $z + 1, 0); - $level->setBlockIdAt($x + $i - 2, $y - 1, $z, 0); - $level->setBlockIdAt($x + $i - 2, $y - 1, $z - 1, 0); - $level->setBlockIdAt($x + $i - 2, $y - 1, $z - 1, 0); - $level->setBlockIdAt($x + $i - 2, $y - 1, $z + 1, 0); - $level->setBlockIdAt($x + $i - 2, $y + 2, $z + 1, 0); - $level->setBlockIdAt($x + $i - 2, $y + 2, $z, 0); - $level->setBlockIdAt($x + $i - 2, $y + 2, $z - 1, 0); - } - for($i = 1; $i < mt_rand(3, 6); $i++){ - $level->setBlockIdAt($x + $i - 3, $y + 1, $z + 2, 0); - $level->setBlockIdAt($x + $i - 3, $y + 1, $z + 1, 0); - $level->setBlockIdAt($x + $i - 3, $y + 1, $z, 0); - $level->setBlockIdAt($x + $i - 3, $y + 1, $z - 1, 0); - $level->setBlockIdAt($x + $i - 3, $y + 1, $z - 2, 0); - $level->setBlockIdAt($x + $i - 3, $y, $z + 2, 0); - $level->setBlockIdAt($x + $i - 3, $y, $z + 1, 0); - $level->setBlockIdAt($x + $i - 3, $y, $z, 0); - $level->setBlockIdAt($x + $i - 3, $y, $z - 1, 0); - $level->setBlockIdAt($x + $i - 3, $y, $z - 2, 0); - } - if($liu){ - $l = (mt_rand(0, 1) == 0) ? new Water() : new Lava(); - $i = mt_rand(3, 6); - $level->setBlock(new Vector3($x + $i - 3, $y + 1, $z + 3), $l); - } - } - - public function ranz($a){ - $n = []; - $j = 0; - for($m = 0; $m < $a; $m++){ - $n[] = mt_rand(0, 999) / 1000 - 1; - } - - for($m = 0; $m < $a; $m++){ - foreach($n as $q){ - $min = min($n); - if($n[$q] == $min){ - $n[$q] = $j; - $j++; - break; - } - } - } - return $n; - } - - public function tiankengy(Level $level, $x, $y, $z, $l, $id, $bd){ - if($level->getBlock(new Vector3($x, $y, $z))->getId() == 0) $level->setBlock(new Vector3($x, $y, $z), Item::get($id, $bd)->getBlock()); - if($l >= 0){ - $random = mt_rand(0, 99999) / 100000; - $mz = $this->ranz(4); - foreach($mz as $sss){ - switch($mz[$sss]){ - case 0: - if($level->getBlock(new Vector3($x, $y, $z - 1))->getId() == 0) $this->tiankengy($level, $x, $y, $z - 1, $l - $random, $id, $bd); - break; - case 1: - if($level->getBlock(new Vector3($x, $y, $z + 1))->getId() == 0) $this->tiankengy($level, $x, $y, $z + 1, $l - $random, $id, $bd); - break; - case 2: - if($level->getBlock(new Vector3($x + 1, $y, $z))->getId() == 0) $this->tiankengy($level, $x + 1, $y, $z, $l - $random, $id, $bd); - break; - case 3: - if($level->getBlock(new Vector3($x - 1, $y, $z))->getId() == 0) $this->tiankengy($level, $x - 1, $y, $z, $l - $random, $id, $bd); - break; - } - } - } - } - -} \ No newline at end of file diff --git a/src/devmine/server/commands/defaults/ChunkInfoCommand.php b/src/devmine/server/commands/defaults/ChunkInfoCommand.php deleted file mode 100644 index bc941dc..0000000 --- a/src/devmine/server/commands/defaults/ChunkInfoCommand.php +++ /dev/null @@ -1,64 +0,0 @@ -setPermission("devmine.command.chunkinfo"); - } - - public function execute(CommandSender $sender, $commandLabel, array $args){ - if(!$this->testPermission($sender)){ - return true; - } - - if(!$sender instanceof Player and count($args) < 4){ - $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); - - return false; - } - - if($sender instanceof Player and count($args) < 4){ - $pos = $sender->getPosition(); - }else{ - $level = $sender->getServer()->getLevelByName($args[3]); - if(!$level instanceof Level){ - $sender->sendMessage(TextFormat::RED . "Invalid level name"); - - return false; - } - $pos = new Position((int) $args[0], (int) $args[1], (int) $args[2], $level); - } - - if(!isset($args[4]) or $args[0] != "regenerate"){ - $chunk = $pos->getLevel()->getChunk($pos->x >> 4, $pos->z >> 4); - McRegion::getRegionIndex($chunk->getX(), $chunk->getZ(), $x, $z); - - $sender->sendMessage("Region X: $x Region Z: $z"); - }elseif($args[4] == "regenerate"){ - foreach($sender->getServer()->getOnlinePlayers() as $p){ - if($p->getLevel() == $pos->getLevel()){ - $p->kick(TextFormat::AQUA . "A chunk of this chunk is regenerating, please re-login.", false); - } - } - $pos->getLevel()->regenerateChunk($pos->x >> 4, $pos->z >> 4); - } - - return true; - } -} \ No newline at end of file diff --git a/src/devmine/server/commands/defaults/DefaultGamemodeCommand.php b/src/devmine/server/commands/defaults/DefaultGamemodeCommand.php index 16adeae..51c3236 100644 --- a/src/devmine/server/commands/defaults/DefaultGamemodeCommand.php +++ b/src/devmine/server/commands/defaults/DefaultGamemodeCommand.php @@ -5,8 +5,8 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Server; +use devmine\events\TranslationContainer; +use devmine\server\server; class DefaultGamemodeCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class DefaultGamemodeCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.defaultgamemode.description", + "%DevMine.command.defaultgamemode.description", "%commands.defaultgamemode.usage" ); - $this->setPermission("devmine.command.defaultgamemode"); + $this->setPermission("DevMine.command.defaultgamemode"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/DeopCommand.php b/src/devmine/server/commands/defaults/DeopCommand.php index ce41f29..03625ee 100644 --- a/src/devmine/server/commands/defaults/DeopCommand.php +++ b/src/devmine/server/commands/defaults/DeopCommand.php @@ -6,8 +6,8 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class DeopCommand extends VanillaCommand{ @@ -15,10 +15,10 @@ class DeopCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.deop.description", + "%DevMine.command.deop.description", "%commands.deop.usage" ); - $this->setPermission("devmine.command.op.take"); + $this->setPermission("DevMine.command.op.take"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/DifficultyCommand.php b/src/devmine/server/commands/defaults/DifficultyCommand.php index dbdf0c6..585eb27 100644 --- a/src/devmine/server/commands/defaults/DifficultyCommand.php +++ b/src/devmine/server/commands/defaults/DifficultyCommand.php @@ -6,10 +6,10 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\server\network\Network; use devmine\server\network\protocol\SetDifficultyPacket; -use devmine\Server; +use devmine\server\server; class DifficultyCommand extends VanillaCommand{ @@ -17,10 +17,10 @@ class DifficultyCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.difficulty.description", + "%DevMine.command.difficulty.description", "%commands.difficulty.usage" ); - $this->setPermission("devmine.command.difficulty"); + $this->setPermission("DevMine.command.difficulty"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/DumpMemoryCommand.php b/src/devmine/server/commands/defaults/DumpMemoryCommand.php index 2510ea2..92bba10 100644 --- a/src/devmine/server/commands/defaults/DumpMemoryCommand.php +++ b/src/devmine/server/commands/defaults/DumpMemoryCommand.php @@ -16,7 +16,7 @@ public function __construct($name){ "Dumps the memory", "/$name [path]" ); - $this->setPermission("devmine.command.dumpmemory"); + $this->setPermission("DevMine.command.dumpmemory"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/EffectCommand.php b/src/devmine/server/commands/defaults/EffectCommand.php index 12e5d06..2d696b7 100644 --- a/src/devmine/server/commands/defaults/EffectCommand.php +++ b/src/devmine/server/commands/defaults/EffectCommand.php @@ -8,7 +8,7 @@ use devmine\server\commands\CommandSender; use devmine\creatures\entities\Effect; use devmine\creatures\entities\InstantEffect; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\utilities\main\TextFormat; class EffectCommand extends VanillaCommand{ @@ -16,10 +16,10 @@ class EffectCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.effect.description", + "%DevMine.command.effect.description", "%commands.effect.usage" ); - $this->setPermission("devmine.command.effect;devmine.command.effect.other"); + $this->setPermission("DevMine.command.effect;DevMine.command.effect.other"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -39,7 +39,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ return true; } - if($player->getName()!=$sender->getName() && !$sender->hasPermission("devmine.command.effect.other")){ + if($player->getName()!=$sender->getName() && !$sender->hasPermission("DevMine.command.effect.other")){ $sender->sendMessage("You don't have permission to give effect to other player ."); return true; } @@ -97,13 +97,15 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ return true; } - $player->removeEffect($effect->getId()); - $sender->sendMessage(new TranslationContainer("commands.effect.success.removed", [$effect->getName(), $player->getDisplayName()])); + if ($player->removeEffect($effect->getId())) { + $sender->sendMessage(new TranslationContainer("commands.effect.success.removed", [$effect->getName(), $player->getDisplayName()])); + } }else{ $effect->setDuration($duration)->setAmplifier($amplification); - $player->addEffect($effect); - self::broadcastCommandMessage($sender, new TranslationContainer("%commands.effect.success", [$effect->getName(), $effect->getId(), $effect->getAmplifier(), $player->getDisplayName(), $effect->getDuration() / 20])); + if ($player->addEffect($effect)) { + self::broadcastCommandMessage($sender, new TranslationContainer("%commands.effect.success", [$effect->getName(), $effect->getId(), $effect->getAmplifier(), $player->getDisplayName(), $effect->getDuration() / 20])); + } } diff --git a/src/devmine/server/commands/defaults/EnchantCommand.php b/src/devmine/server/commands/defaults/EnchantCommand.php index 7f6d46d..414f1de 100644 --- a/src/devmine/server/commands/defaults/EnchantCommand.php +++ b/src/devmine/server/commands/defaults/EnchantCommand.php @@ -8,20 +8,20 @@ use devmine\server\commands\CommandSender; use devmine\creatures\entities\Effect; use devmine\creatures\entities\InstantEffect; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\inventory\items\enchantment\Enchantment; use devmine\utilities\main\TextFormat; -use devmine\Server; +use devmine\server\server; class EnchantCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.enchant.description", + "%DevMine.command.enchant.description", "%commands.enchant.usage" ); - $this->setPermission("devmine.command.enchant"); + $this->setPermission("DevMine.command.enchant"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -41,15 +41,23 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ return true; } - $enchantId = (int) $args[1]; + $enchantId = $args[1]; $enchantLevel = isset($args[2]) ? (int) $args[2] : 1; $enchantment = Enchantment::getEnchantment($enchantId); if($enchantment->getId() === Enchantment::TYPE_INVALID){ - $sender->sendMessage(new TranslationContainer("commands.enchant.notFound", [$enchantId])); + $enchantment = Enchantment::getEnchantmentByName($enchantId); + if($enchantment->getId() === Enchantment::TYPE_INVALID){ + $sender->sendMessage(new TranslationContainer("commands.enchant.notFound", [$enchantment->getId()])); + return true; + } + } + $id = $enchantment->getId(); + $maxLevel = Enchantment::getEnchantMaxLevel($id); + if($enchantLevel > $maxLevel or $enchantLevel <= 0){ + $sender->sendMessage(new TranslationContainer("commands.enchant.maxLevel", [$maxLevel])); return true; } - $enchantment->setLevel($enchantLevel); $item = $player->getInventory()->getItemInHand(); @@ -71,4 +79,4 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ self::broadcastCommandMessage($sender, new TranslationContainer("%commands.enchant.success")); return true; } -} \ No newline at end of file +} diff --git a/src/devmine/server/commands/defaults/ExtractPharCommand.php b/src/devmine/server/commands/defaults/ExtractPharCommand.php deleted file mode 100644 index 938efd6..0000000 --- a/src/devmine/server/commands/defaults/ExtractPharCommand.php +++ /dev/null @@ -1,44 +0,0 @@ -" - ); - $this->setPermission("devmine.command.extractphar"); - } - - public function execute(CommandSender $sender, $commandLabel, array $args){ - if(!$this->testPermission($sender)){ - return false; - } - - if(count($args) === 0){ - $sender->sendMessage(TextFormat::RED . "Usage: ".$this->usageMessage); - return true; - } - if(!isset($args[0]) or !file_exists($args[0])) return \false; - $folderPath = $sender->getServer()->getPluginPath().DIRECTORY_SEPARATOR . "devmine" . DIRECTORY_SEPARATOR . basename($args[0]); - if(file_exists($folderPath)){ - $sender->sendMessage("Phar already exists, overwriting..."); - }else{ - @mkdir($folderPath); - } - - $pharPath = "phar://$args[0]"; - - foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($pharPath)) as $fInfo){ - $path = $fInfo->getPathname(); - @mkdir(dirname($folderPath . str_replace($pharPath, "", $path)), 0755, true); - file_put_contents($folderPath . str_replace($pharPath, "", $path), file_get_contents($path)); - } - $sender->sendMessage("Source Phar $args[0] has been created on $folderPath"); - } -} diff --git a/src/devmine/server/commands/defaults/ExtractPluginCommand.php b/src/devmine/server/commands/defaults/ExtractPluginCommand.php deleted file mode 100644 index 139f178..0000000 --- a/src/devmine/server/commands/defaults/ExtractPluginCommand.php +++ /dev/null @@ -1,63 +0,0 @@ -" - ); - $this->setPermission("devmine.command.extractplugin"); - } - - public function execute(CommandSender $sender, $commandLabel, array $args){ - if(!$this->testPermission($sender)){ - return false; - } - - if(count($args) === 0){ - $sender->sendMessage(TextFormat::RED . "Usage: ".$this->usageMessage); - return true; - } - - $pluginName = trim(implode(" ", $args)); - if($pluginName === "" or !(($plugin = Server::getInstance()->getPluginManager()->getPlugin($pluginName)) instanceof Plugin)){ - $sender->sendMessage(TextFormat::RED . "Invalid plugin name, check the file is in the plugin directory."); - return true; - } - $description = $plugin->getDescription(); - - if(!($plugin->getPluginLoader() instanceof PharPluginLoader)){ - $sender->sendMessage(TextFormat::RED . "Plugin ".$description->getName()." is not in Phar structure."); - return true; - } - - $folderPath = Server::getInstance()->getPluginPath().DIRECTORY_SEPARATOR . "devmine" . DIRECTORY_SEPARATOR . $description->getName()."_v".$description->getVersion()."/"; - if(file_exists($folderPath)){ - $sender->sendMessage("Plugin already exists, overwriting..."); - }else{ - @mkdir($folderPath); - } - - $reflection = new \ReflectionClass("devmine\\plugin\\PluginBase"); - $file = $reflection->getProperty("file"); - $file->setAccessible(true); - $pharPath = str_replace("\\", "/", rtrim($file->getValue($plugin), "\\/")); - - foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($pharPath)) as $fInfo){ - $path = $fInfo->getPathname(); - @mkdir(dirname($folderPath . str_replace($pharPath, "", $path)), 0755, true); - file_put_contents($folderPath . str_replace($pharPath, "", $path), file_get_contents($path)); - } - $sender->sendMessage("Source plugin ".$description->getName() ." v".$description->getVersion()." has been created on ".$folderPath); - return true; - } -} diff --git a/src/devmine/server/commands/defaults/FillCommand.php b/src/devmine/server/commands/defaults/FillCommand.php deleted file mode 100644 index 69a8e27..0000000 --- a/src/devmine/server/commands/defaults/FillCommand.php +++ /dev/null @@ -1,85 +0,0 @@ -setPermission("devmine.command.fill"); - } - - public function execute(CommandSender $sender, $label, array $args){ - if(!$this->testPermission($sender)){ - return true; - } - - for($a = 0; $a < 6; $a++){ - if(isset($args[$a])){ - if(is_numeric($args[$a]) and is_integer($args[$a] + 0)){ - $item = Item::fromString($args[6]); - if($item instanceof ItemBlock){ - $xmin = min($args[0] + 0, $args[3] + 0); - $xmax = max($args[0] + 0, $args[3] + 0); - $ymin = min($args[1] + 0, $args[4] + 0); - $ymax = max($args[1] + 0, $args[4] + 0); - $zmin = min($args[2] + 0, $args[5] + 0); - $zmax = max($args[2] + 0, $args[5] + 0); - $level = ($sender instanceof Player) ? $sender->getLevel() : $sender->getServer()->getDefaultLevel(); - $n = 0; - $nmax = ($xmax - $xmin + 1) * ($ymax - $ymin + 1) * ($zmax - $zmin + 1); - for($x = $xmin; $x <= $xmax; $x++){ - for($y = $ymin; $y <= $ymax; $y++){ - for($z = $zmin; $z <= $zmax; $z++){ - if ($this->setBlock(new Vector3($x, $y, $z), $level, $item, isset($args[7]) ? $args[7] : 0)) { - $n++; - if (is_int($n/10000)) { - $sender->sendMessage(new TranslationContainer("$n out of $nmax blocks filled, now at $x $y $z", [])); - } - } - else { - $sender->sendMessage(TextFormat::RED . new TranslationContainer("Error after filling $n out of $nmax blocks.", [])); - return false; - } - } - } - } - $sender->sendMessage(new TranslationContainer("Total of $n blocks filled.", [])); - return true; - } - $sender->sendMessage(TextFormat::RED . new TranslationContainer($args[6] . " is not a valid block.", [])); - return false; - } - $sender->sendMessage(TextFormat::RED . new TranslationContainer($args[$a] . " is not a valid coordinate.", [])); - $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); - return false; - } - $sender->sendMessage(TextFormat::RED . new TranslationContainer("devmine.command.fill.missingParameter", [])); - $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); - return false; - } - } - - private function setBlock(Vector3 $p, Level $lvl, ItemBlock $b, int $meta = 0) : bool{ - $block = $b->getBlock(); - $block->setDamage($meta); - $lvl->setBlock($p, $block); - return true; - } -} diff --git a/src/devmine/server/commands/defaults/GamemodeCommand.php b/src/devmine/server/commands/defaults/GamemodeCommand.php index bafcdb5..3aac263 100644 --- a/src/devmine/server/commands/defaults/GamemodeCommand.php +++ b/src/devmine/server/commands/defaults/GamemodeCommand.php @@ -6,9 +6,9 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; -use devmine\Server; +use devmine\events\TranslationContainer; +use devmine\creatures\player; +use devmine\server\server; use devmine\utilities\main\TextFormat; class GamemodeCommand extends VanillaCommand{ @@ -16,11 +16,11 @@ class GamemodeCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.gamemode.description", + "%DevMine.command.gamemode.description", "%commands.gamemode.usage", ["gm"] ); - $this->setPermission("devmine.command.gamemode"); + $this->setPermission("DevMine.command.gamemode"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -60,13 +60,12 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ $sender->sendMessage(TextFormat::RED . "Game mode change for " . $target->getName() . " failed!"); }else{ if($target === $sender){ - Command::broadcastCommandMessage($sender, new TranslationContainer("commands.gamemode.success.self", [Server::getGamemodeString($gameMode)])); + Command::broadcastCommandMessage($sender, new TranslationContainer("commands.gamemode.success.self", [' ', ' ', Server::getGamemodeString($gameMode)])); }else{ $target->sendMessage(new TranslationContainer("gameMode.changed")); Command::broadcastCommandMessage($sender, new TranslationContainer("commands.gamemode.success.other", [$target->getName(), Server::getGamemodeString($gameMode)])); } } - return true; } } diff --git a/src/devmine/server/commands/defaults/GarbageCollectorCommand.php b/src/devmine/server/commands/defaults/GarbageCollectorCommand.php index 15dd71d..1509e6e 100644 --- a/src/devmine/server/commands/defaults/GarbageCollectorCommand.php +++ b/src/devmine/server/commands/defaults/GarbageCollectorCommand.php @@ -13,10 +13,10 @@ class GarbageCollectorCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.gc.description", - "%devmine.command.gc.usage" + "%DevMine.command.gc.description", + "%DevMine.command.gc.usage" ); - $this->setPermission("devmine.command.gc"); + $this->setPermission("DevMine.command.gc"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -26,27 +26,27 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ $chunksCollected = 0; $entitiesCollected = 0; - $solidentitiesCollected = 0; + $tilesCollected = 0; $memory = memory_get_usage(); foreach($sender->getServer()->getLevels() as $level){ - $diff = [count($level->getChunks()), count($level->getEntities()), count($level->getsolidentities())]; + $diff = [count($level->getChunks()), count($level->getEntities()), count($level->getTiles())]; $level->doChunkGarbageCollection(); $level->unloadChunks(true); $chunksCollected += $diff[0] - count($level->getChunks()); $entitiesCollected += $diff[1] - count($level->getEntities()); - $solidentitiesCollected += $diff[2] - count($level->getsolidentities()); + $tilesCollected += $diff[2] - count($level->getTiles()); $level->clearCache(true); } $cyclesCollected = $sender->getServer()->getMemoryManager()->triggerGarbageCollector(); - $sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "%devmine.command.gc.title" . TextFormat::GREEN . " ----"); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.gc.chunks" . TextFormat::RED . \number_format($chunksCollected)); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.gc.entities" . TextFormat::RED . \number_format($entitiesCollected)); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.gc.solidentities" . TextFormat::RED . \number_format($solidentitiesCollected)); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.gc.cycles" . TextFormat::RED . \number_format($cyclesCollected)); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.gc.memory" . TextFormat::RED . \number_format(\round((($memory - \memory_get_usage()) / 1024) / 1024, 2))." MB"); + $sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "%DevMine.command.gc.title" . TextFormat::GREEN . " ----"); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.gc.chunks " . TextFormat::RED . \number_format($chunksCollected)); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.gc.entities " . TextFormat::RED . \number_format($entitiesCollected)); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.gc.tiles " . TextFormat::RED . \number_format($tilesCollected)); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.gc.cycles " . TextFormat::RED . \number_format($cyclesCollected)); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.gc.memory " . TextFormat::RED . \number_format(\round((($memory - \memory_get_usage()) / 1024) / 1024, 2))." MB"); return true; } } diff --git a/src/devmine/server/commands/defaults/GiveCommand.php b/src/devmine/server/commands/defaults/GiveCommand.php index a889047..ee9de64 100644 --- a/src/devmine/server/commands/defaults/GiveCommand.php +++ b/src/devmine/server/commands/defaults/GiveCommand.php @@ -6,11 +6,11 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\inventory\items\Item; use devmine\creatures\player\NBT; use devmine\creatures\player\tag\CompoundTag; -use devmine\Player; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class GiveCommand extends VanillaCommand{ @@ -18,10 +18,10 @@ class GiveCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.give.description", - "%devmine.command.give.usage" + "%DevMine.command.give.description", + "%DevMine.command.give.usage" ); - $this->setPermission("devmine.command.give"); + $this->setPermission("DevMine.command.give"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/HelpCommand.php b/src/devmine/server/commands/defaults/HelpCommand.php index ca9a9aa..8c86b24 100644 --- a/src/devmine/server/commands/defaults/HelpCommand.php +++ b/src/devmine/server/commands/defaults/HelpCommand.php @@ -7,7 +7,7 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; use devmine\server\commands\ConsoleCommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\utilities\main\TextFormat; class HelpCommand extends VanillaCommand{ @@ -15,11 +15,11 @@ class HelpCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.help.description", + "%DevMine.command.help.description", "%commands.help.usage", ["?"] ); - $this->setPermission("devmine.command.help"); + $this->setPermission("DevMine.command.help"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -44,7 +44,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ if($sender instanceof ConsoleCommandSender){ $pageHeight = PHP_INT_MAX; }else{ - $pageHeight = 5; + $pageHeight = 7; } if($command === ""){ diff --git a/src/devmine/server/commands/defaults/KickCommand.php b/src/devmine/server/commands/defaults/KickCommand.php index 5e768f6..1e6f2d5 100644 --- a/src/devmine/server/commands/defaults/KickCommand.php +++ b/src/devmine/server/commands/defaults/KickCommand.php @@ -6,8 +6,8 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class KickCommand extends VanillaCommand{ @@ -15,10 +15,10 @@ class KickCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.kick.description", + "%DevMine.command.kick.description", "%commands.kick.usage" ); - $this->setPermission("devmine.command.kick"); + $this->setPermission("DevMine.command.kick"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/KillCommand.php b/src/devmine/server/commands/defaults/KillCommand.php index 2aa2085..b713db6 100644 --- a/src/devmine/server/commands/defaults/KillCommand.php +++ b/src/devmine/server/commands/defaults/KillCommand.php @@ -6,9 +6,9 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\entity\EntityDamageEvent; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\entity\EntityDamageEvent; +use devmine\events\TranslationContainer; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class KillCommand extends VanillaCommand{ @@ -16,11 +16,11 @@ class KillCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.kill.description", - "%devmine.command.kill.usage", + "%DevMine.command.kill.description", + "%DevMine.command.kill.usage", ["suicide"] ); - $this->setPermission("devmine.command.kill.self;devmine.command.kill.other"); + $this->setPermission("DevMine.command.kill.self;DevMine.command.kill.other"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -35,7 +35,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ } if(count($args) === 1){ - if(!$sender->hasPermission("devmine.command.kill.other")){ + if(!$sender->hasPermission("DevMine.command.kill.other")){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission")); return true; @@ -62,7 +62,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ } if($sender instanceof Player){ - if(!$sender->hasPermission("devmine.command.kill.self")){ + if(!$sender->hasPermission("DevMine.command.kill.self")){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission")); return true; diff --git a/src/devmine/server/commands/defaults/ListCommand.php b/src/devmine/server/commands/defaults/ListCommand.php index 623cb17..5d8a090 100644 --- a/src/devmine/server/commands/defaults/ListCommand.php +++ b/src/devmine/server/commands/defaults/ListCommand.php @@ -5,8 +5,8 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; class ListCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class ListCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.list.description", + "%DevMine.command.list.description", "%command.players.usage" ); - $this->setPermission("devmine.command.list"); + $this->setPermission("DevMine.command.list"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/LoadPluginCommand.php b/src/devmine/server/commands/defaults/LoadPluginCommand.php deleted file mode 100644 index d6218d9..0000000 --- a/src/devmine/server/commands/defaults/LoadPluginCommand.php +++ /dev/null @@ -1,37 +0,0 @@ -" - ); - $this->setPermission("devmine.command.loadplugin"); - } - - public function execute(CommandSender $sender, $commandLabel, array $args){ - if(!$this->testPermission($sender)){ - return false; - } - - if(count($args) === 0){ - $sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage); - return true; - } - - if(!isset($args[0])) return false; - - $plugin = $sender->getServer()->getPluginManager()->loadPlugin($sender->getServer()->getPluginPath() . DIRECTORY_SEPARATOR . $args[0]); - if($plugin != null){ - $sender->getServer()->getPluginManager()->enablePlugin($plugin); - return true; - } - return false; - } -} \ No newline at end of file diff --git a/src/devmine/server/commands/defaults/LvdatCommand.php b/src/devmine/server/commands/defaults/LvdatCommand.php deleted file mode 100644 index d1e07fb..0000000 --- a/src/devmine/server/commands/defaults/LvdatCommand.php +++ /dev/null @@ -1,114 +0,0 @@ - " - ); - $this->setPermission("devmine.command.lvdat"); - } - - public function execute(CommandSender $sender, $currentAlias, array $args){ - if(!$this->testPermission($sender)){ - return false; - } - $levname = array_shift($args); - if($levname == ""){ - $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); - return false; - } - if(!$this->autoLoad($sender, $levname)){ - $sender->sendMessage(new TranslationContainer("devmine.command.lvdat.nofound", [$levname])); - return false; - } - $level = $sender->getServer()->getLevelByName($levname); - if(!$level){ - $sender->sendMessage(new TranslationContainer("devmine.command.lvdat.nofound", [$levname])); - return false; - } - /** @var BaseLevelProvider $provider */ - $provider = $level->getProvider(); - $o = array_shift($args); - $p = array_shift($args); - switch($o){ - case "fixname": - $provider->getLevelData()->LevelName = new StringTag("LevelName", $level->getFolderName()); - $sender->sendMessage(new TranslationContainer("devmine.command.lvdat.fixname", [$level->getFolderName()])); - break; - case "help": - $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); - $sender->sendMessage("/lvdat %commands.generic.level fixname"); - $sender->sendMessage("/lvdat %commands.generic.level seed %commands.generic.seed"); - $sender->sendMessage("/lvdat %commands.generic.level name %commands.generic.name"); - $sender->sendMessage("/lvdat %commands.generic.level generator %commands.generic.generator"); - $sender->sendMessage("/lvdat %commands.generic.level preset %devmine.command.lvdat.preset"); - break; - case "seed": - if($p == ""){ - $sender->sendMessage("%commands.generic.opt.missing"); - return false; - } - $provider->setSeed($p); - $sender->sendMessage(new TranslationContainer("devmine.command.lvdat.changed", [$level->getFolderName(), $o])); - break; - case "name": - if($p == ""){ - $sender->sendMessage("%commands.generic.opt.missing"); - return false; - } - $provider->getLevelData()->LevelName = new StringTag("LevelName", $p); - $sender->sendMessage(new TranslationContainer("devmine.command.lvdat.changed", [$level->getFolderName(), $o])); - break; - case "generator": - if($p == ""){ - $sender->sendMessage("%commands.generic.opt.missing"); - return false; - } - $provider->getLevelData()->generatorName = new StringTag("generatorName", $p); - $sender->sendMessage(new TranslationContainer("devmine.command.lvdat.changed", [$level->getFolderName(), $o])); - break; - case "preset": - if($p == ""){ - $sender->sendMessage("%commands.generic.opt.missing"); - return false; - } - $provider->getLevelData()->generatorOptions = new StringTag("generatorOptions", $p); - $sender->sendMessage(new TranslationContainer("devmine.command.lvdat.changed", [$level->getFolderName(), $o])); - break; - default: - $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); - return false; - } - $provider->saveLevelData(); - return true; - } - - public function autoLoad(CommandSender $c, $world){ - if($c->getServer()->isLevelLoaded($world)) return true; - if(!$c->getServer()->isLevelGenerated($world)){ - return false; - } - $c->getServer()->loadLevel($world); - return $c->getServer()->isLevelLoaded($world); - } -} diff --git a/src/devmine/server/commands/defaults/MakePluginCommand.php b/src/devmine/server/commands/defaults/MakePluginCommand.php deleted file mode 100644 index 2c8bd00..0000000 --- a/src/devmine/server/commands/defaults/MakePluginCommand.php +++ /dev/null @@ -1,95 +0,0 @@ - (nogz)" - ); - $this->setPermission("devmine.command.makeplugin"); - } - - public function execute(CommandSender $sender, $commandLabel, array $args){ - if(!$this->testPermission($sender)){ - return false; - } - - if(count($args) === 0){ - $sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage); - return true; - } - - $pluginName = trim(implode(" ", $args)); - if($pluginName === "" or !(($plugin = Server::getInstance()->getPluginManager()->getPlugin($pluginName)) instanceof Plugin)){ - $sender->sendMessage(TextFormat::RED . "Invalid plugin name, check the name case."); - return true; - } - $description = $plugin->getDescription(); - - if(!($plugin->getPluginLoader() instanceof FolderPluginLoader)){ - $sender->sendMessage(TextFormat::RED . "Plugin " . $description->getName() . " is not in folder structure."); - return true; - } - - $pharPath = Server::getInstance()->getPluginPath() . DIRECTORY_SEPARATOR . "devmine" . DIRECTORY_SEPARATOR . $description->getName() . "_v" . $description->getVersion() . ".phar"; - if(file_exists($pharPath)){ - $sender->sendMessage("Phar plugin already exists, overwriting..."); - @unlink($pharPath); - } - $phar = new \Phar($pharPath); - $phar->setepilogos([ - "name" => $description->getName(), - "version" => $description->getVersion(), - "main" => $description->getMain(), - "api" => $description->getCompatibleApis(), - "geniapi" => $description->getCompatibleGeniApis(), - "depend" => $description->getDepend(), - "description" => $description->getDescription(), - "authors" => $description->getAuthors(), - "website" => $description->getWebsite(), - "creator" => "devmine MakePluginCommand", - "creationDate" => time() - ]); - if($description->getName() === "DevTools"){ - $phar->setStub('setStub('getName() . ' v' . $description->getVersion() . '\nThis file has been generated using devmine by iTX Technologies at ' . date("r") . '\n----------------\n";if(extension_loaded("phar")){$phar = new \Phar(__FILE__);foreach($phar->getepilogos() as $key => $value){echo ucfirst($key).": ".(is_array($value) ? implode(", ", $value):$value)."\n";}} __HALT_COMPILER();'); - } - $phar->setSignatureAlgorithm(\Phar::SHA1); - $reflection = new \ReflectionClass("devmine\\plugin\\PluginBase"); - $file = $reflection->getProperty("file"); - $file->setAccessible(true); - $filePath = rtrim(str_replace("\\", "/", $file->getValue($plugin)), "/") . "/"; - $phar->startBuffering(); - foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($filePath)) as $file){ - $path = ltrim(str_replace(["\\", $filePath], ["/", ""], $file), "/"); - if($path{0} === "." or strpos($path, "/.") !== false){ - continue; - } - $phar->addFile($file, $path); - $sender->sendMessage("[devmine] Adding $path"); - } - - foreach($phar as $file => $finfo){ - /** @var \PharFileInfo $finfo */ - if($finfo->getSize() > (1024 * 512)){ - $finfo->compress(\Phar::GZ); - } - } - if(!isset($args[1]) or (isset($args[1]) and $args[1] != "nogz")){ - $phar->compressFiles(\Phar::GZ); - } - $phar->stopBuffering(); - $sender->sendMessage("Phar plugin " . $description->getName() . " v" . $description->getVersion() . " has been created on " . $pharPath); - return true; - } -} diff --git a/src/devmine/server/commands/defaults/MakeServerCommand.php b/src/devmine/server/commands/defaults/MakeServerCommand.php deleted file mode 100644 index decf6dc..0000000 --- a/src/devmine/server/commands/defaults/MakeServerCommand.php +++ /dev/null @@ -1,72 +0,0 @@ -setPermission("devmine.command.makeserver"); - } - - public function execute(CommandSender $sender, $commandLabel, array $args){ - if(!$this->testPermission($sender)){ - return false; - } - - $server = $sender->getServer(); - $pharPath = Server::getInstance()->getPluginPath() . DIRECTORY_SEPARATOR . "devmine" . DIRECTORY_SEPARATOR . $server->getName() . "_" . $server->getdevmineVersion() . ".phar"; - if(file_exists($pharPath)){ - $sender->sendMessage("Phar file already exists, overwriting..."); - @unlink($pharPath); - } - $phar = new \Phar($pharPath); - $phar->setepilogos([ - "name" => $server->getName(), - "version" => $server->getdevmineVersion(), - "api" => $server->getApiVersion(), - "geniapi" => $server->getGeniApiVersion(), - "minecraft" => $server->getVersion(), - "protocol" => Info::CURRENT_PROTOCOL, - "creator" => "devmine MakeServerCommand", - "creationDate" => time() - ]); - $phar->setStub('setSignatureAlgorithm(\Phar::SHA1); - $phar->startBuffering(); - - $filePath = substr(\devmine\PATH, 0, 7) === "phar://" ? \devmine\PATH : realpath(\devmine\PATH) . "/"; - $filePath = rtrim(str_replace("\\", "/", $filePath), "/") . "/"; - foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($filePath . "src")) as $file){ - $path = ltrim(str_replace(["\\", $filePath], ["/", ""], $file), "/"); - if($path{0} === "." or strpos($path, "/.") !== false or substr($path, 0, 4) !== "src/"){ - continue; - } - $phar->addFile($file, $path); - $sender->sendMessage("[devmine] Adding $path"); - } - foreach($phar as $file => $finfo){ - /** @var \PharFileInfo $finfo */ - if($finfo->getSize() > (1024 * 512)){ - $finfo->compress(\Phar::GZ); - } - } - if(!isset($args[0]) or (isset($args[0]) and $args[0] != "nogz")){ - $phar->compressFiles(\Phar::GZ); - } - $phar->stopBuffering(); - - $sender->sendMessage($server->getName() . " " . $server->getdevmineVersion() . " Phar file has been created on " . $pharPath); - - return true; - } -} diff --git a/src/devmine/server/commands/defaults/MeCommand.php b/src/devmine/server/commands/defaults/MeCommand.php index 04cf4e9..a9d530f 100644 --- a/src/devmine/server/commands/defaults/MeCommand.php +++ b/src/devmine/server/commands/defaults/MeCommand.php @@ -5,8 +5,8 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class MeCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class MeCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.me.description", + "%DevMine.command.me.description", "%commands.me.usage" ); - $this->setPermission("devmine.command.me"); + $this->setPermission("DevMine.command.me"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/OpCommand.php b/src/devmine/server/commands/defaults/OpCommand.php index 48af22b..11b2a1c 100644 --- a/src/devmine/server/commands/defaults/OpCommand.php +++ b/src/devmine/server/commands/defaults/OpCommand.php @@ -6,8 +6,8 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class OpCommand extends VanillaCommand{ @@ -15,10 +15,10 @@ class OpCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.op.description", + "%DevMine.command.op.description", "%commands.op.usage" ); - $this->setPermission("devmine.command.op.give"); + $this->setPermission("DevMine.command.op.give"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/PardonCidCommand.php b/src/devmine/server/commands/defaults/PardonCidCommand.php index 93ea153..833ee9f 100644 --- a/src/devmine/server/commands/defaults/PardonCidCommand.php +++ b/src/devmine/server/commands/defaults/PardonCidCommand.php @@ -1,9 +1,29 @@ setPermission("devmine.command.pardoncid"); + $this->setPermission("DevMine.command.pardoncid"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/PardonCommand.php b/src/devmine/server/commands/defaults/PardonCommand.php index 64debbf..14ad696 100644 --- a/src/devmine/server/commands/defaults/PardonCommand.php +++ b/src/devmine/server/commands/defaults/PardonCommand.php @@ -6,7 +6,7 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; class PardonCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class PardonCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.unban.player.description", + "%DevMine.command.unban.player.description", "%commands.unban.usage" ); - $this->setPermission("devmine.command.unban.player"); + $this->setPermission("DevMine.command.unban.player"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/PardonIpCommand.php b/src/devmine/server/commands/defaults/PardonIpCommand.php index e3e6ea9..24fe44e 100644 --- a/src/devmine/server/commands/defaults/PardonIpCommand.php +++ b/src/devmine/server/commands/defaults/PardonIpCommand.php @@ -6,7 +6,7 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; class PardonIpCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class PardonIpCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.unban.ip.description", + "%DevMine.command.unban.ip.description", "%commands.unbanip.usage" ); - $this->setPermission("devmine.command.unban.ip"); + $this->setPermission("DevMine.command.unban.ip"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/ParticleCommand.php b/src/devmine/server/commands/defaults/ParticleCommand.php index d427bcd..5ef0b02 100644 --- a/src/devmine/server/commands/defaults/ParticleCommand.php +++ b/src/devmine/server/commands/defaults/ParticleCommand.php @@ -6,37 +6,38 @@ use devmine\inventory\blocks\Block; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\inventory\items\Item; -use devmine\levels\particle\AngryVillagerParticle; -use devmine\levels\particle\BubbleParticle; -use devmine\levels\particle\CriticalParticle; -use devmine\levels\particle\DustParticle; -use devmine\levels\particle\EnchantmentTableParticle; -use devmine\levels\particle\EnchantParticle; -use devmine\levels\particle\ExplodeParticle; -use devmine\levels\particle\FlameParticle; -use devmine\levels\particle\HappyVillagerParticle; -use devmine\levels\particle\HeartParticle; -use devmine\levels\particle\HugeExplodeParticle; -use devmine\levels\particle\InkParticle; -use devmine\levels\particle\InstantEnchantParticle; -use devmine\levels\particle\ItemBreakParticle; -use devmine\levels\particle\LargeExplodeParticle; -use devmine\levels\particle\LavaDripParticle; -use devmine\levels\particle\LavaParticle; -use devmine\levels\particle\Particle; -use devmine\levels\particle\PortalParticle; -use devmine\levels\particle\RainSplashParticle; -use devmine\levels\particle\RedstoneParticle; -use devmine\levels\particle\SmokeParticle; -use devmine\levels\particle\SplashParticle; -use devmine\levels\particle\SporeParticle; -use devmine\levels\particle\TerrainParticle; -use devmine\levels\particle\WaterDripParticle; -use devmine\levels\particle\WaterParticle; +use devmine\worlds\particle\AngryVillagerParticle; +use devmine\worlds\particle\BubbleParticle; +use devmine\worlds\particle\BlockForceFieldParticle; +use devmine\worlds\particle\CriticalParticle; +use devmine\worlds\particle\DustParticle; +use devmine\worlds\particle\EnchantmentTableParticle; +use devmine\worlds\particle\EnchantParticle; +use devmine\worlds\particle\ExplodeParticle; +use devmine\worlds\particle\FlameParticle; +use devmine\worlds\particle\HappyVillagerParticle; +use devmine\worlds\particle\HeartParticle; +use devmine\worlds\particle\HugeExplodeParticle; +use devmine\worlds\particle\HugeExplodeSeedParticle; +use devmine\worlds\particle\InkParticle; +use devmine\worlds\particle\InstantEnchantParticle; +use devmine\worlds\particle\ItemBreakParticle; +use devmine\worlds\particle\LavaDripParticle; +use devmine\worlds\particle\LavaParticle; +use devmine\worlds\particle\Particle; +use devmine\worlds\particle\PortalParticle; +use devmine\worlds\particle\RainSplashParticle; +use devmine\worlds\particle\RedstoneParticle; +use devmine\worlds\particle\SmokeParticle; +use devmine\worlds\particle\SplashParticle; +use devmine\worlds\particle\SporeParticle; +use devmine\worlds\particle\TerrainParticle; +use devmine\worlds\particle\WaterDripParticle; +use devmine\worlds\particle\WaterParticle; use devmine\server\calculations\Vector3; -use devmine\Player; +use devmine\creatures\player; use devmine\utilities\main\Random; use devmine\utilities\main\TextFormat; @@ -45,10 +46,10 @@ class ParticleCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.particle.description", - "%devmine.command.particle.usage" + "%DevMine.command.particle.description", + "%DevMine.command.particle.usage" ); - $this->setPermission("devmine.command.particle"); + $this->setPermission("DevMine.command.particle"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -118,10 +119,10 @@ private function getParticle($name, Vector3 $pos, $xd, $yd, $zd, $data){ switch($name){ case "explode": return new ExplodeParticle($pos); - case "largeexplode": - return new LargeExplodeParticle($pos); case "hugeexplosion": return new HugeExplodeParticle($pos); + case "hugeexplosionseed": + return new HugeExplodeSeedParticle($pos); case "bubble": return new BubbleParticle($pos); case "splash": @@ -132,7 +133,7 @@ private function getParticle($name, Vector3 $pos, $xd, $yd, $zd, $data){ case "crit": return new CriticalParticle($pos); case "smoke": - return new SmokeParticle($pos, $data !== null ? $data : 0); + return new SmokeParticle($pos, $data ?? 0); case "spell": return new EnchantParticle($pos); case "instantspell": @@ -151,7 +152,7 @@ private function getParticle($name, Vector3 $pos, $xd, $yd, $zd, $data){ case "lava": return new LavaParticle($pos); case "reddust": - return new RedstoneParticle($pos, $data !== null ? $data : 1); + return new RedstoneParticle($pos, $data ?? 1); case "snowballpoof": return new ItemBreakParticle($pos, Item::get(Item::SNOWBALL)); case "slime": @@ -167,9 +168,9 @@ private function getParticle($name, Vector3 $pos, $xd, $yd, $zd, $data){ } break; case "heart": - return new HeartParticle($pos, $data !== null ? $data : 0); + return new HeartParticle($pos, $data ?? 0); case "ink": - return new InkParticle($pos, $data !== null ? $data : 0); + return new InkParticle($pos, $data ?? 0); case "droplet": return new RainSplashParticle($pos); case "enchantmenttable": @@ -178,6 +179,8 @@ private function getParticle($name, Vector3 $pos, $xd, $yd, $zd, $data){ return new HappyVillagerParticle($pos); case "angryvillager": return new AngryVillagerParticle($pos); + case "forcefield": + return new BlockForceFieldParticle($pos, $data ?? 0); } diff --git a/src/devmine/server/commands/defaults/PluginsCommand.php b/src/devmine/server/commands/defaults/PluginsCommand.php index a84ae44..e3a7995 100644 --- a/src/devmine/server/commands/defaults/PluginsCommand.php +++ b/src/devmine/server/commands/defaults/PluginsCommand.php @@ -5,7 +5,7 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\utilities\main\TextFormat; class PluginsCommand extends VanillaCommand{ @@ -13,11 +13,11 @@ class PluginsCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.plugins.description", - "%devmine.command.plugins.usage", + "%DevMine.command.plugins.description", + "%DevMine.command.plugins.usage", ["pl"] ); - $this->setPermission("devmine.command.plugins"); + $this->setPermission("DevMine.command.plugins"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -38,6 +38,6 @@ private function sendPluginList(CommandSender $sender){ $list .= $plugin->getDescription()->getFullName(); } - $sender->sendMessage(new TranslationContainer("devmine.command.plugins.success", [count($plugins), $list])); + $sender->sendMessage(new TranslationContainer("DevMine.command.plugins.success", [count($plugins), $list])); } } diff --git a/src/devmine/server/commands/defaults/ReloadCommand.php b/src/devmine/server/commands/defaults/ReloadCommand.php index b3cde45..9efd217 100644 --- a/src/devmine/server/commands/defaults/ReloadCommand.php +++ b/src/devmine/server/commands/defaults/ReloadCommand.php @@ -6,7 +6,7 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\utilities\main\TextFormat; class ReloadCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class ReloadCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.reload.description", - "%devmine.command.reload.usage" + "%DevMine.command.reload.description", + "%DevMine.command.reload.usage" ); - $this->setPermission("devmine.command.reload"); + $this->setPermission("DevMine.command.reload"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -25,10 +25,10 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ return true; } - Command::broadcastCommandMessage($sender, new TranslationContainer(TextFormat::YELLOW . "%devmine.command.reload.reloading")); + Command::broadcastCommandMessage($sender, new TranslationContainer(TextFormat::YELLOW . "%DevMine.command.reload.reloading")); $sender->getServer()->reload(); - Command::broadcastCommandMessage($sender, new TranslationContainer(TextFormat::YELLOW . "%devmine.command.reload.reloaded")); + Command::broadcastCommandMessage($sender, new TranslationContainer(TextFormat::YELLOW . "%DevMine.command.reload.reloaded")); return true; } diff --git a/src/devmine/server/commands/defaults/SaveCommand.php b/src/devmine/server/commands/defaults/SaveCommand.php index 5a82e17..bde68ba 100644 --- a/src/devmine/server/commands/defaults/SaveCommand.php +++ b/src/devmine/server/commands/defaults/SaveCommand.php @@ -6,7 +6,7 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; class SaveCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class SaveCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.save.description", + "%DevMine.command.save.description", "%commands.save.usage" ); - $this->setPermission("devmine.command.save.perform"); + $this->setPermission("DevMine.command.save.perform"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/SaveOffCommand.php b/src/devmine/server/commands/defaults/SaveOffCommand.php index a74e36a..25c555c 100644 --- a/src/devmine/server/commands/defaults/SaveOffCommand.php +++ b/src/devmine/server/commands/defaults/SaveOffCommand.php @@ -6,7 +6,7 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; class SaveOffCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class SaveOffCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.saveoff.description", + "%DevMine.command.saveoff.description", "%commands.save-off.usage" ); - $this->setPermission("devmine.command.save.disable"); + $this->setPermission("DevMine.command.save.disable"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/SaveOnCommand.php b/src/devmine/server/commands/defaults/SaveOnCommand.php index 7f43c25..984d442 100644 --- a/src/devmine/server/commands/defaults/SaveOnCommand.php +++ b/src/devmine/server/commands/defaults/SaveOnCommand.php @@ -6,7 +6,7 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; class SaveOnCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class SaveOnCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.saveon.description", + "%DevMine.command.saveon.description", "%commands.save-on.usage" ); - $this->setPermission("devmine.command.save.enable"); + $this->setPermission("DevMine.command.save.enable"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/SayCommand.php b/src/devmine/server/commands/defaults/SayCommand.php index d7c3798..b84a076 100644 --- a/src/devmine/server/commands/defaults/SayCommand.php +++ b/src/devmine/server/commands/defaults/SayCommand.php @@ -6,8 +6,8 @@ use devmine\server\commands\CommandSender; use devmine\server\commands\ConsoleCommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class SayCommand extends VanillaCommand{ @@ -15,11 +15,11 @@ class SayCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.say.description", + "%DevMine.command.say.description", "%commands.say.usage", ["broadcast", "announce"] ); - $this->setPermission("devmine.command.say"); + $this->setPermission("DevMine.command.say"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/SeedCommand.php b/src/devmine/server/commands/defaults/SeedCommand.php index 20869bd..a21b3a5 100644 --- a/src/devmine/server/commands/defaults/SeedCommand.php +++ b/src/devmine/server/commands/defaults/SeedCommand.php @@ -5,8 +5,8 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; class SeedCommand extends VanillaCommand{ @@ -14,10 +14,10 @@ class SeedCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.seed.description", + "%DevMine.command.seed.description", "%commands.seed.usage" ); - $this->setPermission("devmine.command.seed"); + $this->setPermission("DevMine.command.seed"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/SetBlockCommand.php b/src/devmine/server/commands/defaults/SetBlockCommand.php index e3deed7..d2a4c98 100644 --- a/src/devmine/server/commands/defaults/SetBlockCommand.php +++ b/src/devmine/server/commands/defaults/SetBlockCommand.php @@ -5,24 +5,24 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; use devmine\server\calculations\Vector3; use devmine\inventory\blocks\Block; use devmine\inventory\items\ItemBlock; use devmine\inventory\items\Item; -use devmine\levels\Level; +use devmine\worlds\Level; class SetBlockCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.setblock.description", + "%DevMine.command.setblock.description", "%commands.setblock.usage" ); - $this->setPermission("devmine.command.setblock"); + $this->setPermission("DevMine.command.setblock"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/SetWorldSpawnCommand.php b/src/devmine/server/commands/defaults/SetWorldSpawnCommand.php index b055e33..0525fc7 100644 --- a/src/devmine/server/commands/defaults/SetWorldSpawnCommand.php +++ b/src/devmine/server/commands/defaults/SetWorldSpawnCommand.php @@ -6,9 +6,9 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\server\calculations\Vector3; -use devmine\Player; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class SetWorldSpawnCommand extends VanillaCommand{ @@ -16,11 +16,11 @@ class SetWorldSpawnCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.setworldspawn.description", + "%DevMine.command.setworldspawn.description", "%commands.setworldspawn.usage", ["setspawn"] ); - $this->setPermission("devmine.command.setworldspawn"); + $this->setPermission("DevMine.command.setworldspawn"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/SpawnpointCommand.php b/src/devmine/server/commands/defaults/SpawnpointCommand.php index 187d3a9..f588c76 100644 --- a/src/devmine/server/commands/defaults/SpawnpointCommand.php +++ b/src/devmine/server/commands/defaults/SpawnpointCommand.php @@ -6,9 +6,9 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\levels\Position; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\worlds\Position; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class SpawnpointCommand extends VanillaCommand{ @@ -16,10 +16,10 @@ class SpawnpointCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.spawnpoint.description", + "%DevMine.command.spawnpoint.description", "%commands.spawnpoint.usage" ); - $this->setPermission("devmine.command.spawnpoint"); + $this->setPermission("DevMine.command.spawnpoint"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/StatusCommand.php b/src/devmine/server/commands/defaults/StatusCommand.php index 4d52887..e4c8056 100644 --- a/src/devmine/server/commands/defaults/StatusCommand.php +++ b/src/devmine/server/commands/defaults/StatusCommand.php @@ -5,7 +5,7 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\Player; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; use devmine\utilities\main\Utils; @@ -14,10 +14,10 @@ class StatusCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.status.description", - "%devmine.command.status.usage" + "%DevMine.command.status.description", + "%DevMine.command.status.usage" ); - $this->setPermission("devmine.command.status"); + $this->setPermission("DevMine.command.status"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -35,10 +35,10 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ ++$onlineCount; } } - $sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "%devmine.command.status.title" . TextFormat::GREEN . " ----"); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.player" . TextFormat::GREEN ." ". $onlineCount . "/" . $sender->getServer()->getMaxPlayers()); + $sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "%DevMine.command.status.title" . TextFormat::GREEN . " ----"); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.player" . TextFormat::GREEN ." ". $onlineCount . "/" . $sender->getServer()->getMaxPlayers()); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.uptime " . TextFormat::RED . $sender->getServer()->getUptime()); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.uptime " . TextFormat::RED . $sender->getServer()->getUptime()); $tpsColor = TextFormat::GREEN; if($server->getTicksPerSecondAverage() < 10){ @@ -54,29 +54,29 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ $tpsColour = TextFormat::RED; } - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.AverageTPS " . $tpsColor . $server->getTicksPerSecondAverage() . " (" . $server->getTickUsageAverage() . "%)"); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.CurrentTPS " . $tpsColour . $server->getTicksPerSecond() . " (" . $server->getTickUsage() . "%)"); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.AverageTPS " . $tpsColor . $server->getTicksPerSecondAverage() . " (" . $server->getTickUsageAverage() . "%)"); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.CurrentTPS " . $tpsColour . $server->getTicksPerSecond() . " (" . $server->getTickUsage() . "%)"); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.Networkupload " . TextFormat::RED . \round($server->getNetwork()->getUpload() / 1024, 2) . " kB/s"); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.Networkdownload " . TextFormat::RED . \round($server->getNetwork()->getDownload() / 1024, 2) . " kB/s"); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.Networkupload " . TextFormat::RED . \round($server->getNetwork()->getUpload() / 1024, 2) . " kB/s"); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.Networkdownload " . TextFormat::RED . \round($server->getNetwork()->getDownload() / 1024, 2) . " kB/s"); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.Threadcount " . TextFormat::RED . Utils::getThreadCount()); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.Threadcount " . TextFormat::RED . Utils::getThreadCount()); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.Mainmemory " . TextFormat::RED . number_format(round(($mUsage[0] / 1024) / 1024, 2)) . " MB."); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.Totalmemory " . TextFormat::RED . number_format(round(($mUsage[1] / 1024) / 1024, 2)) . " MB."); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.Totalvirtualmemory " . TextFormat::RED . number_format(round(($mUsage[2] / 1024) / 1024, 2)) . " MB."); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.Heapmemory " . TextFormat::RED . number_format(round(($rUsage[0] / 1024) / 1024, 2)) . " MB."); - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.Maxmemorysystem " . TextFormat::RED . number_format(round(($mUsage[2] / 1024) / 1024, 2)) . " MB."); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.Mainmemory " . TextFormat::RED . number_format(round(($mUsage[0] / 1024) / 1024, 2)) . " MB."); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.Totalmemory " . TextFormat::RED . number_format(round(($mUsage[1] / 1024) / 1024, 2)) . " MB."); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.Totalvirtualmemory " . TextFormat::RED . number_format(round(($mUsage[2] / 1024) / 1024, 2)) . " MB."); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.Heapmemory " . TextFormat::RED . number_format(round(($rUsage[0] / 1024) / 1024, 2)) . " MB."); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.Maxmemorysystem " . TextFormat::RED . number_format(round(($mUsage[2] / 1024) / 1024, 2)) . " MB."); if($server->getProperty("memory.global-limit") > 0){ - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.Maxmemorymanager " . TextFormat::RED . number_format(round($server->getProperty("memory.global-limit"), 2)) . " MB."); + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.Maxmemorymanager " . TextFormat::RED . number_format(round($server->getProperty("memory.global-limit"), 2)) . " MB."); } foreach($server->getLevels() as $level){ - $sender->sendMessage(TextFormat::GOLD . "%devmine.command.status.World \"" . $level->getFolderName() . "\"" . ($level->getFolderName() !== $level->getName() ? " (" . $level->getName() . ")" : "") . ": " . - TextFormat::RED . number_format(count($level->getChunks())) . TextFormat::GREEN . " %devmine.command.status.chunks " . - TextFormat::RED . number_format(count($level->getEntities())) . TextFormat::GREEN . " %devmine.command.status.entities " . - TextFormat::RED . number_format(count($level->getsolidentities())) . TextFormat::GREEN . " %devmine.command.status.solidentities " . - "%devmine.command.status.Time " . (($level->getTickRate() > 1 or $level->getTickRateTime() > 40) ? TextFormat::RED : TextFormat::YELLOW) . round($level->getTickRateTime(), 2) . "%devmine.command.status.ms" . ($level->getTickRate() > 1 ? " (tick rate " . $level->getTickRate() . ")" : "") + $sender->sendMessage(TextFormat::GOLD . "%DevMine.command.status.World \"" . $level->getFolderName() . "\"" . ($level->getFolderName() !== $level->getName() ? " (" . $level->getName() . ")" : "") . ": " . + TextFormat::RED . number_format(count($level->getChunks())) . TextFormat::GREEN . " %DevMine.command.status.chunks " . + TextFormat::RED . number_format(count($level->getEntities())) . TextFormat::GREEN . " %DevMine.command.status.entities " . + TextFormat::RED . number_format(count($level->getTiles())) . TextFormat::GREEN . " %DevMine.command.status.tiles " . + "%DevMine.command.status.Time " . (($level->getTickRate() > 1 or $level->getTickRateTime() > 40) ? TextFormat::RED : TextFormat::YELLOW) . round($level->getTickRateTime(), 2) . "%DevMine.command.status.ms" . ($level->getTickRate() > 1 ? " (tick rate " . $level->getTickRate() . ")" : "") ); } diff --git a/src/devmine/server/commands/defaults/StopCommand.php b/src/devmine/server/commands/defaults/StopCommand.php index ea22c31..b050493 100644 --- a/src/devmine/server/commands/defaults/StopCommand.php +++ b/src/devmine/server/commands/defaults/StopCommand.php @@ -6,7 +6,7 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; class StopCommand extends VanillaCommand{ @@ -14,33 +14,27 @@ class StopCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.stop.description", + "%DevMine.command.stop.description", "%commands.stop.usage" ); - $this->setPermission("devmine.command.stop"); + $this->setPermission("DevMine.command.stop"); } public function execute(CommandSender $sender, $currentAlias, array $args){ if(!$this->testPermission($sender)){ return true; } - - $msg = ""; - if(isset($args[0])){ - $msg = $args[0]; - } - $restart = false; - if(isset($args[1])){ + if(isset($args[0])){ if($args[0] == 'force'){ $restart = true; + array_shift($args); }else{ $restart = false; } } - Command::broadcastCommandMessage($sender, new TranslationContainer("commands.stop.start")); - + $msg = implode(" ", $args); $sender->getServer()->shutdown($restart, $msg); return true; diff --git a/src/devmine/server/commands/defaults/SummonCommand.php b/src/devmine/server/commands/defaults/SummonCommand.php index 43d78ba..316fc28 100644 --- a/src/devmine/server/commands/defaults/SummonCommand.php +++ b/src/devmine/server/commands/defaults/SummonCommand.php @@ -1,18 +1,30 @@ setPermission("devmine.command.summon"); + $this->setPermission("DevMine.command.summon"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -110,7 +122,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ $entity = null; $type = $args[0]; $level = ($sender instanceof Player) ? $sender->getLevel() : $sender->getServer()->getDefaultLevel(); - $chunk = $level->getChunk(round($x) >> 4, round($z) >> 4); + $chunk = $level->getChunk($x >> 4, $z >> 4, true); $nbt = new CompoundTag("", [ "Pos" => new ListTag("Pos", [ new DoubleTag("", $x), diff --git a/src/devmine/server/commands/defaults/TeleportCommand.php b/src/devmine/server/commands/defaults/TeleportCommand.php index b417c60..5fa0658 100644 --- a/src/devmine/server/commands/defaults/TeleportCommand.php +++ b/src/devmine/server/commands/defaults/TeleportCommand.php @@ -6,9 +6,9 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\server\calculations\Vector3; -use devmine\Player; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class TeleportCommand extends VanillaCommand{ @@ -16,10 +16,10 @@ class TeleportCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.tp.description", + "%DevMine.command.tp.description", "%commands.tp.usage" ); - $this->setPermission("devmine.command.teleport"); + $this->setPermission("DevMine.command.teleport"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -83,7 +83,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ } $x = $this->getRelativeDouble($target->x, $sender, $args[$pos++]); - $y = $this->getRelativeDouble($target->y, $sender, $args[$pos++], 0, 128); + $y = $this->getRelativeDouble($target->y, $sender, $args[$pos++], 0, 256); $z = $this->getRelativeDouble($target->z, $sender, $args[$pos++]); $yaw = $target->getYaw(); $pitch = $target->getPitch(); diff --git a/src/devmine/server/commands/defaults/TellCommand.php b/src/devmine/server/commands/defaults/TellCommand.php index 6082df8..d64f93f 100644 --- a/src/devmine/server/commands/defaults/TellCommand.php +++ b/src/devmine/server/commands/defaults/TellCommand.php @@ -5,8 +5,8 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class TellCommand extends VanillaCommand{ @@ -14,11 +14,11 @@ class TellCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.tell.description", + "%DevMine.command.tell.description", "%commands.message.usage", ["w", "whisper", "msg", "m"] ); - $this->setPermission("devmine.command.tell"); + $this->setPermission("DevMine.command.tell"); } public function execute(CommandSender $sender, $currentAlias, array $args){ diff --git a/src/devmine/server/commands/defaults/TimeCommand.php b/src/devmine/server/commands/defaults/TimeCommand.php index 1cc14eb..936f356 100644 --- a/src/devmine/server/commands/defaults/TimeCommand.php +++ b/src/devmine/server/commands/defaults/TimeCommand.php @@ -6,9 +6,9 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; -use devmine\levels\Level; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\worlds\Level; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class TimeCommand extends VanillaCommand{ @@ -16,10 +16,10 @@ class TimeCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.time.description", - "%devmine.command.time.usage" + "%DevMine.command.time.description", + "%DevMine.command.time.usage" ); - $this->setPermission("devmine.command.time.add;devmine.command.time.set;devmine.command.time.start;devmine.command.time.stop"); + $this->setPermission("DevMine.command.time.add;DevMine.command.time.set;DevMine.command.time.start;DevMine.command.time.stop"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -30,7 +30,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ } if($args[0] === "start"){ - if(!$sender->hasPermission("devmine.command.time.start")){ + if(!$sender->hasPermission("DevMine.command.time.start")){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission")); return true; @@ -43,7 +43,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ Command::broadcastCommandMessage($sender, "Restarted the time"); return true; }elseif($args[0] === "stop"){ - if(!$sender->hasPermission("devmine.command.time.stop")){ + if(!$sender->hasPermission("DevMine.command.time.stop")){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission")); return true; @@ -56,7 +56,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ Command::broadcastCommandMessage($sender, "Stopped the time"); return true; }elseif($args[0] === "query"){ - if(!$sender->hasPermission("devmine.command.time.query")){ + if(!$sender->hasPermission("DevMine.command.time.query")){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission")); return true; @@ -78,7 +78,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ } if($args[0] === "set"){ - if(!$sender->hasPermission("devmine.command.time.set")){ + if(!$sender->hasPermission("DevMine.command.time.set")){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission")); return true; @@ -99,7 +99,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ } Command::broadcastCommandMessage($sender, new TranslationContainer("commands.time.set", [$value])); }elseif($args[0] === "add"){ - if(!$sender->hasPermission("devmine.command.time.add")){ + if(!$sender->hasPermission("DevMine.command.time.add")){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission")); return true; diff --git a/src/devmine/server/commands/defaults/TimingsCommand.php b/src/devmine/server/commands/defaults/TimingsCommand.php index c6c377c..659e91b 100644 --- a/src/devmine/server/commands/defaults/TimingsCommand.php +++ b/src/devmine/server/commands/defaults/TimingsCommand.php @@ -5,8 +5,8 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\server\events\TimingsHandler; -use devmine\server\events\TranslationContainer; +use devmine\events\TimingsHandler; +use devmine\events\TranslationContainer; class TimingsCommand extends VanillaCommand{ @@ -16,10 +16,10 @@ class TimingsCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.timings.description", - "%devmine.command.timings.usage" + "%DevMine.command.timings.description", + "%DevMine.command.timings.usage" ); - $this->setPermission("devmine.command.timings"); + $this->setPermission("DevMine.command.timings"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -38,17 +38,17 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ if($mode === "on"){ $sender->getServer()->getPluginManager()->setUseTimings(true); TimingsHandler::reload(); - $sender->sendMessage(new TranslationContainer("devmine.command.timings.enable")); + $sender->sendMessage(new TranslationContainer("DevMine.command.timings.enable")); return true; }elseif($mode === "off"){ $sender->getServer()->getPluginManager()->setUseTimings(false); - $sender->sendMessage(new TranslationContainer("devmine.command.timings.disable")); + $sender->sendMessage(new TranslationContainer("DevMine.command.timings.disable")); return true; } if(!$sender->getServer()->getPluginManager()->useTimings()){ - $sender->sendMessage(new TranslationContainer("devmine.command.timings.timingsDisabled")); + $sender->sendMessage(new TranslationContainer("DevMine.command.timings.timingsDisabled")); return true; } @@ -57,7 +57,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ if($mode === "reset"){ TimingsHandler::reload(); - $sender->sendMessage(new TranslationContainer("devmine.command.timings.reset")); + $sender->sendMessage(new TranslationContainer("DevMine.command.timings.reset")); }elseif($mode === "merged" or $mode === "report" or $paste){ $sampleTime = microtime(true) - self::$timingStart; @@ -96,23 +96,23 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ curl_setopt($ch, CURLOPT_AUTOREFERER, false); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); curl_setopt($ch, CURLOPT_HEADER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, ["User-Agent: " . $this->getName() . " " . $sender->getServer()->getdevmineVersion()]); + curl_setopt($ch, CURLOPT_HTTPHEADER, ["User-Agent: " . $this->getName() . " " . $sender->getServer()->getDevMineVersion()]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $data = curl_exec($ch); curl_close($ch); if(preg_match('#^Location: http://paste\\.ubuntu\\.com/([0-9]{1,})/#m', $data, $matches) == 0){ - $sender->sendMessage(new TranslationContainer("devmine.command.timings.pasteError")); + $sender->sendMessage(new TranslationContainer("DevMine.command.timings.pasteError")); return true; } - $sender->sendMessage(new TranslationContainer("devmine.command.timings.timingsUpload", ["http://paste.ubuntu.com/" . $matches[1] . "/"])); - $sender->sendMessage(new TranslationContainer("devmine.command.timings.timingsRead", ["http://timings.aikar.co/?url=" . $matches[1]])); + $sender->sendMessage(new TranslationContainer("DevMine.command.timings.timingsUpload", ["http://paste.ubuntu.com/" . $matches[1] . "/"])); + $sender->sendMessage(new TranslationContainer("DevMine.command.timings.timingsRead", ["http://timings.aikar.co/?url=" . $matches[1]])); fclose($fileTimings); }else{ fclose($fileTimings); - $sender->sendMessage(new TranslationContainer("devmine.command.timings.timingsWrite", [$timings])); + $sender->sendMessage(new TranslationContainer("DevMine.command.timings.timingsWrite", [$timings])); } } diff --git a/src/devmine/server/commands/defaults/VersionCommand.php b/src/devmine/server/commands/defaults/VersionCommand.php index a931ce1..2c63134 100644 --- a/src/devmine/server/commands/defaults/VersionCommand.php +++ b/src/devmine/server/commands/defaults/VersionCommand.php @@ -5,9 +5,9 @@ namespace devmine\server\commands\defaults; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\server\network\protocol\Info; -use devmine\pluginfeatures\Plugin; +use devmine\consumer\plugin\Plugin; use devmine\utilities\main\TextFormat; class VersionCommand extends VanillaCommand{ @@ -15,11 +15,11 @@ class VersionCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.version.description", - "%devmine.command.version.usage", + "%DevMine.command.version.description", + "%DevMine.command.version.usage", ["ver", "about"] ); - $this->setPermission("devmine.command.version"); + $this->setPermission("DevMine.command.version"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -28,14 +28,24 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ } if(\count($args) === 0){ - $sender->sendMessage(new TranslationContainer("devmine.server.info.extended", [ - $sender->getServer()->getName(), - $sender->getServer()->getdevmineVersion(), - $sender->getServer()->getCodename(), - $sender->getServer()->getApiVersion(), - $sender->getServer()->getVersion(), - Info::CURRENT_PROTOCOL, - $sender->getServer()->getiTXApiVersion() + $sender->sendMessage(new TranslationContainer("DevMine.server.info.extended.title")); + $sender->sendMessage(new TranslationContainer("DevMine.server.info.extended1", [ + $sender->getServer()->getName(), + $sender->getServer()->getFormattedVersion("-"), + $sender->getServer()->getCodename() + ])); + $sender->sendMessage(new TranslationContainer("DevMine.server.info.extended2", [ + phpversion() + ])); + $sender->sendMessage(new TranslationContainer("DevMine.server.info.extended3", [ + $sender->getServer()->getApiVersion() + + ])); + $sender->sendMessage(new TranslationContainer("DevMine.server.info.extended4", [ + $sender->getServer()->getVersion() + ])); + $sender->sendMessage(new TranslationContainer("DevMine.server.info.extended5", [ + Info::CURRENT_PROTOCOL ])); }else{ $pluginName = \implode(" ", $args); @@ -57,7 +67,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ } if(!$found){ - $sender->sendMessage(new TranslationContainer("devmine.command.version.noSuchPlugin")); + $sender->sendMessage(new TranslationContainer("DevMine.command.version.noSuchPlugin")); } } diff --git a/src/devmine/server/commands/defaults/WeatherCommand.php b/src/devmine/server/commands/defaults/WeatherCommand.php index 5cfa83b..be417ba 100644 --- a/src/devmine/server/commands/defaults/WeatherCommand.php +++ b/src/devmine/server/commands/defaults/WeatherCommand.php @@ -1,14 +1,31 @@ setPermission("devmine.command.weather"); + $this->setPermission("DevMine.command.weather"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -39,30 +56,30 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ else $duration = (int) $args[1]; if($wea >= 0 and $wea <= 3){ $sender->getLevel()->getWeather()->setWeather($wea, $duration); - $sender->sendMessage(new TranslationContainer("devmine.command.weather.changed", [$sender->getLevel()->getFolderName()])); + $sender->sendMessage(new TranslationContainer("DevMine.command.weather.changed", [$sender->getLevel()->getFolderName()])); return true; /*if(WeatherManager::isRegistered($sender->getLevel())){ $sender->getLevel()->getWeather()->setWeather($wea, $duration); - $sender->sendMessage(new TranslationContainer("devmine.command.weather.changed", [$sender->getLevel()->getFolderName()])); + $sender->sendMessage(new TranslationContainer("DevMine.command.weather.changed", [$sender->getLevel()->getFolderName()])); return true; }else{ - $sender->sendMessage(new TranslationContainer("devmine.command.weather.noregistered", [$sender->getLevel()->getFolderName()])); + $sender->sendMessage(new TranslationContainer("DevMine.command.weather.noregistered", [$sender->getLevel()->getFolderName()])); return false; }*/ }else{ - $sender->sendMessage(TextFormat::RED . "%devmine.command.weather.invalid"); + $sender->sendMessage(TextFormat::RED . "%DevMine.command.weather.invalid"); return false; } } if(count($args) < 2){ - $sender->sendMessage(TextFormat::RED . "%devmine.command.weather.wrong"); + $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); return false; } $level = $sender->getServer()->getLevelByName($args[0]); if(!$level instanceof Level){ - $sender->sendMessage(TextFormat::RED . "%devmine.command.weather.invalid.level"); + $sender->sendMessage(TextFormat::RED . "%DevMine.command.weather.invalid.level"); return false; } @@ -71,18 +88,18 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ else $duration = (int) $args[1]; if($wea >= 0 and $wea <= 3){ $level->getWeather()->setWeather($wea, $duration); - $sender->sendMessage(new TranslationContainer("devmine.command.weather.changed", [$level->getFolderName()])); + $sender->sendMessage(new TranslationContainer("DevMine.command.weather.changed", [$level->getFolderName()])); return true; /*if(WeatherManager::isRegistered($level)){ $level->getWeather()->setWeather($wea, $duration); - $sender->sendMessage(new TranslationContainer("devmine.command.weather.changed", [$level->getFolderName()])); + $sender->sendMessage(new TranslationContainer("DevMine.command.weather.changed", [$level->getFolderName()])); return true; }else{ - $sender->sendMessage(new TranslationContainer("devmine.command.weather.noregistered", [$level->getFolderName()])); + $sender->sendMessage(new TranslationContainer("DevMine.command.weather.noregistered", [$level->getFolderName()])); return false; }*/ }else{ - $sender->sendMessage(TextFormat::RED . "%devmine.command.weather.invalid"); + $sender->sendMessage(TextFormat::RED . "%DevMine.command.weather.invalid"); return false; } } diff --git a/src/devmine/server/commands/defaults/WhitelistCommand.php b/src/devmine/server/commands/defaults/WhitelistCommand.php index ba22423..92af30d 100644 --- a/src/devmine/server/commands/defaults/WhitelistCommand.php +++ b/src/devmine/server/commands/defaults/WhitelistCommand.php @@ -6,7 +6,7 @@ use devmine\server\commands\Command; use devmine\server\commands\CommandSender; -use devmine\server\events\TranslationContainer; +use devmine\events\TranslationContainer; use devmine\utilities\main\TextFormat; class WhitelistCommand extends VanillaCommand{ @@ -14,11 +14,11 @@ class WhitelistCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.whitelist.description", + "%DevMine.command.whitelist.description", "%commands.whitelist.usage", ["wl"] ); - $this->setPermission("devmine.command.whitelist.reload;devmine.command.whitelist.enable;devmine.command.whitelist.disable;devmine.command.whitelist.list;devmine.command.whitelist.add;devmine.command.whitelist.remove"); + $this->setPermission("DevMine.command.whitelist.reload;DevMine.command.whitelist.enable;DevMine.command.whitelist.disable;DevMine.command.whitelist.list;DevMine.command.whitelist.add;DevMine.command.whitelist.remove"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -93,7 +93,7 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ } private function badPerm(CommandSender $sender, $perm){ - if(!$sender->hasPermission("devmine.command.whitelist.$perm")){ + if(!$sender->hasPermission("DevMine.command.whitelist.$perm")){ $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.permission")); return true; diff --git a/src/devmine/server/commands/defaults/XpCommand.php b/src/devmine/server/commands/defaults/XpCommand.php index 132606c..3e42f42 100644 --- a/src/devmine/server/commands/defaults/XpCommand.php +++ b/src/devmine/server/commands/defaults/XpCommand.php @@ -6,8 +6,9 @@ use devmine\server\commands\CommandSender; use devmine\server\commands\ConsoleCommandSender; -use devmine\server\events\TranslationContainer; -use devmine\Player; +use devmine\events\TranslationContainer; +use devmine\worlds\sound\ExpPickupSound; +use devmine\creatures\player; use devmine\utilities\main\TextFormat; class XpCommand extends VanillaCommand{ @@ -15,10 +16,10 @@ class XpCommand extends VanillaCommand{ public function __construct($name){ parent::__construct( $name, - "%devmine.command.xp.description", + "%DevMine.command.xp.description", "%commands.xp.usage" ); - $this->setPermission("devmine.command.xp"); + $this->setPermission("DevMine.command.xp"); } public function execute(CommandSender $sender, $currentAlias, array $args){ @@ -26,30 +27,50 @@ public function execute(CommandSender $sender, $currentAlias, array $args){ return true; } - if(count($args) != 2){ - $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); - return false; + if(count($args) < 2){ + if($sender instanceof ConsoleCommandSender){ + $sender->sendMessage("You must specify a target player in the console"); + return true; + } + $player = $sender; }else{ $player = $sender->getServer()->getPlayer($args[1]); - if($player instanceof Player){ - $name = $player->getName(); - if(strcasecmp(substr($args[0], -1), "L") == 0){ //Set Experience Level(with "L" after args[0]) - $level = rtrim($args[0], "Ll"); - if(is_numeric($level)){ - $player->addExpLevel($level); - $sender->sendMessage("Successfully added $level Level of experience to $name"); - } - }elseif(is_numeric($args[0])){ //Set Experience - $player->addExperience($args[0]); - $sender->sendMessage("Successfully added $args[0] of experience to $name"); - }else{ - $sender->sendMessage("Argument error"); - return false; + } + if($player instanceof Player){ + $name = $player->getName(); + if(count($args) < 1){ + $player->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); + return false; + } + if(strcasecmp(substr($args[0], -1), "L") == 0){ //Set Experience Level(with "L" after args[0]) + $level = (int) rtrim($args[0], "Ll"); + if($level > 0){ + $player->addXpLevel((int) $level); + $sender->sendMessage(new TranslationContainer("%commands.xp.success.levels", [$level, $name])); + $player->getLevel()->addSound(new ExpPickupSound($player, mt_rand(0, 1000))); //TODO: Find the level-up sound + return true; + }elseif($level < 0){ + $player->takeXpLevel((int) -$level); + $sender->sendMessage(new TranslationContainer("%commands.xp.success.negative.levels", [-$level, $name])); + return true; } }else{ - $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound")); - return false; + if(($xp = (int) $args[0]) > 0){ //Set Experience + $player->addXp((int) $args[0]); + $player->getLevel()->addSound(new ExpPickupSound($player, mt_rand(0, 1000))); + $sender->sendMessage(new TranslationContainer("%commands.xp.success", [$name, $args[0]])); + return true; + }elseif($xp < 0){ //Stupid, but this lines up with vanilla behaviour, so... + $sender->sendMessage(new TranslationContainer("%commands.xp.failure.withdrawXp")); + return true; + } } + //This statement will only be reached if the command failed + $sender->sendMessage(new TranslationContainer("commands.generic.usage", [$this->usageMessage])); + return false; + }else{ + $sender->sendMessage(new TranslationContainer(TextFormat::RED . "%commands.generic.player.notFound")); + return false; } return false; } diff --git a/src/devmine/server/epilogos/EntityMetadataStore.php b/src/devmine/server/epilogos/EntityMetadataStore.php deleted file mode 100644 index c7c76a0..0000000 --- a/src/devmine/server/epilogos/EntityMetadataStore.php +++ /dev/null @@ -1,18 +0,0 @@ -getId() . ":" . $epilogosKey; - } -} \ No newline at end of file diff --git a/src/devmine/server/epilogos/EpilogosStore.php b/src/devmine/server/epilogos/EpilogosStore.php deleted file mode 100644 index c08bb0b..0000000 --- a/src/devmine/server/epilogos/EpilogosStore.php +++ /dev/null @@ -1,123 +0,0 @@ -getOwningPlugin(); - if($owningPlugin === null){ - throw new PluginException("Plugin cannot be null"); - } - - $key = $this->disambiguate($subject, $epilogosKey); - if(!isset($this->epilogosMap[$key])){ - //$entry = new \WeakMap(); - $this->epilogosMap[$key] = new \SplObjectStorage();//$entry; - }else{ - $entry = $this->epilogosMap[$key]; - } - $entry[$owningPlugin] = $newepilogosValue; - } - - /** - * Returns all epilogos values attached to an object. If multiple - * have attached epilogos, each will value will be included. - * - * @param mixed $subject - * @param string $epilogosKey - * - * @return epilogosValue[] - * - * @throws \Exception - */ - public function getepilogos($subject, $epilogosKey){ - $key = $this->disambiguate($subject, $epilogosKey); - if(isset($this->epilogosMap[$key])){ - return $this->epilogosMap[$key]; - }else{ - return []; - } - } - - /** - * Tests to see if a epilogos attribute has been set on an object. - * - * @param mixed $subject - * @param string $epilogosKey - * - * @return bool - * - * @throws \Exception - */ - public function hasepilogos($subject, $epilogosKey){ - return isset($this->epilogosMap[$this->disambiguate($subject, $epilogosKey)]); - } - - /** - * Removes a epilogos item owned by a plugin from a subject. - * - * @param mixed $subject - * @param string $epilogosKey - * @param Plugin $owningPlugin - * - * @throws \Exception - */ - public function removeepilogos($subject, $epilogosKey, Plugin $owningPlugin){ - $key = $this->disambiguate($subject, $epilogosKey); - if(isset($this->epilogosMap[$key])){ - unset($this->epilogosMap[$key][$owningPlugin]); - if($this->epilogosMap[$key]->count() === 0){ - unset($this->epilogosMap[$key]); - } - } - } - - /** - * Invalidates all epilogos in the epilogos store that originates from the - * given plugin. Doing this will force each invalidated epilogos item to - * be recalculated the next time it is accessed. - * - * @param Plugin $owningPlugin - */ - public function invalidateAll(Plugin $owningPlugin){ - /** @var $values epilogosValue[] */ - foreach($this->epilogosMap as $values){ - if(isset($values[$owningPlugin])){ - $values[$owningPlugin]->invalidate(); - } - } - } - - /** - * Creates a unique name for the object receiving epilogos by combining - * unique data from the subject with a epilogosKey. - * - * @param epilogosble $subject - * @param string $epilogosKey - * - * @return string - * - * @throws \InvalidArgumentException - */ - public abstract function disambiguate(epilogosble $subject, $epilogosKey); -} \ No newline at end of file diff --git a/src/devmine/server/epilogos/Epilogosble.php b/src/devmine/server/epilogos/Epilogosble.php deleted file mode 100644 index 81264ef..0000000 --- a/src/devmine/server/epilogos/Epilogosble.php +++ /dev/null @@ -1,52 +0,0 @@ -getName()) . ":" . $epilogosKey; - } -} \ No newline at end of file diff --git a/src/devmine/server/epilogos/PlayerMetadataStore.php b/src/devmine/server/epilogos/PlayerMetadataStore.php deleted file mode 100644 index 9b57232..0000000 --- a/src/devmine/server/epilogos/PlayerMetadataStore.php +++ /dev/null @@ -1,18 +0,0 @@ -getName()) . ":" . $epilogosKey; - } -} diff --git a/src/devmine/server/epilogos/Epilogos.php b/src/devmine/server/meta/BlockMetadataStore.php similarity index 67% rename from src/devmine/server/epilogos/Epilogos.php rename to src/devmine/server/meta/BlockMetadataStore.php index f2def04..d35cc57 100644 --- a/src/devmine/server/epilogos/Epilogos.php +++ b/src/devmine/server/meta/BlockMetadataStore.php @@ -2,13 +2,13 @@ -namespace devmine\server\epilogos; +namespace devmine\server\meta; use devmine\inventory\blocks\Block; -use devmine\levels\Level; -use devmine\pluginfeatures\Plugin; +use devmine\worlds\Level; +use devmine\consumer\plugin\Plugin; -class BlockepilogosStore extends epilogosStore{ +class BlockMetadataStore extends MetadataStore{ /** @var Level */ private $owningLevel; @@ -16,53 +16,53 @@ public function __construct(Level $owningLevel){ $this->owningLevel = $owningLevel; } - public function disambiguate(epilogosble $block, $epilogosKey){ + public function disambiguate(Metadatable $block, $metadataKey){ if(!($block instanceof Block)){ throw new \InvalidArgumentException("Argument must be a Block instance"); } - return $block->x . ":" . $block->y . ":" . $block->z . ":" . $epilogosKey; + return $block->x . ":" . $block->y . ":" . $block->z . ":" . $metadataKey; } - public function getepilogos($block, $epilogosKey){ + public function getMetadata($block, $metadataKey){ if(!($block instanceof Block)){ throw new \InvalidArgumentException("Object must be a Block"); } if($block->getLevel() === $this->owningLevel){ - return parent::getepilogos($block, $epilogosKey); + return parent::getMetadata($block, $metadataKey); }else{ throw new \InvalidStateException("Block does not belong to world " . $this->owningLevel->getName()); } } - public function hasepilogos($block, $epilogosKey){ + public function hasMetadata($block, $metadataKey){ if(!($block instanceof Block)){ throw new \InvalidArgumentException("Object must be a Block"); } if($block->getLevel() === $this->owningLevel){ - return parent::hasepilogos($block, $epilogosKey); + return parent::hasMetadata($block, $metadataKey); }else{ throw new \InvalidStateException("Block does not belong to world " . $this->owningLevel->getName()); } } - public function removeepilogos($block, $epilogosKey, Plugin $owningPlugin){ + public function removeMetadata($block, $metadataKey, Plugin $owningPlugin){ if(!($block instanceof Block)){ throw new \InvalidArgumentException("Object must be a Block"); } if($block->getLevel() === $this->owningLevel){ - parent::hasepilogos($block, $epilogosKey, $owningPlugin); + parent::hasMetadata($block, $metadataKey, $owningPlugin); }else{ throw new \InvalidStateException("Block does not belong to world " . $this->owningLevel->getName()); } } - public function setepilogos($block, $epilogosKey, epilogosValue $newepilogosvalue){ + public function setMetadata($block, $metadataKey, MetadataValue $newMetadatavalue){ if(!($block instanceof Block)){ throw new \InvalidArgumentException("Object must be a Block"); } if($block->getLevel() === $this->owningLevel){ - parent::setepilogos($block, $epilogosKey, $newepilogosvalue); + parent::setMetadata($block, $metadataKey, $newMetadatavalue); }else{ throw new \InvalidStateException("Block does not belong to world " . $this->owningLevel->getName()); } diff --git a/src/devmine/server/meta/EntityMetadataStore.php b/src/devmine/server/meta/EntityMetadataStore.php new file mode 100644 index 0000000..2c3fb48 --- /dev/null +++ b/src/devmine/server/meta/EntityMetadataStore.php @@ -0,0 +1,18 @@ +getId() . ":" . $metadataKey; + } +} \ No newline at end of file diff --git a/src/devmine/server/meta/LevelMetadataStore.php b/src/devmine/server/meta/LevelMetadataStore.php new file mode 100644 index 0000000..a833780 --- /dev/null +++ b/src/devmine/server/meta/LevelMetadataStore.php @@ -0,0 +1,18 @@ +getName()) . ":" . $metadataKey; + } +} \ No newline at end of file diff --git a/src/devmine/server/meta/MetadataStore.php b/src/devmine/server/meta/MetadataStore.php new file mode 100644 index 0000000..3e65e91 --- /dev/null +++ b/src/devmine/server/meta/MetadataStore.php @@ -0,0 +1,123 @@ +getOwningPlugin(); + if($owningPlugin === null){ + throw new PluginException("Plugin cannot be null"); + } + + $key = $this->disambiguate($subject, $metadataKey); + if(!isset($this->metadataMap[$key])){ + //$entry = new \WeakMap(); + $this->metadataMap[$key] = new \SplObjectStorage();//$entry; + }else{ + $entry = $this->metadataMap[$key]; + } + $entry[$owningPlugin] = $newMetadataValue; + } + + /** + * Returns all metadata values attached to an object. If multiple + * have attached metadata, each will value will be included. + * + * @param mixed $subject + * @param string $metadataKey + * + * @return MetadataValue[] + * + * @throws \Exception + */ + public function getMetadata($subject, $metadataKey){ + $key = $this->disambiguate($subject, $metadataKey); + if(isset($this->metadataMap[$key])){ + return $this->metadataMap[$key]; + }else{ + return []; + } + } + + /** + * Tests to see if a metadata attribute has been set on an object. + * + * @param mixed $subject + * @param string $metadataKey + * + * @return bool + * + * @throws \Exception + */ + public function hasMetadata($subject, $metadataKey){ + return isset($this->metadataMap[$this->disambiguate($subject, $metadataKey)]); + } + + /** + * Removes a metadata item owned by a plugin from a subject. + * + * @param mixed $subject + * @param string $metadataKey + * @param Plugin $owningPlugin + * + * @throws \Exception + */ + public function removeMetadata($subject, $metadataKey, Plugin $owningPlugin){ + $key = $this->disambiguate($subject, $metadataKey); + if(isset($this->metadataMap[$key])){ + unset($this->metadataMap[$key][$owningPlugin]); + if($this->metadataMap[$key]->count() === 0){ + unset($this->metadataMap[$key]); + } + } + } + + /** + * Invalidates all metadata in the metadata store that originates from the + * given plugin. Doing this will force each invalidated metadata item to + * be recalculated the next time it is accessed. + * + * @param Plugin $owningPlugin + */ + public function invalidateAll(Plugin $owningPlugin){ + /** @var $values MetadataValue[] */ + foreach($this->metadataMap as $values){ + if(isset($values[$owningPlugin])){ + $values[$owningPlugin]->invalidate(); + } + } + } + + /** + * Creates a unique name for the object receiving metadata by combining + * unique data from the subject with a metadataKey. + * + * @param Metadatable $subject + * @param string $metadataKey + * + * @return string + * + * @throws \InvalidArgumentException + */ + public abstract function disambiguate(Metadatable $subject, $metadataKey); +} \ No newline at end of file diff --git a/src/devmine/server/epilogos/EpilogosValue.php b/src/devmine/server/meta/MetadataValue.php similarity index 67% rename from src/devmine/server/epilogos/EpilogosValue.php rename to src/devmine/server/meta/MetadataValue.php index 3e86b0d..ef452c8 100644 --- a/src/devmine/server/epilogos/EpilogosValue.php +++ b/src/devmine/server/meta/MetadataValue.php @@ -2,11 +2,11 @@ -namespace devmine\server\epilogos; +namespace devmine\server\meta; -use devmine\pluginfeatures\Plugin; +use devmine\consumer\plugin\Plugin; -abstract class epilogosValue{ +abstract class MetadataValue{ /** @var \WeakRef */ protected $owningPlugin; @@ -22,14 +22,14 @@ public function getOwningPlugin(){ } /** - * Fetches the value of this epilogos item. + * Fetches the value of this metadata item. * * @return mixed */ public abstract function value(); /** - * Invalidates this epilogos item, forcing it to recompute when next + * Invalidates this metadata item, forcing it to recompute when next * accessed. */ public abstract function invalidate(); diff --git a/src/devmine/server/meta/Metadatable.php b/src/devmine/server/meta/Metadatable.php new file mode 100644 index 0000000..9bf0398 --- /dev/null +++ b/src/devmine/server/meta/Metadatable.php @@ -0,0 +1,52 @@ +getName()) . ":" . $metadataKey; + } +} diff --git a/src/devmine/server/network/CompressBatchedTask.php b/src/devmine/server/network/CompressBatchedTask.php index 7ff2d7b..554e569 100644 --- a/src/devmine/server/network/CompressBatchedTask.php +++ b/src/devmine/server/network/CompressBatchedTask.php @@ -4,9 +4,9 @@ namespace devmine\server\network; -use devmine\Player; +use devmine\creatures\player; use devmine\server\tasks\AsyncTask; -use devmine\Server; +use devmine\server\server; class CompressBatchedTask extends AsyncTask{ diff --git a/src/devmine/server/network/Network.php b/src/devmine/server/network/Network.php index 53d2497..4a2f418 100644 --- a/src/devmine/server/network/Network.php +++ b/src/devmine/server/network/Network.php @@ -8,13 +8,18 @@ namespace devmine\server\network; use devmine\server\network\protocol\AddEntityPacket; +use devmine\server\network\protocol\AddHangingEntityPacket; use devmine\server\network\protocol\AddItemEntityPacket; +use devmine\server\network\protocol\AddItemPacket; use devmine\server\network\protocol\AddPaintingPacket; use devmine\server\network\protocol\AddPlayerPacket; use devmine\server\network\protocol\AdventureSettingsPacket; use devmine\server\network\protocol\AnimatePacket; +use devmine\server\network\protocol\AvailableCommandsPacket; use devmine\server\network\protocol\BatchPacket; +use devmine\server\network\protocol\BossEventPacket; use devmine\server\network\protocol\ChunkRadiusUpdatedPacket; +use devmine\server\network\protocol\CommandStepPacket; use devmine\server\network\protocol\ContainerClosePacket; use devmine\server\network\protocol\ContainerOpenPacket; use devmine\server\network\protocol\ContainerSetContentPacket; @@ -36,7 +41,9 @@ use devmine\server\network\protocol\HurtArmorPacket; use devmine\server\network\protocol\Info as ProtocolInfo; use devmine\server\network\protocol\InteractPacket; +use devmine\server\network\protocol\InventoryActionPacket; use devmine\server\network\protocol\LevelEventPacket; +use devmine\server\network\protocol\LevelSoundEventPacket; use devmine\server\network\protocol\DisconnectPacket; use devmine\server\network\protocol\LoginPacket; use devmine\server\network\protocol\PlayStatusPacket; @@ -49,7 +56,11 @@ use devmine\server\network\protocol\RemoveBlockPacket; use devmine\server\network\protocol\RemoveEntityPacket; use devmine\server\network\protocol\RemovePlayerPacket; +use devmine\server\network\protocol\ReplaceItemInSlotPacket; +use devmine\server\network\protocol\ResourcePackClientResponsePacket; +use devmine\server\network\protocol\ResourcePacksInfoPacket; use devmine\server\network\protocol\RespawnPacket; +use devmine\server\network\protocol\SetCommandsEnabledPacket; use devmine\server\network\protocol\SetDifficultyPacket; use devmine\server\network\protocol\SetEntityDataPacket; use devmine\server\network\protocol\SetEntityMotionPacket; @@ -57,16 +68,20 @@ use devmine\server\network\protocol\SetPlayerGameTypePacket; use devmine\server\network\protocol\SetSpawnPositionPacket; use devmine\server\network\protocol\SetTimePacket; +use devmine\server\network\protocol\SpawnExperienceOrbPacket; use devmine\server\network\protocol\StartGamePacket; use devmine\server\network\protocol\TakeItemEntityPacket; use devmine\server\network\protocol\BlockEventPacket; use devmine\server\network\protocol\UpdateBlockPacket; +use devmine\server\network\protocol\PlayerFallPacket; use devmine\server\network\protocol\UseItemPacket; use devmine\server\network\protocol\PlayerListPacket; use devmine\server\network\protocol\PlayerInputPacket; -use devmine\Player; -use devmine\Server; +use devmine\server\network\protocol\ShowCreditsPacket; +use devmine\creatures\player; +use devmine\server\server; use devmine\utilities\main\Binary; +use devmine\utilities\main\BinaryStream; use devmine\utilities\main\MainLogger; class Network { @@ -128,7 +143,7 @@ public function processInterfaces() { $interface->process(); } catch (\Throwable $e) { $logger = $this->server->getLogger(); - if (\devmine\DEBUG > 1) { + if (\DevMine\DEBUG > 1) { if ($logger instanceof MainLogger) { $logger->logException($e); } @@ -136,7 +151,7 @@ public function processInterfaces() { $interface->emergencyShutdown(); $this->unregisterInterface($interface); - $logger->critical($this->server->getLanguage()->translateString("devmine.server.networkError", [get_class($interface), $e->getMessage()])); + $logger->critical($this->server->getLanguage()->translateString("DevMine.server.networkError", [get_class($interface), $e->getMessage()])); } } } @@ -195,44 +210,35 @@ public function getServer() { return $this->server; } - public function processBatch(BatchPacket $packet, Player $p) { - $str = zlib_decode($packet->payload, 1024 * 1024 * 64); //Max 64MB - $len = strlen($str); - $offset = 0; - try { - while ($offset < $len) { - $pkLen = Binary::readInt(substr($str, $offset, 4)); - $offset += 4; - - $buf = substr($str, $offset, $pkLen); - $offset += $pkLen; - - if(strlen($buf) === 0){ - throw new \InvalidStateException("Empty or invalid BatchPacket received"); - } - - if (($pk = $this->getPacket(ord($buf{0}))) !== null) { - if ($pk::NETWORK_ID === Info::BATCH_PACKET) { + public function processBatch(BatchPacket $packet, Player $p){ + try{ + if(strlen($packet->payload) === 0){ + //prevent zlib_decode errors for incorrectly-decoded packets + throw new \InvalidArgumentException("BatchPacket payload is empty or packet decode error"); + } + $str = zlib_decode($packet->payload, 1024 * 1024 * 64); //Max 64MB + $len = strlen($str); + if($len === 0){ + throw new \InvalidStateException("Decoded BatchPacket payload is empty"); + } + $stream = new BinaryStream($str); + while($stream->offset < $len){ + $buf = $stream->getString(); + if(($pk = $this->getPacket(ord($buf{0}))) !== null){ + if($pk::NETWORK_ID === Info::BATCH_PACKET){ throw new \InvalidStateException("Invalid BatchPacket inside BatchPacket"); } - $pk->setBuffer($buf, 1); - $pk->decode(); + assert($pk->feof(), "Still " . strlen(substr($pk->buffer, $pk->offset)) . " bytes unread in " . get_class($pk)); $p->handleDataPacket($pk); - - if ($pk->getOffset() <= 0) { - return; - } } } - } catch (\Throwable $e) { - if (\devmine\DEBUG > 1) { + }catch(\Throwable $e){ + if(\DevMine\DEBUG > 1){ $logger = $this->server->getLogger(); - if ($logger instanceof MainLogger) { - $logger->debug("BatchPacket " . " 0x" . bin2hex($packet->payload)); - $logger->logException($e); - } + $logger->debug("BatchPacket " . " 0x" . bin2hex($packet->payload)); + $logger->logException($e); } } } @@ -289,58 +295,75 @@ public function unblockAddress($address) { private function registerPackets() { $this->packetPool = new \SplFixedArray(256); - $this->registerPacket(ProtocolInfo::LOGIN_PACKET, LoginPacket::class); - $this->registerPacket(ProtocolInfo::PLAY_STATUS_PACKET, PlayStatusPacket::class); - $this->registerPacket(ProtocolInfo::DISCONNECT_PACKET, DisconnectPacket::class); - $this->registerPacket(ProtocolInfo::BATCH_PACKET, BatchPacket::class); - $this->registerPacket(ProtocolInfo::TEXT_PACKET, TextPacket::class); - $this->registerPacket(ProtocolInfo::SET_TIME_PACKET, SetTimePacket::class); - $this->registerPacket(ProtocolInfo::START_GAME_PACKET, StartGamePacket::class); - $this->registerPacket(ProtocolInfo::ADD_PLAYER_PACKET, AddPlayerPacket::class); $this->registerPacket(ProtocolInfo::ADD_ENTITY_PACKET, AddEntityPacket::class); - $this->registerPacket(ProtocolInfo::REMOVE_ENTITY_PACKET, RemoveEntityPacket::class); + $this->registerPacket(ProtocolInfo::ADD_HANGING_ENTITY_PACKET, AddHangingEntityPacket::class); $this->registerPacket(ProtocolInfo::ADD_ITEM_ENTITY_PACKET, AddItemEntityPacket::class); - $this->registerPacket(ProtocolInfo::TAKE_ITEM_ENTITY_PACKET, TakeItemEntityPacket::class); - $this->registerPacket(ProtocolInfo::MOVE_ENTITY_PACKET, MoveEntityPacket::class); - $this->registerPacket(ProtocolInfo::MOVE_PLAYER_PACKET, MovePlayerPacket::class); - $this->registerPacket(ProtocolInfo::REMOVE_BLOCK_PACKET, RemoveBlockPacket::class); - $this->registerPacket(ProtocolInfo::UPDATE_BLOCK_PACKET, UpdateBlockPacket::class); + $this->registerPacket(ProtocolInfo::ADD_ITEM_PACKET, AddItemPacket::class); $this->registerPacket(ProtocolInfo::ADD_PAINTING_PACKET, AddPaintingPacket::class); - $this->registerPacket(ProtocolInfo::EXPLODE_PACKET, ExplodePacket::class); - $this->registerPacket(ProtocolInfo::LEVEL_EVENT_PACKET, LevelEventPacket::class); - $this->registerPacket(ProtocolInfo::BLOCK_EVENT_PACKET, BlockEventPacket::class); - $this->registerPacket(ProtocolInfo::ENTITY_EVENT_PACKET, EntityEventPacket::class); - $this->registerPacket(ProtocolInfo::MOB_EQUIPMENT_PACKET, MobEquipmentPacket::class); - $this->registerPacket(ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET, MobArmorEquipmentPacket::class); - $this->registerPacket(ProtocolInfo::INTERACT_PACKET, InteractPacket::class); - $this->registerPacket(ProtocolInfo::USE_ITEM_PACKET, UseItemPacket::class); - $this->registerPacket(ProtocolInfo::PLAYER_ACTION_PACKET, PlayerActionPacket::class); - $this->registerPacket(ProtocolInfo::HURT_ARMOR_PACKET, HurtArmorPacket::class); - $this->registerPacket(ProtocolInfo::SET_ENTITY_DATA_PACKET, SetEntityDataPacket::class); - $this->registerPacket(ProtocolInfo::SET_ENTITY_MOTION_PACKET, SetEntityMotionPacket::class); - $this->registerPacket(ProtocolInfo::SET_ENTITY_LINK_PACKET, SetEntityLinkPacket::class); - $this->registerPacket(ProtocolInfo::SET_HEALTH_PACKET, SetHealthPacket::class); - $this->registerPacket(ProtocolInfo::SET_SPAWN_POSITION_PACKET, SetSpawnPositionPacket::class); + $this->registerPacket(ProtocolInfo::ADD_PLAYER_PACKET, AddPlayerPacket::class); + $this->registerPacket(ProtocolInfo::ADVENTURE_SETTINGS_PACKET, AdventureSettingsPacket::class); $this->registerPacket(ProtocolInfo::ANIMATE_PACKET, AnimatePacket::class); - $this->registerPacket(ProtocolInfo::RESPAWN_PACKET, RespawnPacket::class); - $this->registerPacket(ProtocolInfo::DROP_ITEM_PACKET, DropItemPacket::class); - $this->registerPacket(ProtocolInfo::CONTAINER_OPEN_PACKET, ContainerOpenPacket::class); + $this->registerPacket(ProtocolInfo::INVENTORY_ACTION_PACKET, InventoryActionPacket::class); + $this->registerPacket(ProtocolInfo::AVAILABLE_COMMANDS_PACKET, AvailableCommandsPacket::class); + $this->registerPacket(ProtocolInfo::BATCH_PACKET, BatchPacket::class); + $this->registerPacket(ProtocolInfo::BLOCK_ENTITY_DATA_PACKET, BlockEntityDataPacket::class); + $this->registerPacket(ProtocolInfo::BLOCK_EVENT_PACKET, BlockEventPacket::class); + $this->registerPacket(ProtocolInfo::BOSS_EVENT_PACKET, BossEventPacket::class); + $this->registerPacket(ProtocolInfo::CHANGE_DIMENSION_PACKET, ChangeDimensionPacket::class); + $this->registerPacket(ProtocolInfo::CHUNK_RADIUS_UPDATED_PACKET, ChunkRadiusUpdatedPacket::class); + $this->registerPacket(ProtocolInfo::COMMAND_STEP_PACKET, CommandStepPacket::class); $this->registerPacket(ProtocolInfo::CONTAINER_CLOSE_PACKET, ContainerClosePacket::class); - $this->registerPacket(ProtocolInfo::CONTAINER_SET_SLOT_PACKET, ContainerSetSlotPacket::class); - $this->registerPacket(ProtocolInfo::CONTAINER_SET_DATA_PACKET, ContainerSetDataPacket::class); + $this->registerPacket(ProtocolInfo::CONTAINER_OPEN_PACKET, ContainerOpenPacket::class); $this->registerPacket(ProtocolInfo::CONTAINER_SET_CONTENT_PACKET, ContainerSetContentPacket::class); + $this->registerPacket(ProtocolInfo::CONTAINER_SET_DATA_PACKET, ContainerSetDataPacket::class); + $this->registerPacket(ProtocolInfo::CONTAINER_SET_SLOT_PACKET, ContainerSetSlotPacket::class); $this->registerPacket(ProtocolInfo::CRAFTING_DATA_PACKET, CraftingDataPacket::class); $this->registerPacket(ProtocolInfo::CRAFTING_EVENT_PACKET, CraftingEventPacket::class); - $this->registerPacket(ProtocolInfo::ADVENTURE_SETTINGS_PACKET, AdventureSettingsPacket::class); - $this->registerPacket(ProtocolInfo::BLOCK_ENTITY_DATA_PACKET, BlockEntityDataPacket::class); + $this->registerPacket(ProtocolInfo::DISCONNECT_PACKET, DisconnectPacket::class); + $this->registerPacket(ProtocolInfo::DROP_ITEM_PACKET, DropItemPacket::class); + $this->registerPacket(ProtocolInfo::ENTITY_EVENT_PACKET, EntityEventPacket::class); + $this->registerPacket(ProtocolInfo::EXPLODE_PACKET, ExplodePacket::class); + $this->registerPacket(ProtocolInfo::PLAYER_FALL_PACKET, PlayerFallPacket::class); $this->registerPacket(ProtocolInfo::FULL_CHUNK_DATA_PACKET, FullChunkDataPacket::class); - $this->registerPacket(ProtocolInfo::SET_DIFFICULTY_PACKET, SetDifficultyPacket::class); - $this->registerPacket(ProtocolInfo::PLAYER_LIST_PACKET, PlayerListPacket::class); + $this->registerPacket(ProtocolInfo::SET_COMMANDS_ENABLED_PACKET, SetCommandsEnabledPacket::class); + $this->registerPacket(ProtocolInfo::HURT_ARMOR_PACKET, HurtArmorPacket::class); + $this->registerPacket(ProtocolInfo::INTERACT_PACKET, InteractPacket::class); + $this->registerPacket(ProtocolInfo::INVENTORY_ACTION_PACKET, InventoryActionPacket::class); + $this->registerPacket(ProtocolInfo::ITEM_FRAME_DROP_ITEM_PACKET, ItemFrameDropItemPacket::class); + $this->registerPacket(ProtocolInfo::LEVEL_EVENT_PACKET, LevelEventPacket::class); + $this->registerPacket(ProtocolInfo::LEVEL_SOUND_EVENT_PACKET, LevelSoundEventPacket::class); + $this->registerPacket(ProtocolInfo::LOGIN_PACKET, LoginPacket::class); + $this->registerPacket(ProtocolInfo::SHOW_CREDITS_PACKET, ShowCreditsPacket::class); + $this->registerPacket(ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET, MobArmorEquipmentPacket::class); + $this->registerPacket(ProtocolInfo::MOB_EQUIPMENT_PACKET, MobEquipmentPacket::class); + $this->registerPacket(ProtocolInfo::MOVE_ENTITY_PACKET, MoveEntityPacket::class); + $this->registerPacket(ProtocolInfo::MOVE_PLAYER_PACKET, MovePlayerPacket::class); + $this->registerPacket(ProtocolInfo::PLAYER_ACTION_PACKET, PlayerActionPacket::class); $this->registerPacket(ProtocolInfo::PLAYER_INPUT_PACKET, PlayerInputPacket::class); - $this->registerPacket(ProtocolInfo::SET_PLAYER_GAMETYPE_PACKET, SetPlayerGameTypePacket::class); - $this->registerPacket(ProtocolInfo::CHANGE_DIMENSION_PACKET, ChangeDimensionPacket::class); + $this->registerPacket(ProtocolInfo::PLAYER_LIST_PACKET, PlayerListPacket::class); + $this->registerPacket(ProtocolInfo::PLAY_STATUS_PACKET, PlayStatusPacket::class); + $this->registerPacket(ProtocolInfo::REMOVE_BLOCK_PACKET, RemoveBlockPacket::class); + $this->registerPacket(ProtocolInfo::REMOVE_ENTITY_PACKET, RemoveEntityPacket::class); + $this->registerPacket(ProtocolInfo::REPLACE_SELECTED_ITEM_PACKET, ReplaceItemInSlotPacket::class); $this->registerPacket(ProtocolInfo::REQUEST_CHUNK_RADIUS_PACKET, RequestChunkRadiusPacket::class); - $this->registerPacket(ProtocolInfo::CHUNK_RADIUS_UPDATED_PACKET, ChunkRadiusUpdatedPacket::class); + $this->registerPacket(ProtocolInfo::RESOURCE_PACK_CLIENT_RESPONSE_PACKET, ResourcePackClientResponsePacket::class); + $this->registerPacket(ProtocolInfo::RESOURCE_PACKS_INFO_PACKET, ResourcePacksInfoPacket::class); + $this->registerPacket(ProtocolInfo::RESPAWN_PACKET, RespawnPacket::class); + $this->registerPacket(ProtocolInfo::SET_COMMANDS_ENABLED_PACKET, SetCommandsEnabledPacket::class); + $this->registerPacket(ProtocolInfo::SET_DIFFICULTY_PACKET, SetDifficultyPacket::class); + $this->registerPacket(ProtocolInfo::SET_ENTITY_DATA_PACKET, SetEntityDataPacket::class); + $this->registerPacket(ProtocolInfo::SET_ENTITY_LINK_PACKET, SetEntityLinkPacket::class); + $this->registerPacket(ProtocolInfo::SET_ENTITY_MOTION_PACKET, SetEntityMotionPacket::class); + $this->registerPacket(ProtocolInfo::SET_HEALTH_PACKET, SetHealthPacket::class); + $this->registerPacket(ProtocolInfo::SET_PLAYER_GAME_TYPE_PACKET, SetPlayerGameTypePacket::class); + $this->registerPacket(ProtocolInfo::SET_SPAWN_POSITION_PACKET, SetSpawnPositionPacket::class); + $this->registerPacket(ProtocolInfo::SET_TIME_PACKET, SetTimePacket::class); + $this->registerPacket(ProtocolInfo::SPAWN_EXPERIENCE_ORB_PACKET, SpawnExperienceOrbPacket::class); + $this->registerPacket(ProtocolInfo::START_GAME_PACKET, StartGamePacket::class); + $this->registerPacket(ProtocolInfo::TAKE_ITEM_ENTITY_PACKET, TakeItemEntityPacket::class); + $this->registerPacket(ProtocolInfo::TEXT_PACKET, TextPacket::class); + $this->registerPacket(ProtocolInfo::UPDATE_BLOCK_PACKET, UpdateBlockPacket::class); + $this->registerPacket(ProtocolInfo::USE_ITEM_PACKET, UseItemPacket::class); $this->registerPacket(ProtocolInfo::ITEM_FRAME_DROP_ITEM_PACKET, ItemFrameDropItemPacket::class); } } diff --git a/src/devmine/server/network/RakLibInterface.php b/src/devmine/server/network/RakLibInterface.php index 7f82c0e..ad21586 100644 --- a/src/devmine/server/network/RakLibInterface.php +++ b/src/devmine/server/network/RakLibInterface.php @@ -4,14 +4,15 @@ namespace devmine\server\network; -use devmine\server\events\player\PlayerCreationEvent; +use devmine\events\player\PlayerCreationEvent; use devmine\server\network\protocol\DataPacket; use devmine\server\network\protocol\Info as ProtocolInfo; use devmine\server\network\protocol\Info; -use devmine\Player; -use devmine\Server; +use devmine\creatures\player; +use devmine\server\server; use devmine\utilities\main\MainLogger; use raklib\protocol\EncapsulatedPacket; +use raklib\protocol\PacketReliability; use raklib\RakLib; use raklib\server\RakLibServer; use raklib\server\ServerHandler; @@ -119,12 +120,13 @@ public function handleEncapsulated($identifier, EncapsulatedPacket $packet, $fla $pk = $this->getPacket($packet->buffer); if($pk !== null){ $pk->decode(); + assert($pk->feof(), "Still " . strlen(substr($pk->buffer, $pk->offset)) . " bytes unread!"); $this->players[$identifier]->handleDataPacket($pk); } } }catch(\Throwable $e){ $logger = $this->server->getLogger(); - if(\devmine\DEBUG > 1 and isset($pk)){ + if(\DevMine\DEBUG > 1 and isset($pk)){ $logger->debug("Exception in packet " . get_class($pk) . " 0x" . bin2hex($packet->buffer)); } $logger->logException($e); @@ -170,7 +172,7 @@ public function setName($name){ $this->interface->sendOption("name", "MCPE;" . addcslashes($name, ";") . ";" . ProtocolInfo::CURRENT_PROTOCOL . ";" . - \devmine\MINECRAFT_VERSION_NETWORK . ";" . + ProtocolInfo::MINECRAFT_VERSION_NETWORK . ";" . $poc . ";" . $pc ); @@ -198,7 +200,7 @@ public function putPacket(Player $player, DataPacket $packet, $needACK = false, $packet->__encapsulatedPacket = new CachedEncapsulatedPacket; $packet->__encapsulatedPacket->identifierACK = null; $packet->__encapsulatedPacket->buffer = chr(0xfe) . $packet->buffer; - $packet->__encapsulatedPacket->reliability = 3; + $packet->__encapsulatedPacket->reliability = PacketReliability::RELIABLE_ORDERED; $packet->__encapsulatedPacket->orderChannel = 0; } $pk = $packet->__encapsulatedPacket; @@ -214,7 +216,7 @@ public function putPacket(Player $player, DataPacket $packet, $needACK = false, if($pk === null){ $pk = new EncapsulatedPacket(); $pk->buffer = chr(0xfe) . $packet->buffer; - $packet->reliability = 3; + $packet->reliability = PacketReliability::RELIABLE_ORDERED; $packet->orderChannel = 0; if($needACK === true){ diff --git a/src/devmine/server/network/SourceInterface.php b/src/devmine/server/network/SourceInterface.php index a1f6700..0e49ebd 100644 --- a/src/devmine/server/network/SourceInterface.php +++ b/src/devmine/server/network/SourceInterface.php @@ -8,7 +8,7 @@ namespace devmine\server\network; use devmine\server\network\protocol\DataPacket; -use devmine\Player; +use devmine\creatures\player; /** * Classes that implement this interface will be able to be attached to players diff --git a/src/devmine/server/network/protocol/AddEntityPacket.php b/src/devmine/server/network/protocol/AddEntityPacket.php index 49de8b9..529cf22 100644 --- a/src/devmine/server/network/protocol/AddEntityPacket.php +++ b/src/devmine/server/network/protocol/AddEntityPacket.php @@ -25,7 +25,7 @@ class AddEntityPacket extends DataPacket{ public $yaw; public $pitch; public $modifiers; - public $epilogos = []; + public $metadata = []; public $links = []; public function decode(){ @@ -34,23 +34,20 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putLong($this->eid); - $this->putInt($this->type); - $this->putFloat($this->x); - $this->putFloat($this->y); - $this->putFloat($this->z); - $this->putFloat($this->speedX); - $this->putFloat($this->speedY); - $this->putFloat($this->speedZ); - $this->putFloat($this->yaw * 0.71111); - $this->putFloat($this->pitch * 0.71111); - $this->putInt($this->modifiers); - $meta = Binary::writeepilogos($this->epilogos); + $this->putEntityId($this->eid); //EntityUniqueID - TODO: verify this + $this->putEntityId($this->eid); + $this->putUnsignedVarInt($this->type); + $this->putVector3f($this->x, $this->y, $this->z); + $this->putVector3f($this->speedX, $this->speedY, $this->speedZ); + $this->putLFloat($this->pitch * 0.71111); + $this->putLFloat($this->yaw * 0.71111); + $this->putUnsignedVarInt($this->modifiers); //attributes? + $meta = Binary::writeMetadata($this->metadata); $this->put($meta); - $this->putShort(count($this->links)); + $this->putUnsignedVarInt(count($this->links)); foreach($this->links as $link){ - $this->putLong($link[0]); - $this->putLong($link[1]); + $this->putEntityId($link[0]); + $this->putEntityId($link[1]); $this->putByte($link[2]); } } diff --git a/src/devmine/server/network/protocol/AddHangingEntityPacket.php b/src/devmine/server/network/protocol/AddHangingEntityPacket.php new file mode 100644 index 0000000..2ba6429 --- /dev/null +++ b/src/devmine/server/network/protocol/AddHangingEntityPacket.php @@ -0,0 +1,31 @@ + + +class AddHangingEntityPacket extends DataPacket{ + const NETWORK_ID = Info::ADD_HANGING_ENTITY_PACKET; + + public $entityUniqueId; + public $entityRuntimeId; + public $x; + public $y; + public $z; + public $unknown; + + public function decode(){ + + } + + public function encode(){ + $this->reset(); + $this->putEntityId($this->entityUniqueId); + $this->putEntityId($this->entityRuntimeId); + $this->putBlockCoords($this->x, $this->y, $this->z); + $this->putVarInt($this->unknown); + } + +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/AddItemEntityPacket.php b/src/devmine/server/network/protocol/AddItemEntityPacket.php index 1b8f000..c11b730 100644 --- a/src/devmine/server/network/protocol/AddItemEntityPacket.php +++ b/src/devmine/server/network/protocol/AddItemEntityPacket.php @@ -25,14 +25,11 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putLong($this->eid); + $this->putEntityId($this->eid); //EntityUniqueID + $this->putEntityId($this->eid); //EntityRuntimeID $this->putSlot($this->item); - $this->putFloat($this->x); - $this->putFloat($this->y); - $this->putFloat($this->z); - $this->putFloat($this->speedX); - $this->putFloat($this->speedY); - $this->putFloat($this->speedZ); + $this->putVector3f($this->x, $this->y, $this->z); + $this->putVector3f($this->speedX, $this->speedY, $this->speedZ); } } diff --git a/src/devmine/server/network/protocol/AddItemPacket.php b/src/devmine/server/network/protocol/AddItemPacket.php new file mode 100644 index 0000000..90f710d --- /dev/null +++ b/src/devmine/server/network/protocol/AddItemPacket.php @@ -0,0 +1,24 @@ + + + +class AddItemPacket extends DataPacket{ + const NETWORK_ID = Info::ADD_ITEM_PACKET; + + public $item; + + public function decode(){ + + } + + public function encode(){ + $this->reset(); + $this->putSlot($this->item); + } + +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/AddPaintingPacket.php b/src/devmine/server/network/protocol/AddPaintingPacket.php index c9a67f7..bc739e6 100644 --- a/src/devmine/server/network/protocol/AddPaintingPacket.php +++ b/src/devmine/server/network/protocol/AddPaintingPacket.php @@ -23,11 +23,10 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putLong($this->eid); - $this->putInt($this->x); - $this->putInt($this->y); - $this->putInt($this->z); - $this->putInt($this->direction); + $this->putEntityId($this->eid); //EntityUniqueID + $this->putEntityId($this->eid); //EntityRuntimeID + $this->putBlockCoords($this->x, $this->y, $this->z); + $this->putVarInt($this->direction); $this->putString($this->title); } diff --git a/src/devmine/server/network/protocol/AddPlayerPacket.php b/src/devmine/server/network/protocol/AddPlayerPacket.php index fe1e8e6..f8084ce 100644 --- a/src/devmine/server/network/protocol/AddPlayerPacket.php +++ b/src/devmine/server/network/protocol/AddPlayerPacket.php @@ -26,7 +26,7 @@ class AddPlayerPacket extends DataPacket{ public $pitch; public $yaw; public $item; - public $epilogos; + public $metadata = []; public function decode(){ @@ -36,19 +36,17 @@ public function encode(){ $this->reset(); $this->putUUID($this->uuid); $this->putString($this->username); - $this->putLong($this->eid); - $this->putFloat($this->x); - $this->putFloat($this->y); - $this->putFloat($this->z); - $this->putFloat($this->speedX); - $this->putFloat($this->speedY); - $this->putFloat($this->speedZ); - $this->putFloat($this->yaw); - $this->putFloat($this->yaw); //TODO headrot - $this->putFloat($this->pitch); + $this->putEntityId($this->eid); //EntityUniqueID + $this->putEntityId($this->eid); //EntityRuntimeID + $this->putVector3f($this->x, $this->y, $this->z); + $this->putVector3f($this->speedX, $this->speedY, $this->speedZ); + //TODO: check these are in the right order + $this->putLFloat($this->yaw); + $this->putLFloat($this->yaw); //TODO headrot + $this->putLFloat($this->pitch); $this->putSlot($this->item); - $meta = Binary::writeepilogos($this->epilogos); + $meta = Binary::writeMetadata($this->metadata); $this->put($meta); } diff --git a/src/devmine/server/network/protocol/AdventureSettingsPacket.php b/src/devmine/server/network/protocol/AdventureSettingsPacket.php index 770dcc8..541e84c 100644 --- a/src/devmine/server/network/protocol/AdventureSettingsPacket.php +++ b/src/devmine/server/network/protocol/AdventureSettingsPacket.php @@ -10,19 +10,61 @@ class AdventureSettingsPacket extends DataPacket{ const NETWORK_ID = Info::ADVENTURE_SETTINGS_PACKET; - public $flags; + const PERMISSION_NORMAL = 0; + const PERMISSION_OPERATOR = 1; + const PERMISSION_HOST = 2; + const PERMISSION_AUTOMATION = 3; + const PERMISSION_ADMIN = 4; + public $worldImmutable; + public $noPvp; + public $noPvm; + public $noMvp; + public $autoJump; + public $allowFlight; + public $noClip; + public $isFlying; + /* + bit mask | flag name + 0x00000001 world_immutable + 0x00000002 no_pvp + 0x00000004 no_pvm + 0x00000008 no_mvp + 0x00000010 ? + 0x00000020 auto_jump + 0x00000040 allow_fly + 0x00000080 noclip + 0x00000100 ? + 0x00000200 is_flying + */ + public $flags = 0; public $userPermission; - public $globalPermission; public function decode(){ - + $this->flags = $this->getUnsignedVarInt(); + $this->userPermission = $this->getUnsignedVarInt(); + $this->worldImmutable = (bool) ($this->flags & 1); + $this->noPvp = (bool) ($this->flags & (1 << 1)); + $this->noPvm = (bool) ($this->flags & (1 << 2)); + $this->noMvp = (bool) ($this->flags & (1 << 3)); + $this->autoJump = (bool) ($this->flags & (1 << 5)); + $this->allowFlight = (bool) ($this->flags & (1 << 6)); + $this->noClip = (bool) ($this->flags & (1 << 7)); + $this->isFlying = (bool) ($this->flags & (1 << 9)); } public function encode(){ $this->reset(); - $this->putInt($this->flags); - $this->putInt($this->userPermission); - $this->putInt($this->globalPermission); + + $this->flags |= ((int) $this->worldImmutable); + $this->flags |= ((int) $this->noPvp) << 1; + $this->flags |= ((int) $this->noPvm) << 2; + $this->flags |= ((int) $this->noMvp) << 3; + $this->flags |= ((int) $this->autoJump) << 5; + $this->flags |= ((int) $this->allowFlight) << 6; + $this->flags |= ((int) $this->noClip) << 7; + $this->flags |= ((int) $this->isFlying) << 9; + $this->putUnsignedVarInt($this->flags); + $this->putUnsignedVarInt($this->userPermission); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/AnimatePacket.php b/src/devmine/server/network/protocol/AnimatePacket.php index 37f74a8..cc2f022 100644 --- a/src/devmine/server/network/protocol/AnimatePacket.php +++ b/src/devmine/server/network/protocol/AnimatePacket.php @@ -12,16 +12,21 @@ class AnimatePacket extends DataPacket{ public $action; public $eid; + public $unknownFloat; //TODO: find out what this is for (maybe an amplifier?) public function decode(){ - $this->action = $this->getByte(); - $this->eid = $this->getLong(); + $this->action = $this->getVarInt(); + $this->eid = $this->getEntityId(); + if(!$this->feof()){ + $this->unknownFloat = $this->getLFloat(); //TODO: find out when this is sent (not always! >:-[) + } } public function encode(){ $this->reset(); - $this->putByte($this->action); - $this->putLong($this->eid); + $this->getVarInt($this->action); + $this->putEntityId($this->eid); + $this->putLFloat($this->unknownFloat); } } diff --git a/src/devmine/server/network/protocol/AvailableCommandsPacket.php b/src/devmine/server/network/protocol/AvailableCommandsPacket.php new file mode 100644 index 0000000..abca691 --- /dev/null +++ b/src/devmine/server/network/protocol/AvailableCommandsPacket.php @@ -0,0 +1,25 @@ + + +class AvailableCommandsPacket extends DataPacket{ + const NETWORK_ID = Info::AVAILABLE_COMMANDS_PACKET; + + public $commands; //JSON-encoded command data + public $unknown; + + public function decode(){ + + } + + public function encode(){ + $this->reset(); + $this->putString($this->commands); + $this->putString($this->unknown); + } + +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/BatchPacket.php b/src/devmine/server/network/protocol/BatchPacket.php index 69510e1..c66bd1f 100644 --- a/src/devmine/server/network/protocol/BatchPacket.php +++ b/src/devmine/server/network/protocol/BatchPacket.php @@ -13,14 +13,11 @@ class BatchPacket extends DataPacket{ public $payload; public function decode(){ - $size = $this->getInt(); - $this->payload = $this->get($size); + $this->payload = $this->getString(); } public function encode(){ $this->reset(); - $this->putInt(strlen($this->payload)); - $this->put($this->payload); + $this->putString($this->payload); } - -} \ No newline at end of file +} diff --git a/src/devmine/server/network/protocol/BlockEntityDataPacket.php b/src/devmine/server/network/protocol/BlockEntityDataPacket.php index 9555554..c0e4777 100644 --- a/src/devmine/server/network/protocol/BlockEntityDataPacket.php +++ b/src/devmine/server/network/protocol/BlockEntityDataPacket.php @@ -16,17 +16,13 @@ class BlockEntityDataPacket extends DataPacket{ public $namedtag; public function decode(){ - $this->x = $this->getInt(); - $this->y = $this->getInt(); - $this->z = $this->getInt(); + $this->getBlockCoords($this->x, $this->y, $this->z); $this->namedtag = $this->get(true); } public function encode(){ $this->reset(); - $this->putInt($this->x); - $this->putInt($this->y); - $this->putInt($this->z); + $this->putBlockCoords($this->x, $this->y, $this->z); $this->put($this->namedtag); } diff --git a/src/devmine/server/network/protocol/BlockEventPacket.php b/src/devmine/server/network/protocol/BlockEventPacket.php index ad54d83..64dcad4 100644 --- a/src/devmine/server/network/protocol/BlockEventPacket.php +++ b/src/devmine/server/network/protocol/BlockEventPacket.php @@ -22,11 +22,9 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putInt($this->x); - $this->putInt($this->y); - $this->putInt($this->z); - $this->putInt($this->case1); - $this->putInt($this->case2); + $this->putBlockCoords($this->x, $this->y, $this->z); + $this->putVarInt($this->case1); + $this->putVarInt($this->case2); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/BossEventPacket.php b/src/devmine/server/network/protocol/BossEventPacket.php new file mode 100644 index 0000000..141d305 --- /dev/null +++ b/src/devmine/server/network/protocol/BossEventPacket.php @@ -0,0 +1,24 @@ + +use devmine\utilities\main\Binary; + +class BossEventPacket extends DataPacket{ + const NETWORK_ID = Info::BOSS_EVENT_PACKET; + public $eid; + public $type; + + public function decode(){ + + } + + public function encode(){ + $this->reset(); + $this->putVarInt($this->eid); + $this->putUnsignedVarInt($this->type); + } +} diff --git a/src/devmine/server/network/protocol/CameraPacket.php b/src/devmine/server/network/protocol/CameraPacket.php new file mode 100644 index 0000000..2703399 --- /dev/null +++ b/src/devmine/server/network/protocol/CameraPacket.php @@ -0,0 +1,40 @@ + +namespace devmine\server\network\protocol; + +class CameraPacket extends DataPacket{ + + const NETWORK_ID = Info::CAMERA_PACKET; + public $eid; + + public function decode(){ + } + + public function encode(){ + $this->reset(); + $this->putVarInt($this->eid); + $this->putVarInt($this->eid); + } +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/ChangeDimensionPacket.php b/src/devmine/server/network/protocol/ChangeDimensionPacket.php index ad49f69..f12295c 100644 --- a/src/devmine/server/network/protocol/ChangeDimensionPacket.php +++ b/src/devmine/server/network/protocol/ChangeDimensionPacket.php @@ -1,6 +1,23 @@ reset(); - $this->putByte($this->dimension); - $this->putFloat($this->x); - $this->putFloat($this->y); - $this->putFloat($this->z); - $this->putByte(0); + $this->putVarInt($this->dimension); + $this->putVector3f($this->x, $this->y, $this->z); + $this->putBool($this->unknownBool); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/ChunkRadiusUpdatedPacket.php b/src/devmine/server/network/protocol/ChunkRadiusUpdatedPacket.php index 7801bd0..617750f 100644 --- a/src/devmine/server/network/protocol/ChunkRadiusUpdatedPacket.php +++ b/src/devmine/server/network/protocol/ChunkRadiusUpdatedPacket.php @@ -1,6 +1,23 @@ reset(); - $this->putInt($this->radius); + $this->putVarInt($this->radius); } -} \ No newline at end of file +} diff --git a/src/devmine/server/network/protocol/CommandStepPacket.php b/src/devmine/server/network/protocol/CommandStepPacket.php new file mode 100644 index 0000000..00d9fd2 --- /dev/null +++ b/src/devmine/server/network/protocol/CommandStepPacket.php @@ -0,0 +1,51 @@ + + +class CommandStepPacket extends DataPacket{ + const NETWORK_ID = Info::COMMAND_STEP_PACKET; + + /** + * unknown (string) + * unknown (string) + * unknown (uvarint) + * unknown (uvarint) + * unknown (bool) + * unknown (uvarint64) + * unknown (string) + * unknown (string) + * https://gist.github.com/dktapps/8285b93af4ca38e0104bfeb9a6c87afd + */ + + public $command; + public $overload; + public $uvarint1; + public $uvarint2; + public $bool; + public $uvarint64; + public $args; //JSON formatted command arguments + public $string4; + + public function decode(){ + $this->command = $this->getString(); + $this->overload = $this->getString(); + $this->uvarint1 = $this->getUnsignedVarInt(); + $this->uvarint2 = $this->getUnsignedVarInt(); + $this->bool = (bool) $this->getByte(); + $this->uvarint64 = $this->getUnsignedVarInt(); //TODO: varint64 + $this->args = json_decode($this->getString()); + $this->string4 = $this->getString(); + while(!$this->feof()){ + $this->getByte(); //prevent assertion errors. TODO: find out why there are always 3 extra bytes at the end of this packet. + } + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/ContainerOpenPacket.php b/src/devmine/server/network/protocol/ContainerOpenPacket.php index a437979..45617cf 100644 --- a/src/devmine/server/network/protocol/ContainerOpenPacket.php +++ b/src/devmine/server/network/protocol/ContainerOpenPacket.php @@ -26,11 +26,9 @@ public function encode(){ $this->reset(); $this->putByte($this->windowid); $this->putByte($this->type); - $this->putShort($this->slots); - $this->putInt($this->x); - $this->putInt($this->y); - $this->putInt($this->z); - $this->putLong($this->entityId); + $this->putVarInt($this->slots); + $this->putBlockCoords($this->x, $this->y, $this->z); + $this->putEntityId($this->entityId); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/ContainerSetContentPacket.php b/src/devmine/server/network/protocol/ContainerSetContentPacket.php index f63b5f2..f218253 100644 --- a/src/devmine/server/network/protocol/ContainerSetContentPacket.php +++ b/src/devmine/server/network/protocol/ContainerSetContentPacket.php @@ -13,6 +13,7 @@ class ContainerSetContentPacket extends DataPacket{ const SPECIAL_INVENTORY = 0; const SPECIAL_ARMOR = 0x78; const SPECIAL_CREATIVE = 0x79; + const SPECIAL_HOTBAR = 0x7a; public $windowid; public $slots = []; @@ -26,14 +27,14 @@ public function clean(){ public function decode(){ $this->windowid = $this->getByte(); - $count = $this->getShort(); + $count = $this->getUnsignedVarInt(); for($s = 0; $s < $count and !$this->feof(); ++$s){ $this->slots[$s] = $this->getSlot(); } if($this->windowid === self::SPECIAL_INVENTORY){ - $count = $this->getShort(); + $count = $this->getUnsignedVarInt(); for($s = 0; $s < $count and !$this->feof(); ++$s){ - $this->hotbar[$s] = $this->getInt(); + $this->hotbar[$s] = $this->getVarInt(); } } } @@ -41,17 +42,17 @@ public function decode(){ public function encode(){ $this->reset(); $this->putByte($this->windowid); - $this->putShort(count($this->slots)); + $this->putUnsignedVarInt(count($this->slots)); foreach($this->slots as $slot){ $this->putSlot($slot); } if($this->windowid === self::SPECIAL_INVENTORY and count($this->hotbar) > 0){ - $this->putShort(count($this->hotbar)); + $this->putUnsignedVarInt(count($this->hotbar)); foreach($this->hotbar as $slot){ - $this->putInt($slot); + $this->putVarInt($slot); } }else{ - $this->putShort(0); + $this->putUnsignedVarInt(0); } } diff --git a/src/devmine/server/network/protocol/ContainerSetDataPacket.php b/src/devmine/server/network/protocol/ContainerSetDataPacket.php index b129129..d5d139a 100644 --- a/src/devmine/server/network/protocol/ContainerSetDataPacket.php +++ b/src/devmine/server/network/protocol/ContainerSetDataPacket.php @@ -21,8 +21,8 @@ public function decode(){ public function encode(){ $this->reset(); $this->putByte($this->windowid); - $this->putShort($this->property); - $this->putShort($this->value); + $this->putVarInt($this->property); + $this->putVarInt($this->value); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/ContainerSetSlotPacket.php b/src/devmine/server/network/protocol/ContainerSetSlotPacket.php index cb98e03..2bea088 100644 --- a/src/devmine/server/network/protocol/ContainerSetSlotPacket.php +++ b/src/devmine/server/network/protocol/ContainerSetSlotPacket.php @@ -16,20 +16,23 @@ class ContainerSetSlotPacket extends DataPacket{ /** @var Item */ public $item; public $hotbarSlot; + public $unknown; public function decode(){ $this->windowid = $this->getByte(); - $this->slot = $this->getShort(); - $this->hotbarSlot = $this->getShort(); + $this->slot = $this->getVarInt(); + $this->hotbarSlot = $this->getVarInt(); $this->item = $this->getSlot(); + $this->unknown = $this->getByte(); } public function encode(){ $this->reset(); $this->putByte($this->windowid); - $this->putShort($this->slot); - $this->putShort($this->hotbarSlot); + $this->putVarInt($this->slot); + $this->putVarInt($this->hotbarSlot); $this->putSlot($this->item); + $this->putByte($this->unknown); } } diff --git a/src/devmine/server/network/protocol/CraftingDataPacket.php b/src/devmine/server/network/protocol/CraftingDataPacket.php index 4620fd7..382d94d 100644 --- a/src/devmine/server/network/protocol/CraftingDataPacket.php +++ b/src/devmine/server/network/protocol/CraftingDataPacket.php @@ -42,12 +42,12 @@ private static function writeEntry($entry, BinaryStream $stream){ } private static function writeShapelessRecipe(ShapelessRecipe $recipe, BinaryStream $stream){ - $stream->putInt($recipe->getIngredientCount()); + $stream->putUnsignedVarInt($recipe->getIngredientCount()); foreach($recipe->getIngredientList() as $item){ $stream->putSlot($item); } - $stream->putInt(1); + $stream->putUnsignedVarInt(1); $stream->putSlot($recipe->getResult()); $stream->putUUID($recipe->getId()); @@ -56,8 +56,8 @@ private static function writeShapelessRecipe(ShapelessRecipe $recipe, BinaryStre } private static function writeShapedRecipe(ShapedRecipe $recipe, BinaryStream $stream){ - $stream->putInt($recipe->getWidth()); - $stream->putInt($recipe->getHeight()); + $stream->putVarInt($recipe->getWidth()); + $stream->putVarInt($recipe->getHeight()); for($z = 0; $z < $recipe->getWidth(); ++$z){ for($x = 0; $x < $recipe->getHeight(); ++$x){ @@ -65,7 +65,7 @@ private static function writeShapedRecipe(ShapedRecipe $recipe, BinaryStream $st } } - $stream->putInt(1); + $stream->putUnsignedVarInt(1); $stream->putSlot($recipe->getResult()); $stream->putUUID($recipe->getId()); @@ -74,13 +74,14 @@ private static function writeShapedRecipe(ShapedRecipe $recipe, BinaryStream $st } private static function writeFurnaceRecipe(FurnaceRecipe $recipe, BinaryStream $stream){ - if($recipe->getInput()->getDamage() !== 0){ //Data recipe - $stream->putInt(($recipe->getInput()->getId() << 16) | ($recipe->getInput()->getDamage())); + if($recipe->getInput()->getDamage() !== null){ //Data recipe + $stream->putVarInt($recipe->getInput()->getId()); + $stream->putVarInt($recipe->getInput()->getDamage()); $stream->putSlot($recipe->getResult()); return CraftingDataPacket::ENTRY_FURNACE_DATA; }else{ - $stream->putInt($recipe->getInput()->getId()); + $stream->putVarInt($recipe->getInput()->getId()); $stream->putSlot($recipe->getResult()); return CraftingDataPacket::ENTRY_FURNACE; @@ -89,14 +90,14 @@ private static function writeFurnaceRecipe(FurnaceRecipe $recipe, BinaryStream $ private static function writeEnchantList(EnchantmentList $list, BinaryStream $stream){ - $stream->putByte($list->getSize()); + $stream->putUnsignedVarInt($list->getSize()); for($i = 0; $i < $list->getSize(); ++$i){ $entry = $list->getSlot($i); - $stream->putInt($entry->getCost()); - $stream->putByte(count($entry->getEnchantments())); + $stream->putUnsignedVarInt($entry->getCost()); + $stream->putUnsignedVarInt(count($entry->getEnchantments())); foreach($entry->getEnchantments() as $enchantment){ - $stream->putInt($enchantment->getId()); - $stream->putInt($enchantment->getLevel()); + $stream->putUnsignedVarInt($enchantment->getId()); + $stream->putUnsignedVarInt($enchantment->getLevel()); } $stream->putString($entry->getRandomName()); } @@ -131,18 +132,16 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putInt(count($this->entries)); + $this->putUnsignedVarInt(count($this->entries)); $writer = new BinaryStream(); foreach($this->entries as $d){ $entryType = self::writeEntry($d, $writer); if($entryType >= 0){ - $this->putInt($entryType); - $this->putInt(strlen($writer->getBuffer())); + $this->putVarInt($entryType); $this->put($writer->getBuffer()); }else{ - $this->putInt(-1); - $this->putInt(0); + $this->putVarInt(-1); } $writer->reset(); diff --git a/src/devmine/server/network/protocol/CraftingEventPacket.php b/src/devmine/server/network/protocol/CraftingEventPacket.php index d9ab65e..c7b506b 100644 --- a/src/devmine/server/network/protocol/CraftingEventPacket.php +++ b/src/devmine/server/network/protocol/CraftingEventPacket.php @@ -24,15 +24,15 @@ public function clean(){ public function decode(){ $this->windowId = $this->getByte(); - $this->type = $this->getInt(); + $this->type = $this->getVarInt(); $this->id = $this->getUUID(); - $size = $this->getInt(); + $size = $this->getUnsignedVarInt(); for($i = 0; $i < $size and $i < 128; ++$i){ $this->input[] = $this->getSlot(); } - $size = $this->getInt(); + $size = $this->getUnsignedVarInt(); for($i = 0; $i < $size and $i < 128; ++$i){ $this->output[] = $this->getSlot(); } diff --git a/src/devmine/server/network/protocol/DataPacket.php b/src/devmine/server/network/protocol/DataPacket.php index 88f1226..0325634 100644 --- a/src/devmine/server/network/protocol/DataPacket.php +++ b/src/devmine/server/network/protocol/DataPacket.php @@ -20,7 +20,6 @@ abstract class DataPacket extends BinaryStream{ const NETWORK_ID = 0; public $isEncoded = false; - private $channel = 0; public function pid(){ return $this::NETWORK_ID; @@ -35,18 +34,6 @@ public function reset(){ $this->offset = 0; } - /** - * @deprecated This adds extra overhead on the network, so its usage is now discouraged. It was a test for the viability of this. - */ - public function setChannel($channel){ - $this->channel = (int) $channel; - return $this; - } - - public function getChannel(){ - return $this->channel; - } - public function clean(){ $this->buffer = null; $this->isEncoded = false; diff --git a/src/devmine/server/network/protocol/DisconnectPacket.php b/src/devmine/server/network/protocol/DisconnectPacket.php index b6e9727..8f36a54 100644 --- a/src/devmine/server/network/protocol/DisconnectPacket.php +++ b/src/devmine/server/network/protocol/DisconnectPacket.php @@ -10,14 +10,21 @@ class DisconnectPacket extends DataPacket{ const NETWORK_ID = Info::DISCONNECT_PACKET; + public $hideDisconnectionScreen = false; public $message; public function decode(){ + $this->hideDisconnectionScreen = $this->getBool(); $this->message = $this->getString(); + if(!$this->feof()){ + var_dump(strlen($this->buffer) - $this->offset); + var_dump($buffer); + } } public function encode(){ $this->reset(); + $this->putBool($this->hideDisconnectionScreen); $this->putString($this->message); } diff --git a/src/devmine/server/network/protocol/EntityEventPacket.php b/src/devmine/server/network/protocol/EntityEventPacket.php index c970faa..119ec63 100644 --- a/src/devmine/server/network/protocol/EntityEventPacket.php +++ b/src/devmine/server/network/protocol/EntityEventPacket.php @@ -30,16 +30,19 @@ class EntityEventPacket extends DataPacket{ public $eid; public $event; + public $unknownVarInt; public function decode(){ - $this->eid = $this->getLong(); + $this->eid = $this->getEntityId(); $this->event = $this->getByte(); + $this->unknownVarInt = $this->getVarInt(); } public function encode(){ $this->reset(); - $this->putLong($this->eid); + $this->putEntityId($this->eid); $this->putByte($this->event); + $this->putVarInt($this->unknownVarInt); } } diff --git a/src/devmine/server/network/protocol/ExplodePacket.php b/src/devmine/server/network/protocol/ExplodePacket.php index 5ec42c0..5f956ad 100644 --- a/src/devmine/server/network/protocol/ExplodePacket.php +++ b/src/devmine/server/network/protocol/ExplodePacket.php @@ -27,16 +27,12 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putFloat($this->x); - $this->putFloat($this->y); - $this->putFloat($this->z); - $this->putFloat($this->radius); - $this->putInt(count($this->records)); + $this->putVector3f($this->x, $this->y, $this->z); + $this->putLFloat($this->radius); + $this->putUnsignedVarInt(count($this->records)); if(count($this->records) > 0){ foreach($this->records as $record){ - $this->putByte($record->x); - $this->putByte($record->y); - $this->putByte($record->z); + $this->putBlockCoords($record->x, $record->y, $record->z); } } } diff --git a/src/devmine/server/network/protocol/FullChunkDataPacket.php b/src/devmine/server/network/protocol/FullChunkDataPacket.php index b6d1523..66de1bd 100644 --- a/src/devmine/server/network/protocol/FullChunkDataPacket.php +++ b/src/devmine/server/network/protocol/FullChunkDataPacket.php @@ -9,13 +9,9 @@ class FullChunkDataPacket extends DataPacket{ const NETWORK_ID = Info::FULL_CHUNK_DATA_PACKET; - - const ORDER_COLUMNS = 0; - const ORDER_LAYERED = 1; public $chunkX; public $chunkZ; - public $order = self::ORDER_COLUMNS; public $data; public function decode(){ @@ -24,11 +20,9 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putInt($this->chunkX); - $this->putInt($this->chunkZ); - $this->putByte($this->order); - $this->putInt(strlen($this->data)); - $this->put($this->data); + $this->putVarInt($this->chunkX); + $this->putVarInt($this->chunkZ); + $this->putString($this->data); } } diff --git a/src/devmine/server/network/protocol/HurtArmorPacket.php b/src/devmine/server/network/protocol/HurtArmorPacket.php index 18bbef1..5e74ffa 100644 --- a/src/devmine/server/network/protocol/HurtArmorPacket.php +++ b/src/devmine/server/network/protocol/HurtArmorPacket.php @@ -18,7 +18,7 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putByte($this->health); + $this->putVarInt($this->health); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/Info.php b/src/devmine/server/network/protocol/Info.php index 0a6fde5..0a9e3a1 100644 --- a/src/devmine/server/network/protocol/Info.php +++ b/src/devmine/server/network/protocol/Info.php @@ -1,94 +1,98 @@ action = $this->getByte(); - $this->target = $this->getLong(); + $this->target = $this->getEntityId(); } public function encode(){ $this->reset(); $this->putByte($this->action); - $this->putLong($this->target); + $this->putEntityId($this->target); } } diff --git a/src/devmine/server/network/protocol/InventoryActionPacket.php b/src/devmine/server/network/protocol/InventoryActionPacket.php new file mode 100644 index 0000000..d07c48c --- /dev/null +++ b/src/devmine/server/network/protocol/InventoryActionPacket.php @@ -0,0 +1,24 @@ + + +class InventoryActionPacket extends DataPacket{ + const NETWORK_ID = Info::INVENTORY_ACTION_PACKET; + + public $unknown; //varint (unsigned) + public $item; + + public function decode(){ + $this->unknown = $this->getUnsignedVarInt(); + $this->item = $this->getSlot(); + } + + public function encode(){ + $this->putUnsignedVarInt($this->unknown); + $this->putSlot($this->item); + } +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/ItemFrameDropItemPacket.php b/src/devmine/server/network/protocol/ItemFrameDropItemPacket.php index 34de445..14e984c 100644 --- a/src/devmine/server/network/protocol/ItemFrameDropItemPacket.php +++ b/src/devmine/server/network/protocol/ItemFrameDropItemPacket.php @@ -1,6 +1,23 @@ z = $this->getInt(); - $this->y = $this->getInt(); - $this->x = $this->getInt(); + $this->getBlockCoords($this->x, $this->y, $this->z); $this->dropItem = $this->getSlot(); } diff --git a/src/devmine/server/network/protocol/LevelEventPacket.php b/src/devmine/server/network/protocol/LevelEventPacket.php index 85a0d95..a818d1f 100644 --- a/src/devmine/server/network/protocol/LevelEventPacket.php +++ b/src/devmine/server/network/protocol/LevelEventPacket.php @@ -28,15 +28,29 @@ class LevelEventPacket extends DataPacket{ const EVENT_SOUND_ZOMBIE_INFECT = 1016; const EVENT_SOUND_ZOMBIE_HEAL = 1017; const EVENT_SOUND_ENDERMAN_TELEPORT = 1018; - + + const EVENT_SOUND_ANVIL_BREAK = 1020; //This sound is played on the anvil's final use, NOT when the block is broken. const EVENT_SOUND_ANVIL_USE = 1021; const EVENT_SOUND_ANVIL_FALL = 1022; + + const EVENT_SOUND_DROP_ITEM = 1030; + const EVENT_SOUND_THROW_PROJECTILE = 1031; + + const EVENT_SOUND_ITEMFRAME_ADD_ITEM = 1040; + const EVENT_SOUND_ITEMFRAME_PLACE = 1041; + //1042 is item frame, but cannot tell exactly what. + const EVENT_SOUND_ITEMFRAME_DROP_ITEM = 1043; + const EVENT_SOUND_ITEMFRAME_ROTATE_ITEM = 1044; + + //1050 sounds a lot like skeleton walking but different. TODO: find out exactly what it is. + const EVENT_SOUND_EXP_PICKUP = 1051; + const EVENT_SOUND_BLOCK_PLACE = 1052; const EVENT_SOUND_BUTTON_CLICK = 3500; const EVENT_PARTICLE_SHOOT = 2000; const EVENT_PARTICLE_DESTROY = 2001; - const EVENT_PARTICLE_SPLASH = 2002; + const EVENT_PARTICLE_SPLASH = 2002; //This is actually the splash potion sound with particles const EVENT_PARTICLE_EYE_DESPAWN = 2003; const EVENT_PARTICLE_SPAWN = 2004; @@ -46,6 +60,7 @@ class LevelEventPacket extends DataPacket{ const EVENT_STOP_THUNDER = 3004; const EVENT_SOUND_EXPLODE = 3501; + /* 3502-3509 are splash SOUNDS with particles. Probably for cauldrons. */ const EVENT_SOUND_SPELL = 3504; const EVENT_SOUND_SPLASH = 3506; const EVENT_SOUND_GRAY_SPLASH = 3507;//TODO: fix name @@ -57,9 +72,9 @@ class LevelEventPacket extends DataPacket{ const EVENT_ADD_PARTICLE_MASK = 0x4000; public $evid; - public $x; - public $y; - public $z; + public $x = 0; //Weather effects don't have coordinates -_- + public $y = 0; + public $z = 0; public $data; public function decode(){ @@ -68,11 +83,9 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putShort($this->evid); - $this->putFloat($this->x); - $this->putFloat($this->y); - $this->putFloat($this->z); - $this->putInt($this->data); + $this->putVarInt($this->evid); + $this->putVector3f($this->x, $this->y, $this->z); + $this->putVarInt($this->data); } } diff --git a/src/devmine/server/network/protocol/LevelSoundEventPacket.php b/src/devmine/server/network/protocol/LevelSoundEventPacket.php new file mode 100644 index 0000000..63b010d --- /dev/null +++ b/src/devmine/server/network/protocol/LevelSoundEventPacket.php @@ -0,0 +1,133 @@ + + +class LevelSoundEventPacket extends DataPacket{ + const NETWORK_ID = Info::LEVEL_SOUND_EVENT_PACKET; + + //Thanks to PMMP + const SOUND_ITEM_USE_ON = 0; + const SOUND_HIT = 1; + const SOUND_STEP = 2; + const SOUND_JUMP = 3; + const SOUND_BREAK = 4; + const SOUND_PLACE = 5; + const SOUND_HEAVY_STEP = 6; + const SOUND_GALLOP = 7; + const SOUND_FALL = 8; + const SOUND_AMBIENT = 9; + const SOUND_AMBIENT_BABY = 10; + const SOUND_AMBIENT_IN_WATER = 11; + const SOUND_BREATHE = 12; + const SOUND_DEATH = 13; + const SOUND_DEATH_IN_WATER = 14; + const SOUND_DEATH_TO_ZOMBIE = 15; + const SOUND_HURT = 16; + const SOUND_HURT_IN_WATER = 17; + const SOUND_MAD = 18; + const SOUND_BOOST = 19; + const SOUND_BOW = 20; + const SOUND_SQUISH_BIG = 21; + const SOUND_SQUISH_SMALL = 22; + const SOUND_FALL_BIG = 23; + const SOUND_FALL_SMALL = 24; + const SOUND_SPLASH = 25; + const SOUND_FIZZ = 26; + const SOUND_FLAP = 27; + const SOUND_SWIM = 28; + const SOUND_DRINK = 29; + const SOUND_EAT = 30; + const SOUND_TAKEOFF = 31; + const SOUND_SHAKE = 32; + const SOUND_PLOP = 33; + const SOUND_LAND = 34; + const SOUND_SADDLE = 35; + const SOUND_ARMOR = 36; + const SOUND_ADD_CHEST = 37; + const SOUND_THROW = 38; + const SOUND_ATTACK = 39; + const SOUND_ATTACK_NODAMAGE = 40; + const SOUND_WARN = 41; + const SOUND_SHEAR = 42; + const SOUND_MILK = 43; + const SOUND_THUNDER = 44; + const SOUND_EXPLODE = 45; + const SOUND_FIRE = 46; + const SOUND_IGNITE = 47; + const SOUND_FUSE = 48; + const SOUND_STARE = 49; + const SOUND_SPAWN = 50; + const SOUND_SHOOT = 51; + const SOUND_BREAK_BLOCK = 52; + const SOUND_REMEDY = 53; + const SOUND_UNFECT = 54; + const SOUND_LEVELUP = 55; + const SOUND_BOW_HIT = 56; + const SOUND_BULLET_HIT = 57; + const SOUND_EXTINGUISH_FIRE = 58; + const SOUND_ITEM_FIZZ = 59; + const SOUND_CHEST_OPEN = 60; + const SOUND_CHEST_CLOSED = 61; + const SOUND_POWER_ON = 62; + const SOUND_POWER_OFF = 63; + const SOUND_ATTACH = 64; + const SOUND_DETACH = 65; + const SOUND_DENY = 66; + const SOUND_TRIPOD = 67; + const SOUND_POP = 68; + const SOUND_DROP_SLOT = 69; + const SOUND_NOTE = 70; + const SOUND_THORNS = 71; + const SOUND_PISTON_IN = 72; + const SOUND_PISTON_OUT = 73; + const SOUND_PORTAL = 74; + const SOUND_WATER = 75; + const SOUND_LAVA_POP = 76; + const SOUND_LAVA = 77; + const SOUND_BURP = 78; + const SOUND_BUCKET_FILL_WATER = 79; + const SOUND_BUCKET_FILL_LAVA = 80; + const SOUND_BUCKET_EMPTY_WATER = 81; + const SOUND_BUCKET_EMPTY_LAVA = 82; + const SOUND_GUARDIAN_FLOP = 83; + const SOUND_ELDERGUARDIAN_CURSE = 84; + const SOUND_MOB_WARNING = 85; + const SOUND_MOB_WARNING_BABY = 86; + const SOUND_TELEPORT = 87; + const SOUND_SHULKER_OPEN = 88; + const SOUND_SHULKER_CLOSE = 89; + const SOUND_DEFAULT = 90; + const SOUND_UNDEFINED = 91; + + public $sound; + public $x; + public $y; + public $z; + public $volume; + public $pitch; + public $unknownBool; + public $unknownBool2; + + public function decode(){ + $this->sound = $this->getByte(); + $this->getVector3f($this->x, $this->y, $this->z); + $this->volume = $this->getVarInt(); + $this->pitch = $this->getVarInt(); + $this->unknownBool = $this->getBool(); + $this->unknownBool2 = $this->getBool(); + } + + public function encode(){ + $this->reset(); + $this->putByte($this->sound); + $this->putVector3f($this->x, $this->y, $this->z); + $this->putVarInt($this->volume); + $this->putVarInt($this->pitch); + $this->putBool($this->unknownBool); + $this->putBool($this->unknownBool2); + } +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/LoginPacket.php b/src/devmine/server/network/protocol/LoginPacket.php index 0ecba9d..5fdc26a 100644 --- a/src/devmine/server/network/protocol/LoginPacket.php +++ b/src/devmine/server/network/protocol/LoginPacket.php @@ -10,46 +10,65 @@ class LoginPacket extends DataPacket{ const NETWORK_ID = Info::LOGIN_PACKET; + const MOJANG_PUBKEY = "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V"; + + const EDITION_POCKET = 0; + public $username; public $protocol; - + public $gameEdition; public $clientUUID; public $clientId; - public $identityPublickey; + public $identityPublicKey; public $serverAddress; public $skinId = null; public $skin = null; public function decode(){ - //$this->username = $this->getString(); - //$this->protocol1 = $this->getInt(); - //$this->protocol2 = $this->getInt(); - /*if($this->protocol1 < Info::CURRENT_PROTOCOL){ //New fields! - $this->setBuffer(null, 0); //Skip batch packet handling - return; - }*/ $this->protocol = $this->getInt(); - - $str = zlib_decode($this->get($this->getInt()),1024 *1024 * 64); - $this->setBuffer($str,0); - - $chainData = json_decode($this->get($this->getLInt())); - foreach($chainData->{"chain"} as $chain){ - $webtoken = $this->decodeToken($chain); - if(isset($webtoken["extraData"])){ - if(isset($webtoken["extraData"]["displayName"])){ - $this->username = $webtoken["extraData"]["displayName"]; + if($this->protocol !== Info::CURRENT_PROTOCOL){ + return; //Do not attempt to decode for non-accepted protocols + } + $this->gameEdition = $this->getByte(); + $str = zlib_decode($this->getString(), 1024 * 1024 * 64); + $this->setBuffer($str, 0); + + $time = time(); + + $chainData = json_decode($this->get($this->getLInt()))->{"chain"}; + // Start with the trusted one + $chainKey = self::MOJANG_PUBKEY; + while(!empty($chainData)){ + foreach($chainData as $index => $chain){ + list($verified, $webtoken) = $this->decodeToken($chain, $chainKey); + if(isset($webtoken["extraData"])){ + if(isset($webtoken["extraData"]["displayName"])){ + $this->username = $webtoken["extraData"]["displayName"]; + } + if(isset($webtoken["extraData"]["identity"])){ + $this->clientUUID = $webtoken["extraData"]["identity"]; + } } - if(isset($webtoken["extraData"]["identity"])){ - $this->clientUUID = $webtoken["extraData"]["identity"]; + if($verified){ + $verified = isset($webtoken["nbf"]) && $webtoken["nbf"] <= $time && isset($webtoken["exp"]) && $webtoken["exp"] > $time; } - if(isset($webtoken["identityPublicKey"])){ - $this->identityPublicKey = $webtoken["identityPublicKey"]; + if($verified and isset($webtoken["identityPublicKey"])){ + // Looped key chain. #blamemojang + if($webtoken["identityPublicKey"] != self::MOJANG_PUBKEY) $chainKey = $webtoken["identityPublicKey"]; + break; + }elseif($chainKey === null){ + // We have already gave up + break; } } + if(!$verified && $chainKey !== null){ + $chainKey = null; + }else{ + unset($chainData[$index]); + } } - $skinToken = $this->decodeToken($this->get($this->getLInt())); + list($verified, $skinToken) = $this->decodeToken($this->get($this->getLInt()), $chainKey); if(isset($skinToken["ClientRandomId"])){ $this->clientId = $skinToken["ClientRandomId"]; } @@ -62,17 +81,44 @@ public function decode(){ if(isset($skinToken["SkinId"])){ $this->skinId = $skinToken["SkinId"]; } + if($verified){ + $this->identityPublicKey = $chainKey; + } } public function encode(){ } - public function decodeToken($token){ + public function decodeToken($token, $key){ $tokens = explode(".", $token); list($headB64, $payloadB64, $sigB64) = $tokens; - - return json_decode(base64_decode($payloadB64), true); + + if($key !== null and extension_loaded("openssl")){ + $sig = base64_decode(strtr($sigB64, '-_', '+/'), true); + $rawLen = 48; // ES384 + for($i = $rawLen; $i > 0 and $sig[$rawLen - $i] == chr(0); $i--) {} + $j = $i + (ord($sig[$rawLen - $i]) >= 128 ? 1 : 0); + for($k = $rawLen; $k > 0 and $sig[2 * $rawLen - $k] == chr(0); $k--) {} + $l = $k + (ord($sig[2 * $rawLen - $k]) >= 128 ? 1 : 0); + $len = 2 + $j + 2 + $l; + $derSig = chr(48); + if($len > 255){ + throw new \RuntimeException("Invalid signature format"); + }elseif($len >= 128){ + $derSig .= chr(81); + } + $derSig .= chr($len) . chr(2) . chr($j); + $derSig .= str_repeat(chr(0), $j - $i) . substr($sig, $rawLen - $i, $i); + $derSig .= chr(2) . chr($l); + $derSig .= str_repeat(chr(0), $l - $k) . substr($sig, 2 * $rawLen - $k, $k); + + $verified = openssl_verify($headB64 . "." . $payloadB64, $derSig, "-----BEGIN PUBLIC KEY-----\n" . wordwrap($key, 64, "\n", true) . "\n-----END PUBLIC KEY-----\n", OPENSSL_ALGO_SHA384) === 1; + }else{ + $verified = false; + } + + return array($verified, json_decode(base64_decode($payloadB64), true)); } -} \ No newline at end of file +} diff --git a/src/devmine/server/network/protocol/MobArmorEquipmentPacket.php b/src/devmine/server/network/protocol/MobArmorEquipmentPacket.php index 0a55dd3..44b3b4f 100644 --- a/src/devmine/server/network/protocol/MobArmorEquipmentPacket.php +++ b/src/devmine/server/network/protocol/MobArmorEquipmentPacket.php @@ -14,7 +14,7 @@ class MobArmorEquipmentPacket extends DataPacket{ public $slots = []; public function decode(){ - $this->eid = $this->getLong(); + $this->eid = $this->getEntityId(); $this->slots[0] = $this->getSlot(); $this->slots[1] = $this->getSlot(); $this->slots[2] = $this->getSlot(); @@ -23,7 +23,7 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putLong($this->eid); + $this->putEntityId($this->eid); $this->putSlot($this->slots[0]); $this->putSlot($this->slots[1]); $this->putSlot($this->slots[2]); diff --git a/src/devmine/server/network/protocol/MobEffectPacket.php b/src/devmine/server/network/protocol/MobEffectPacket.php index dd80e3c..e893eb2 100644 --- a/src/devmine/server/network/protocol/MobEffectPacket.php +++ b/src/devmine/server/network/protocol/MobEffectPacket.php @@ -27,12 +27,12 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putLong($this->eid); + $this->putEntityId($this->eid); $this->putByte($this->eventId); - $this->putByte($this->effectId); - $this->putByte($this->amplifier); - $this->putByte($this->particles ? 1 : 0); - $this->putInt($this->duration); + $this->putVarInt($this->effectId); + $this->putVarInt($this->amplifier); + $this->putBool($this->particles); + $this->putVarInt($this->duration); } } diff --git a/src/devmine/server/network/protocol/MobEquipmentPacket.php b/src/devmine/server/network/protocol/MobEquipmentPacket.php index c6fbf4c..a697076 100644 --- a/src/devmine/server/network/protocol/MobEquipmentPacket.php +++ b/src/devmine/server/network/protocol/MobEquipmentPacket.php @@ -14,20 +14,23 @@ class MobEquipmentPacket extends DataPacket{ public $item; public $slot; public $selectedSlot; + public $unknown; //byte public function decode(){ - $this->eid = $this->getLong(); + $this->eid = $this->getEntityId(); $this->item = $this->getSlot(); $this->slot = $this->getByte(); $this->selectedSlot = $this->getByte(); + $this->unknown = $this->getByte(); } public function encode(){ $this->reset(); - $this->putLong($this->eid); + $this->putEntityId($this->eid); $this->putSlot($this->item); $this->putByte($this->slot); $this->putByte($this->selectedSlot); + $this->putByte($this->unknown); } } diff --git a/src/devmine/server/network/protocol/MoveEntityPacket.php b/src/devmine/server/network/protocol/MoveEntityPacket.php index a045a89..4e60e04 100644 --- a/src/devmine/server/network/protocol/MoveEntityPacket.php +++ b/src/devmine/server/network/protocol/MoveEntityPacket.php @@ -19,10 +19,8 @@ class MoveEntityPacket extends DataPacket{ public $pitch; public function decode(){ - $this->eid = $this->getLong(); - $this->x = $this->getFloat(); - $this->y = $this->getFloat(); - $this->z = $this->getFloat(); + $this->eid = $this->getEntityId(); + $this->getVector3f($this->x, $this->y, $this->z); $this->pitch = $this->getByte()*(360.0/256); $this->yaw = $this->getByte()*(360.0/256); $this->headYaw = $this->getByte()*(360.0/256); @@ -30,10 +28,8 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putLong($this->eid); - $this->putFloat($this->x); - $this->putFloat($this->y); - $this->putFloat($this->z); + $this->putEntityId($this->eid); + $this->putVector3f($this->x, $this->y, $this->z); $this->putByte($this->pitch/(360.0/256)); $this->putByte($this->yaw/(360.0/256)); $this->putByte($this->headYaw/(360.0/256)); diff --git a/src/devmine/server/network/protocol/MovePlayerPacket.php b/src/devmine/server/network/protocol/MovePlayerPacket.php index f9b6fbb..de247e6 100644 --- a/src/devmine/server/network/protocol/MovePlayerPacket.php +++ b/src/devmine/server/network/protocol/MovePlayerPacket.php @@ -30,28 +30,24 @@ public function clean(){ } public function decode(){ - $this->eid = $this->getLong(); - $this->x = $this->getFloat(); - $this->y = $this->getFloat(); - $this->z = $this->getFloat(); - $this->yaw = $this->getFloat(); - $this->bodyYaw = $this->getFloat(); - $this->pitch = $this->getFloat(); + $this->eid = $this->getEntityId(); + $this->getVector3f($this->x, $this->y, $this->z); + $this->pitch = $this->getLFloat(); + $this->yaw = $this->getLFloat(); + $this->bodyYaw = $this->getLFloat(); $this->mode = $this->getByte(); - $this->onGround = $this->getByte() > 0; + $this->onGround = $this->getBool(); } public function encode(){ $this->reset(); - $this->putLong($this->eid); - $this->putFloat($this->x); - $this->putFloat($this->y); - $this->putFloat($this->z); - $this->putFloat($this->yaw); - $this->putFloat($this->bodyYaw); //TODO - $this->putFloat($this->pitch); + $this->putEntityId($this->eid); + $this->putVector3f($this->x, $this->y, $this->z); + $this->putLFloat($this->pitch); + $this->putLFloat($this->yaw); + $this->putLFloat($this->bodyYaw); //TODO $this->putByte($this->mode); - $this->putByte($this->onGround > 0); + $this->putBool($this->onGround); } } diff --git a/src/devmine/server/network/protocol/PlayStatusPacket.php b/src/devmine/server/network/protocol/PlayStatusPacket.php index 246737b..dd4d15e 100644 --- a/src/devmine/server/network/protocol/PlayStatusPacket.php +++ b/src/devmine/server/network/protocol/PlayStatusPacket.php @@ -14,6 +14,8 @@ class PlayStatusPacket extends DataPacket{ const LOGIN_FAILED_CLIENT = 1; const LOGIN_FAILED_SERVER = 2; const PLAYER_SPAWN = 3; + const INVALID_TENANT = 4; + const EDITION_MISMATCH = 5; public $status; diff --git a/src/devmine/server/network/protocol/PlayerActionPacket.php b/src/devmine/server/network/protocol/PlayerActionPacket.php index ee6088a..8cf6d68 100644 --- a/src/devmine/server/network/protocol/PlayerActionPacket.php +++ b/src/devmine/server/network/protocol/PlayerActionPacket.php @@ -14,10 +14,10 @@ class PlayerActionPacket extends DataPacket{ const ACTION_ABORT_BREAK = 1; const ACTION_STOP_BREAK = 2; - const ACTION_RELEASE_ITEM = 5; const ACTION_STOP_SLEEPING = 6; const ACTION_SPAWN_SAME_DIMENSION = 7; + const ACTION_RESPAWN = 7; const ACTION_JUMP = 8; const ACTION_START_SPRINT = 9; const ACTION_STOP_SPRINT = 10; @@ -25,6 +25,8 @@ class PlayerActionPacket extends DataPacket{ const ACTION_STOP_SNEAK = 12; const ACTION_SPAWN_OVERWORLD = 13; const ACTION_SPAWN_NETHER = 14; + const ACTION_START_GLIDING = 15; + const ACTION_STOP_GLIDING = 16; public $eid; public $action; @@ -34,22 +36,18 @@ class PlayerActionPacket extends DataPacket{ public $face; public function decode(){ - $this->eid = $this->getLong(); - $this->action = $this->getInt(); - $this->x = $this->getInt(); - $this->y = $this->getInt(); - $this->z = $this->getInt(); - $this->face = $this->getInt(); + $this->eid = $this->getVarInt(); + $this->action = $this->getVarInt(); + $this->getBlockCoords($this->x, $this->y, $this->z); + $this->face = $this->getVarInt(); } public function encode(){ $this->reset(); - $this->putLong($this->eid); - $this->putInt($this->action); - $this->putInt($this->x); - $this->putInt($this->y); - $this->putInt($this->z); - $this->putInt($this->face); + $this->putVarInt($this->eid); + $this->putVarInt($this->action); + $this->putBlockCoords($this->x, $this->y, $this->z); + $this->putVarInt($this->face); } } diff --git a/src/devmine/server/network/protocol/PlayerFallPacket.php b/src/devmine/server/network/protocol/PlayerFallPacket.php new file mode 100644 index 0000000..306a008 --- /dev/null +++ b/src/devmine/server/network/protocol/PlayerFallPacket.php @@ -0,0 +1,22 @@ + + + +class PlayerFallPacket extends DataPacket{ + + const NETWORK_ID = Info::PLAYER_FALL_PACKET; + public $fallDistance; + + public function decode(){ + $this->fallDistance = $this->getLFloat(); + } + + public function encode(){ + + } +} diff --git a/src/devmine/server/network/protocol/PlayerInputPacket.php b/src/devmine/server/network/protocol/PlayerInputPacket.php index 0890989..3b1b3fd 100644 --- a/src/devmine/server/network/protocol/PlayerInputPacket.php +++ b/src/devmine/server/network/protocol/PlayerInputPacket.php @@ -1,5 +1,7 @@ motX = $this->getFloat(); $this->motY = $this->getFloat(); $flags = $this->getByte(); + $this->unknownBool = $this->getBool(); + $this->unknownBool1 = $this->getBool(); + $this->unknownBool2 = $this->getBool(); $this->jumping = (($flags & 0x80) > 0); $this->sneaking = (($flags & 0x40) > 0); } diff --git a/src/devmine/server/network/protocol/PlayerListPacket.php b/src/devmine/server/network/protocol/PlayerListPacket.php index 4835b21..175ff26 100644 --- a/src/devmine/server/network/protocol/PlayerListPacket.php +++ b/src/devmine/server/network/protocol/PlayerListPacket.php @@ -13,7 +13,7 @@ class PlayerListPacket extends DataPacket{ const TYPE_ADD = 0; const TYPE_REMOVE = 1; - //REMOVE: UUID, ADD: UUID, entity id, name, isSlim, skin + //REMOVE: UUID, ADD: UUID, entity id, name, skinId, skin /** @var array[] */ public $entries = []; public $type; @@ -30,11 +30,11 @@ public function decode(){ public function encode(){ $this->reset(); $this->putByte($this->type); - $this->putInt(count($this->entries)); + $this->putUnsignedVarInt(count($this->entries)); foreach($this->entries as $d){ if($this->type === self::TYPE_ADD){ $this->putUUID($d[0]); - $this->putLong($d[1]); + $this->putEntityId($d[1]); $this->putString($d[2]); $this->putString($d[3]); $this->putString($d[4]); diff --git a/src/devmine/server/network/protocol/RemoveBlockPacket.php b/src/devmine/server/network/protocol/RemoveBlockPacket.php index 26fce91..8713a85 100644 --- a/src/devmine/server/network/protocol/RemoveBlockPacket.php +++ b/src/devmine/server/network/protocol/RemoveBlockPacket.php @@ -10,16 +10,12 @@ class RemoveBlockPacket extends DataPacket{ const NETWORK_ID = Info::REMOVE_BLOCK_PACKET; - public $eid; public $x; public $y; public $z; public function decode(){ - $this->eid = $this->getLong(); - $this->x = $this->getInt(); - $this->z = $this->getInt(); - $this->y = $this->getByte(); + $this->getBlockCoords($this->x, $this->y, $this->z); } public function encode(){ diff --git a/src/devmine/server/network/protocol/RemoveEntityPacket.php b/src/devmine/server/network/protocol/RemoveEntityPacket.php index 761a320..eb24a95 100644 --- a/src/devmine/server/network/protocol/RemoveEntityPacket.php +++ b/src/devmine/server/network/protocol/RemoveEntityPacket.php @@ -18,7 +18,7 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putLong($this->eid); + $this->putEntityId($this->eid); } } diff --git a/src/devmine/server/network/protocol/RemovePlayerPacket.php b/src/devmine/server/network/protocol/RemovePlayerPacket.php deleted file mode 100644 index 432b2b0..0000000 --- a/src/devmine/server/network/protocol/RemovePlayerPacket.php +++ /dev/null @@ -1,26 +0,0 @@ - - - -class RemovePlayerPacket extends DataPacket{ - const NETWORK_ID = Info::REMOVE_PLAYER_PACKET; - - public $eid; - public $clientId; - - public function decode(){ - - } - - public function encode(){ - $this->reset(); - $this->putLong($this->eid); - $this->putUUID($this->clientId); - } - -} diff --git a/src/devmine/server/network/protocol/ReplaceItemInSlotPacket.php b/src/devmine/server/network/protocol/ReplaceItemInSlotPacket.php new file mode 100644 index 0000000..cb0a577 --- /dev/null +++ b/src/devmine/server/network/protocol/ReplaceItemInSlotPacket.php @@ -0,0 +1,24 @@ + + + +class ReplaceItemInSlotPacket extends DataPacket{ + const NETWORK_ID = Info::REPLACE_ITEM_IN_SLOT_PACKET; + + public $item; + + public function decode(){ + + } + + public function encode(){ + $this->reset(); + $this->putSlot($this->item); + } + +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/ReplaceSelectedItemPacket.php b/src/devmine/server/network/protocol/ReplaceSelectedItemPacket.php new file mode 100644 index 0000000..dfb5843 --- /dev/null +++ b/src/devmine/server/network/protocol/ReplaceSelectedItemPacket.php @@ -0,0 +1,24 @@ + + + +class ReplaceSelectedItemPacket extends DataPacket{ + const NETWORK_ID = Info::REPLACE_SELECTED_ITEM_PACKET; + + public $item; + + public function decode(){ + + } + + public function encode(){ + $this->reset(); + $this->putSlot($this->item); + } + +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/RequestChunkRadiusPacket.php b/src/devmine/server/network/protocol/RequestChunkRadiusPacket.php index b3f7231..5d24caa 100644 --- a/src/devmine/server/network/protocol/RequestChunkRadiusPacket.php +++ b/src/devmine/server/network/protocol/RequestChunkRadiusPacket.php @@ -1,6 +1,23 @@ radius = $this->getInt(); + $this->radius = $this->getVarInt(); } public function encode(){ } -} \ No newline at end of file +} diff --git a/src/devmine/server/network/protocol/ResourcePackClientResponsePacket.php b/src/devmine/server/network/protocol/ResourcePackClientResponsePacket.php new file mode 100644 index 0000000..c1353ca --- /dev/null +++ b/src/devmine/server/network/protocol/ResourcePackClientResponsePacket.php @@ -0,0 +1,25 @@ + + + +class ResourcePackClientResponsePacket extends DataPacket{ + const NETWORK_ID = Info::RESOURCE_PACK_CLIENT_RESPONSE_PACKET; + + public $unknownByte; + public $unknownShort; + + public function decode(){ + $this->unknownByte = $this->getByte(); + $this->unknownShort = $this->getShort(); + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/ResourcePackInfoEntry.php b/src/devmine/server/network/protocol/ResourcePackInfoEntry.php new file mode 100644 index 0000000..ff725f7 --- /dev/null +++ b/src/devmine/server/network/protocol/ResourcePackInfoEntry.php @@ -0,0 +1,30 @@ +packId = $packId; + $this->version = $version; + $this->uint64 = $uint64; + } + + public function getPackId() : string{ + return $this->packId; + } + + public function getVersion() : string{ + return $this->version; + } + + public function getUint64(){ + return $this->uint64; + } + +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/ResourcePacksInfoPacket.php b/src/devmine/server/network/protocol/ResourcePacksInfoPacket.php new file mode 100644 index 0000000..93a57e4 --- /dev/null +++ b/src/devmine/server/network/protocol/ResourcePacksInfoPacket.php @@ -0,0 +1,40 @@ + + + +class ResourcePacksInfoPacket extends DataPacket{ + const NETWORK_ID = Info::RESOURCE_PACKS_INFO_PACKET; + + public $mustAccept = false; //force client to use selected resource packs + /** @var ResourcePackInfoEntry */ + public $behaviourPackEntries = []; + /** @var ResourcePackInfoEntry */ + public $resourcePackEntries = []; + + public function decode(){ + + } + + public function encode(){ + $this->reset(); + + $this->putBool($this->mustAccept); + $this->putShort(count($this->behaviourPackEntries)); + foreach($this->behaviourPackEntries as $entry){ + $this->putString($entry->getPackId()); + $this->putString($entry->getVersion()); + $this->putLong($entry->getUint64()); + } + $this->putShort(count($this->resourcePackEntries)); + foreach($this->resourcePackEntries as $entry){ + $this->putString($entry->getPackId()); + $this->putString($entry->getVersion()); + $this->putLong($entry->getUint64()); + } + } +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/RespawnPacket.php b/src/devmine/server/network/protocol/RespawnPacket.php index aa60030..116f3b2 100644 --- a/src/devmine/server/network/protocol/RespawnPacket.php +++ b/src/devmine/server/network/protocol/RespawnPacket.php @@ -15,16 +15,16 @@ class RespawnPacket extends DataPacket{ public $z; public function decode(){ - $this->x = $this->getFloat(); - $this->y = $this->getFloat(); - $this->z = $this->getFloat(); + $this->x = $this->getLFloat(); + $this->y = $this->getLFloat(); + $this->z = $this->getLFloat(); } public function encode(){ $this->reset(); - $this->putFloat($this->x); - $this->putFloat($this->y); - $this->putFloat($this->z); + $this->putLFloat($this->x); + $this->putLFloat($this->y); + $this->putLFloat($this->z); } } diff --git a/src/devmine/server/network/protocol/SetCommandsEnabledPacket.php b/src/devmine/server/network/protocol/SetCommandsEnabledPacket.php new file mode 100644 index 0000000..be1a46b --- /dev/null +++ b/src/devmine/server/network/protocol/SetCommandsEnabledPacket.php @@ -0,0 +1,20 @@ +reset(); + $this->putBool($this->enabled); + } +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/SetDifficultyPacket.php b/src/devmine/server/network/protocol/SetDifficultyPacket.php index afef53a..0d84689 100644 --- a/src/devmine/server/network/protocol/SetDifficultyPacket.php +++ b/src/devmine/server/network/protocol/SetDifficultyPacket.php @@ -13,12 +13,12 @@ class SetDifficultyPacket extends DataPacket{ public $difficulty; public function decode(){ - $this->difficulty = $this->getInt(); + $this->difficulty = $this->getUnsignedVarInt(); } public function encode(){ $this->reset(); - $this->putInt($this->difficulty); + $this->putUnsignedVarInt($this->difficulty); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/SetEntityDataPacket.php b/src/devmine/server/network/protocol/SetEntityDataPacket.php index b366314..211bdf8 100644 --- a/src/devmine/server/network/protocol/SetEntityDataPacket.php +++ b/src/devmine/server/network/protocol/SetEntityDataPacket.php @@ -15,7 +15,7 @@ class SetEntityDataPacket extends DataPacket{ const NETWORK_ID = Info::SET_ENTITY_DATA_PACKET; public $eid; - public $epilogos; + public $metadata; public function decode(){ @@ -23,8 +23,8 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putLong($this->eid); - $meta = Binary::writeepilogos($this->epilogos); + $this->putEntityId($this->eid); + $meta = Binary::writeMetadata($this->metadata); $this->put($meta); } diff --git a/src/devmine/server/network/protocol/SetEntityLinkPacket.php b/src/devmine/server/network/protocol/SetEntityLinkPacket.php index eb0e946..064ac03 100644 --- a/src/devmine/server/network/protocol/SetEntityLinkPacket.php +++ b/src/devmine/server/network/protocol/SetEntityLinkPacket.php @@ -25,8 +25,8 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putLong($this->from); - $this->putLong($this->to); + $this->putEntityId($this->from); + $this->putEntityId($this->to); $this->putByte($this->type); } diff --git a/src/devmine/server/network/protocol/SetEntityMotionPacket.php b/src/devmine/server/network/protocol/SetEntityMotionPacket.php index f407168..da0e532 100644 --- a/src/devmine/server/network/protocol/SetEntityMotionPacket.php +++ b/src/devmine/server/network/protocol/SetEntityMotionPacket.php @@ -9,16 +9,11 @@ class SetEntityMotionPacket extends DataPacket{ const NETWORK_ID = Info::SET_ENTITY_MOTION_PACKET; - - - // eid, motX, motY, motZ - /** @var array[] */ - public $entities = []; - - public function clean(){ - $this->entities = []; - return parent::clean(); - } + + public $eid; + public $motionX; + public $motionY; + public $motionZ; public function decode(){ @@ -26,13 +21,8 @@ public function decode(){ public function encode(){ $this->reset(); - //$this->putInt(count($this->entities)); - foreach($this->entities as $d){ - $this->putLong($d[0]); //eid - $this->putFloat($d[1]); //motX - $this->putFloat($d[2]); //motY - $this->putFloat($d[3]); //motZ - } + $this->putEntityId($this->eid); + $this->putVector3f($this->motionX, $this->motionY, $this->motionZ); } } diff --git a/src/devmine/server/network/protocol/SetHealthPacket.php b/src/devmine/server/network/protocol/SetHealthPacket.php index d5188eb..169984f 100644 --- a/src/devmine/server/network/protocol/SetHealthPacket.php +++ b/src/devmine/server/network/protocol/SetHealthPacket.php @@ -13,12 +13,12 @@ class SetHealthPacket extends DataPacket{ public $health; public function decode(){ - $this->health = $this->getInt(); + $this->health = $this->getVarInt(); } public function encode(){ $this->reset(); - $this->putInt($this->health); + $this->putVarInt($this->health); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/SetPlayerGameTypePacket.php b/src/devmine/server/network/protocol/SetPlayerGameTypePacket.php index 93255df..29bc270 100644 --- a/src/devmine/server/network/protocol/SetPlayerGameTypePacket.php +++ b/src/devmine/server/network/protocol/SetPlayerGameTypePacket.php @@ -1,20 +1,23 @@ class SetPlayerGameTypePacket extends DataPacket { - const NETWORK_ID = Info::SET_PLAYER_GAMETYPE_PACKET; + const NETWORK_ID = Info::SET_PLAYER_GAME_TYPE_PACKET; public $gamemode; public function decode() { - + $this->gamemode = $this->getVarInt(); } public function encode() { $this->reset(); - $this->putInt($this->gamemode); + $this->putVarInt($this->gamemode); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/SetSpawnPositionPacket.php b/src/devmine/server/network/protocol/SetSpawnPositionPacket.php index 83e5cc5..9d25df7 100644 --- a/src/devmine/server/network/protocol/SetSpawnPositionPacket.php +++ b/src/devmine/server/network/protocol/SetSpawnPositionPacket.php @@ -10,9 +10,12 @@ class SetSpawnPositionPacket extends DataPacket{ const NETWORK_ID = Info::SET_SPAWN_POSITION_PACKET; + public $unknownVarInt; public $x; public $y; public $z; + public $unknown; + public $unknownBool; public function decode(){ @@ -20,9 +23,9 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putInt($this->x); - $this->putInt($this->y); - $this->putInt($this->z); + $this->putVarInt($this->unknownVarInt); + $this->putBlockCoords($this->x, $this->y, $this->z); + $this->putBool($this->unknownBool); } } diff --git a/src/devmine/server/network/protocol/SetTimePacket.php b/src/devmine/server/network/protocol/SetTimePacket.php index 1187543..d067216 100644 --- a/src/devmine/server/network/protocol/SetTimePacket.php +++ b/src/devmine/server/network/protocol/SetTimePacket.php @@ -7,7 +7,7 @@ #include -use devmine\levels\Level; +use devmine\worlds\Level; class SetTimePacket extends DataPacket{ const NETWORK_ID = Info::SET_TIME_PACKET; @@ -21,8 +21,8 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putInt($this->time); - $this->putByte($this->started ? 1 : 0); + $this->putVarInt($this->time); + $this->putBool($this->started); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/ShowCreditsPacket.php b/src/devmine/server/network/protocol/ShowCreditsPacket.php new file mode 100644 index 0000000..a8cc4b4 --- /dev/null +++ b/src/devmine/server/network/protocol/ShowCreditsPacket.php @@ -0,0 +1,24 @@ + + + +class ShowCreditsPacket extends DataPacket{ + const NETWORK_ID = Info::SHOW_CREDITS_PACKET; + + public $eid; + + public function decode(){ + $this->eid = $this->getEntityId(); //EntityRuntimeID + } + + public function encode(){ + $this->reset(); + $this->putEntityId($this->eid); //EntityRuntimeID + } + +} diff --git a/src/devmine/server/network/protocol/SpawnExperienceOrbPacket.php b/src/devmine/server/network/protocol/SpawnExperienceOrbPacket.php new file mode 100644 index 0000000..3df890c --- /dev/null +++ b/src/devmine/server/network/protocol/SpawnExperienceOrbPacket.php @@ -0,0 +1,27 @@ + + + +class SpawnExperienceOrbPacket extends DataPacket{ + const NETWORK_ID = Info::SPAWN_EXPERIENCE_ORB_PACKET; + + public $x; + public $y; + public $z; + public $amount; + + public function decode(){ + + } + + public function encode(){ + $this->reset(); + $this->putVector3f($this->x, $this->y, $this->z); + $this->putVarInt($this->amount); + } +} \ No newline at end of file diff --git a/src/devmine/server/network/protocol/StartGamePacket.php b/src/devmine/server/network/protocol/StartGamePacket.php index 12b8bb4..5c8e17f 100644 --- a/src/devmine/server/network/protocol/StartGamePacket.php +++ b/src/devmine/server/network/protocol/StartGamePacket.php @@ -10,18 +10,28 @@ class StartGamePacket extends DataPacket{ const NETWORK_ID = Info::START_GAME_PACKET; + public $entityUniqueId; + public $entityRuntimeId; + public $x; + public $y; + public $z; public $seed; public $dimension; - public $generator; + public $generator = 1; //default infinite - 0 old, 1 infinite, 2 flat public $gamemode; - public $eid; + public $difficulty; public $spawnX; public $spawnY; public $spawnZ; - public $x; - public $y; - public $z; + public $hasAchievementsDisabled = 1; + public $dayCycleStopTime = -1; //-1 = not stopped, any positive value = stopped at that time + public $eduMode = 0; + public $rainLevel; + public $lightningLevel; + public $commandsEnabled; + public $isTexturePacksRequired = 0; public $unknown; + public $worldName; public function decode(){ @@ -29,21 +39,26 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putInt($this->seed); - $this->putByte($this->dimension); - $this->putInt($this->generator); - $this->putInt($this->gamemode); - $this->putLong($this->eid); - $this->putInt($this->spawnX); - $this->putInt($this->spawnY); - $this->putInt($this->spawnZ); - $this->putFloat($this->x); - $this->putFloat($this->y); - $this->putFloat($this->z); - $this->putByte(1); - $this->putByte(1); - $this->putByte(0); + $this->putVarInt($this->entityUniqueId); //EntityUniqueID + $this->putVarInt($this->entityRuntimeId); //EntityRuntimeID + $this->putVector3f($this->x, $this->y, $this->z); + $this->putLFloat(0); //TODO: find out what these are (yaw/pitch?) + $this->putLFloat(0); + $this->putVarInt($this->seed); + $this->putVarInt($this->dimension); + $this->putVarInt($this->generator); + $this->putVarInt($this->gamemode); + $this->putVarInt($this->difficulty); + $this->putBlockCoords($this->spawnX, $this->spawnY, $this->spawnZ); + $this->putBool($this->hasAchievementsDisabled); + $this->putVarInt($this->dayCycleStopTime); + $this->putBool($this->eduMode); + $this->putLFloat($this->rainLevel); + $this->putLFloat($this->lightningLevel); + $this->putBool($this->commandsEnabled); + $this->putBool($this->isTexturePacksRequired); $this->putString($this->unknown); + $this->putString($this->worldName); } } diff --git a/src/devmine/server/network/protocol/StrangePacket.php b/src/devmine/server/network/protocol/StrangePacket.php deleted file mode 100644 index d3f467c..0000000 --- a/src/devmine/server/network/protocol/StrangePacket.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. - */ - -namespace devmine\server\network\protocol; - -class StrangePacket extends DataPacket{ - const NETWORK_ID = 0x1b; - - public $address; - public $port = 19132; - - public function pid(){ - return 0x1b; - } - - protected function putAddress($addr, $port, $version = 4){ - $this->putByte($version); - if($version === 4){ - foreach(explode(".", $addr) as $b){ - $this->putByte((~((int) $b)) & 0xff); - } - $this->putShort($port); - }else{ - //IPv6 - } - } - - public function decode(){ - - } - - public function encode(){ - $this->reset(); - $this->putAddress($this->address, $this->port); - } - -} diff --git a/src/devmine/server/network/protocol/TakeItemEntityPacket.php b/src/devmine/server/network/protocol/TakeItemEntityPacket.php index f170bdc..48e2226 100644 --- a/src/devmine/server/network/protocol/TakeItemEntityPacket.php +++ b/src/devmine/server/network/protocol/TakeItemEntityPacket.php @@ -19,8 +19,8 @@ public function decode(){ public function encode(){ $this->reset(); - $this->putLong($this->target); - $this->putLong($this->eid); + $this->putEntityId($this->target); + $this->putEntityId($this->eid); } } diff --git a/src/devmine/server/network/protocol/TextPacket.php b/src/devmine/server/network/protocol/TextPacket.php index eff9635..49586c4 100644 --- a/src/devmine/server/network/protocol/TextPacket.php +++ b/src/devmine/server/network/protocol/TextPacket.php @@ -16,6 +16,7 @@ class TextPacket extends DataPacket{ const TYPE_POPUP = 3; const TYPE_TIP = 4; const TYPE_SYSTEM = 5; + const TYPE_WHISPER = 6; public $type; public $source; @@ -36,7 +37,7 @@ public function decode(){ case self::TYPE_TRANSLATION: $this->message = $this->getString(); - $count = $this->getByte(); + $count = $this->getUnsignedVarInt(); for($i = 0; $i < $count; ++$i){ $this->parameters[] = $this->getString(); } @@ -58,7 +59,7 @@ public function encode(){ case self::TYPE_TRANSLATION: $this->putString($this->message); - $this->putByte(count($this->parameters)); + $this->putUnsignedVarInt(count($this->parameters)); foreach($this->parameters as $p){ $this->putString($p); } diff --git a/src/devmine/server/network/protocol/UpdateAttributesPacket.php b/src/devmine/server/network/protocol/UpdateAttributesPacket.php index 91e62aa..da7705e 100644 --- a/src/devmine/server/network/protocol/UpdateAttributesPacket.php +++ b/src/devmine/server/network/protocol/UpdateAttributesPacket.php @@ -1,23 +1,33 @@ + use devmine\creatures\entities\Attribute; + class UpdateAttributesPacket extends DataPacket{ + const NETWORK_ID = Info::UPDATE_ATTRIBUTES_PACKET; + public $entityId; /** @var Attribute[] */ public $entries = []; + public function decode(){ + } + public function encode(){ $this->reset(); - $this->putLong($this->entityId); - $this->putShort(count($this->entries)); + $this->putEntityId($this->entityId); + $this->putUnsignedVarInt(count($this->entries)); foreach($this->entries as $entry){ - $this->putFloat($entry->getMinValue()); - $this->putFloat($entry->getMaxValue()); - $this->putFloat($entry->getValue()); + $this->putLFloat($entry->getMinValue()); + $this->putLFloat($entry->getMaxValue()); + $this->putLFloat($entry->getValue()); + $this->putLFloat($entry->getDefaultValue()); $this->putString($entry->getName()); } } diff --git a/src/devmine/server/network/protocol/UpdateBlockPacket.php b/src/devmine/server/network/protocol/UpdateBlockPacket.php index f8bf4f4..8342711 100644 --- a/src/devmine/server/network/protocol/UpdateBlockPacket.php +++ b/src/devmine/server/network/protocol/UpdateBlockPacket.php @@ -19,7 +19,12 @@ class UpdateBlockPacket extends DataPacket{ const FLAG_ALL = (self::FLAG_NEIGHBORS | self::FLAG_NETWORK); const FLAG_ALL_PRIORITY = (self::FLAG_ALL | self::FLAG_PRIORITY); - public $records = []; //x, z, y, blockId, blockData, flags + public $x; + public $y; + public $z; + public $blockId; + public $blockData; + public $flags; public function decode(){ @@ -27,14 +32,9 @@ public function decode(){ public function encode(){ $this->reset(); - //$this->putInt(count($this->records)); - foreach($this->records as $r){ - $this->putInt($r[0]); - $this->putInt($r[1]); - $this->putByte($r[2]); - $this->putByte($r[3]); - $this->putByte(($r[5] << 4) | $r[4]); - } + $this->putBlockCoords($this->x, $this->y, $this->z); + $this->putUnsignedVarInt($this->blockId); + $this->putUnsignedVarInt(($this->flags << 4) | $this->blockData); } } \ No newline at end of file diff --git a/src/devmine/server/network/protocol/UseItemPacket.php b/src/devmine/server/network/protocol/UseItemPacket.php index 1f159f1..2ab81dd 100644 --- a/src/devmine/server/network/protocol/UseItemPacket.php +++ b/src/devmine/server/network/protocol/UseItemPacket.php @@ -14,6 +14,7 @@ class UseItemPacket extends DataPacket{ public $y; public $z; public $face; + public $blockid; public $item; public $fx; public $fy; @@ -24,21 +25,17 @@ class UseItemPacket extends DataPacket{ public $slot; public function decode(){ - $this->x = $this->getInt(); - $this->y = $this->getInt(); - $this->z = $this->getInt(); - $this->face = $this->getByte(); - $this->fx = $this->getFloat(); - $this->fy = $this->getFloat(); - $this->fz = $this->getFloat(); - $this->posX = $this->getFloat(); - $this->posY = $this->getFloat(); - $this->posZ = $this->getFloat(); - $this->slot = $this->getInt(); + $this->getBlockCoords($this->x, $this->y, $this->z); + $this->blockid = $this->getUnsignedVarInt(); + $this->face = $this->getVarInt(); + $this->getVector3f($this->fx, $this->fy, $this->fz); + $this->getVector3f($this->posX, $this->posY, $this->posZ); + $this->slot = $this->getVarInt(); $this->item = $this->getSlot(); } public function encode(){ } + } diff --git a/src/devmine/server/network/query/QueryHandler.php b/src/devmine/server/network/query/QueryHandler.php index 8a1a763..32b10db 100644 --- a/src/devmine/server/network/query/QueryHandler.php +++ b/src/devmine/server/network/query/QueryHandler.php @@ -8,7 +8,7 @@ */ namespace devmine\server\network\query; -use devmine\Server; +use devmine\server\server; use devmine\utilities\main\Binary; use devmine\utilities\main\Utils; @@ -20,10 +20,10 @@ class QueryHandler{ public function __construct(){ $this->server = Server::getInstance(); - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.server.query.start")); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.server.query.start")); $addr = ($ip = $this->server->getIp()) != "" ? $ip : "0.0.0.0"; $port = $this->server->getPort(); - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.server.query.info", [$port])); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.server.query.info", [$port])); /* The Query protocol is built on top of the existing Minecraft PE UDP network stack. Because the 0xFE packet does not exist in the MCPE protocol, @@ -36,7 +36,7 @@ public function __construct(){ $this->regenerateToken(); $this->lastToken = $this->token; $this->regenerateInfo(); - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.server.query.running", [$addr, $port])); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.server.query.running", [$addr, $port])); } public function regenerateInfo(){ @@ -48,7 +48,7 @@ public function regenerateInfo(){ public function regenerateToken(){ $this->lastToken = $this->token; - $this->token = @Utils::getRandomBytes(16, false); + $this->token = random_bytes(16); } public static function getTokenString($token, $salt){ diff --git a/src/devmine/server/network/rcon/RCON.php b/src/devmine/server/network/rcon/RCON.php index 6d4cc6a..e297270 100644 --- a/src/devmine/server/network/rcon/RCON.php +++ b/src/devmine/server/network/rcon/RCON.php @@ -12,9 +12,9 @@ namespace devmine\server\network\rcon; use devmine\server\commands\RemoteConsoleCommandSender; -use devmine\server\events\server\RemoteServerCommandEvent; +use devmine\events\server\RemoteServerCommandEvent; use devmine\utilities\main\Utils; -use devmine\Server; +use devmine\server\server; class RCON{ const PROTOCOL_VERSION = 3; diff --git a/src/devmine/server/network/rcon/RCONInstance.php b/src/devmine/server/network/rcon/RCONInstance.php index 320df18..ffc95d2 100644 --- a/src/devmine/server/network/rcon/RCONInstance.php +++ b/src/devmine/server/network/rcon/RCONInstance.php @@ -4,7 +4,7 @@ namespace devmine\server\network\rcon; -use devmine\Thread; +use devmine\server\Thread; use devmine\utilities\main\Binary; use devmine\utilities\main\MainLogger; @@ -114,7 +114,7 @@ public function run(){ $this->{"status" . $n} = -1; continue; } - $p = $this->readPacket($client, $size, $requestD, $packetType, $payload); + $p = $this->readPacket($client, $size, $requestID, $packetType, $payload); if($p === false){ $this->{"status" . $n} = -1; continue; diff --git a/src/devmine/server/network/upnp/UPnP.php b/src/devmine/server/network/upnp/UPnP.php index d85b452..7c0d368 100644 --- a/src/devmine/server/network/upnp/UPnP.php +++ b/src/devmine/server/network/upnp/UPnP.php @@ -14,7 +14,7 @@ public static function PortForward($port){ if(Utils::$online === false){ return false; } - if(Utils::getOS() != "win" or !class_exists("COM")){ + if(Utils::getOS() != "win" or !class_exists("COM", false)){ return false; } $port = (int) $port; @@ -24,7 +24,7 @@ public static function PortForward($port){ if($com === false or !is_object($com->StaticPortMappingCollection)){ return false; } - $com->StaticPortMappingCollection->Add($port, "UDP", $port, $myLocalIP, true, "devmine-MP"); + $com->StaticPortMappingCollection->Add($port, "UDP", $port, $myLocalIP, true, "DevMine-MP"); }catch(\Throwable $e){ return false; } @@ -52,4 +52,4 @@ public static function RemovePortForward($port){ return true; } -} \ No newline at end of file +} diff --git a/src/devmine/server/permissions/BanEntry.php b/src/devmine/server/perms/BanEntry.php similarity index 84% rename from src/devmine/server/permissions/BanEntry.php rename to src/devmine/server/perms/BanEntry.php index b767a3c..9f5c94e 100644 --- a/src/devmine/server/permissions/BanEntry.php +++ b/src/devmine/server/perms/BanEntry.php @@ -2,7 +2,9 @@ -namespace devmine\server\permissions; +namespace devmine\server\perms; + +use devmine\utilities\main\MainLogger; class BanEntry{ public static $format = "Y-m-d H:i:s O"; @@ -92,7 +94,12 @@ public static function fromString($str){ $str = explode("|", trim($str)); $entry = new BanEntry(trim(array_shift($str))); if(count($str) > 0){ - $entry->setCreated(\DateTime::createFromFormat(self::$format, array_shift($str))); + $datetime = \DateTime::createFromFormat(self::$format, array_shift($str)); + if(!($datetime instanceof \DateTime)){ + MainLogger::getLogger()->alert("Error parsing date for BanEntry for player \"" . $entry->getName() . "\", the format may be invalid!"); + return $entry; + } + $entry->setCreated($datetime); if(count($str) > 0){ $entry->setSource(trim(array_shift($str))); if(count($str) > 0){ diff --git a/src/devmine/server/permissions/BanList.php b/src/devmine/server/perms/BanList.php similarity index 96% rename from src/devmine/server/permissions/BanList.php rename to src/devmine/server/perms/BanList.php index 1c5e508..ab5ff94 100644 --- a/src/devmine/server/permissions/BanList.php +++ b/src/devmine/server/perms/BanList.php @@ -2,9 +2,9 @@ -namespace devmine\server\permissions; +namespace devmine\server\perms; -use devmine\Server; +use devmine\server\server; use devmine\utilities\main\MainLogger; class BanList{ @@ -134,7 +134,7 @@ public function save($flag = true){ $fp = @fopen($this->file, "w"); if(is_resource($fp)){ if($flag === true){ - fwrite($fp, "# Updated " . strftime("%x %H:%M", time()) . " by " . Server::getInstance()->getName() . " " . Server::getInstance()->getdevmineVersion() . "\n"); + fwrite($fp, "# Updated " . strftime("%x %H:%M", time()) . " by " . Server::getInstance()->getName() . " " . Server::getInstance()->getDevMineVersion() . "\n"); fwrite($fp, "# victim name | ban date | banned by | banned until | reason\n\n"); } diff --git a/src/devmine/server/permissions/DefaultPermissions.php b/src/devmine/server/perms/DefaultPermissions.php similarity index 98% rename from src/devmine/server/permissions/DefaultPermissions.php rename to src/devmine/server/perms/DefaultPermissions.php index effea2f..7c1bec0 100644 --- a/src/devmine/server/permissions/DefaultPermissions.php +++ b/src/devmine/server/perms/DefaultPermissions.php @@ -2,12 +2,12 @@ -namespace devmine\server\permissions; +namespace devmine\server\perms; -use devmine\Server; +use devmine\server\server; abstract class DefaultPermissions{ - const ROOT = "devmine"; + const ROOT = "DevMine"; /** * @param Permission $perm @@ -27,7 +27,7 @@ public static function registerPermission(Permission $perm, Permission $parent = } public static function registerCorePermissions(){ - $parent = self::registerPermission(new Permission(self::ROOT, "Allows using all devmine commands and utilities")); + $parent = self::registerPermission(new Permission(self::ROOT, "Allows using all DevMine commands and utilities")); $broadcasts = self::registerPermission(new Permission(self::ROOT . ".broadcast", "Allows the user to receive all broadcast messages"), $parent); @@ -36,7 +36,7 @@ public static function registerCorePermissions(){ $broadcasts->recalculatePermissibles(); - $commands = self::registerPermission(new Permission(self::ROOT . ".command", "Allows using all devmine commands"), $parent); + $commands = self::registerPermission(new Permission(self::ROOT . ".command", "Allows using all DevMine commands"), $parent); $whitelist = self::registerPermission(new Permission(self::ROOT . ".command.whitelist", "Allows the user to modify the server whitelist", Permission::DEFAULT_OP), $commands); self::registerPermission(new Permission(self::ROOT . ".command.whitelist.add", "Allows the user to add a player to the server whitelist"), $whitelist); diff --git a/src/devmine/server/permissions/Permissible.php b/src/devmine/server/perms/Permissible.php similarity index 92% rename from src/devmine/server/permissions/Permissible.php rename to src/devmine/server/perms/Permissible.php index 6c21537..2a6c1e2 100644 --- a/src/devmine/server/permissions/Permissible.php +++ b/src/devmine/server/perms/Permissible.php @@ -2,9 +2,9 @@ -namespace devmine\server\permissions; +namespace devmine\server\perms; -use devmine\pluginfeatures\Plugin; +use devmine\consumer\plugin\Plugin; interface Permissible extends ServerOperator{ diff --git a/src/devmine/server/permissions/PermissibleBase.php b/src/devmine/server/perms/PermissibleBase.php similarity index 97% rename from src/devmine/server/permissions/PermissibleBase.php rename to src/devmine/server/perms/PermissibleBase.php index 3dd71e5..69d0c06 100644 --- a/src/devmine/server/permissions/PermissibleBase.php +++ b/src/devmine/server/perms/PermissibleBase.php @@ -2,11 +2,11 @@ -namespace devmine\server\permissions; +namespace devmine\server\perms; -use devmine\server\events\Timings; -use devmine\pluginfeatures\Plugin; -use devmine\Server; +use devmine\events\Timings; +use devmine\consumer\plugin\Plugin; +use devmine\server\server; use devmine\utilities\main\PluginException; class PermissibleBase implements Permissible{ diff --git a/src/devmine/server/permissions/Permission.php b/src/devmine/server/perms/Permission.php similarity index 98% rename from src/devmine/server/permissions/Permission.php rename to src/devmine/server/perms/Permission.php index f572d1d..c24fd31 100644 --- a/src/devmine/server/permissions/Permission.php +++ b/src/devmine/server/perms/Permission.php @@ -5,9 +5,9 @@ /** * Permission related classes */ -namespace devmine\server\permissions; +namespace devmine\server\perms; -use devmine\Server; +use devmine\server\server; /** * Represents a permission diff --git a/src/devmine/server/permissions/PermissionAttachment.php b/src/devmine/server/perms/PermissionAttachment.php similarity index 97% rename from src/devmine/server/permissions/PermissionAttachment.php rename to src/devmine/server/perms/PermissionAttachment.php index 3ac79d3..97dda4e 100644 --- a/src/devmine/server/permissions/PermissionAttachment.php +++ b/src/devmine/server/perms/PermissionAttachment.php @@ -2,9 +2,9 @@ -namespace devmine\server\permissions; +namespace devmine\server\perms; -use devmine\pluginfeatures\Plugin; +use devmine\consumer\plugin\Plugin; use devmine\utilities\main\PluginException; class PermissionAttachment{ diff --git a/src/devmine/server/permissions/PermissionAttachmentInfo.php b/src/devmine/server/perms/PermissionAttachmentInfo.php similarity index 96% rename from src/devmine/server/permissions/PermissionAttachmentInfo.php rename to src/devmine/server/perms/PermissionAttachmentInfo.php index 58a1450..28f1748 100644 --- a/src/devmine/server/permissions/PermissionAttachmentInfo.php +++ b/src/devmine/server/perms/PermissionAttachmentInfo.php @@ -2,7 +2,7 @@ -namespace devmine\server\permissions; +namespace devmine\server\perms; class PermissionAttachmentInfo{ diff --git a/src/devmine/server/permissions/PermissionRemovedExecutor.php b/src/devmine/server/perms/PermissionRemovedExecutor.php similarity index 83% rename from src/devmine/server/permissions/PermissionRemovedExecutor.php rename to src/devmine/server/perms/PermissionRemovedExecutor.php index 0ed57c6..f74995f 100644 --- a/src/devmine/server/permissions/PermissionRemovedExecutor.php +++ b/src/devmine/server/perms/PermissionRemovedExecutor.php @@ -2,7 +2,7 @@ -namespace devmine\server\permissions; +namespace devmine\server\perms; interface PermissionRemovedExecutor{ diff --git a/src/devmine/server/permissions/ServerOperator.php b/src/devmine/server/perms/ServerOperator.php similarity index 88% rename from src/devmine/server/permissions/ServerOperator.php rename to src/devmine/server/perms/ServerOperator.php index 602c54d..a675366 100644 --- a/src/devmine/server/permissions/ServerOperator.php +++ b/src/devmine/server/perms/ServerOperator.php @@ -2,7 +2,7 @@ -namespace devmine\server\permissions; +namespace devmine\server\perms; interface ServerOperator{ diff --git a/src/devmine/server/resources/command_default.json b/src/devmine/server/resources/command_default.json new file mode 100644 index 0000000..3d8c2c3 --- /dev/null +++ b/src/devmine/server/resources/command_default.json @@ -0,0 +1,19 @@ +{ + "aliases": [], + "description": "insert_description_here", + "overloads": { + "default": { + "input": { + "parameters": [ + { + "name": "args", + "type": "rawtext", + "optional": true + } + ] + }, + "output": {} + } + }, + "permission": "any" +} diff --git a/src/devmine/server/resources/creativeitems.json b/src/devmine/server/resources/creativeitems.json index 043545f..2f3f006 100644 --- a/src/devmine/server/resources/creativeitems.json +++ b/src/devmine/server/resources/creativeitems.json @@ -1 +1,4088 @@ -{ "Cobblestone":{"ID":4,"Damage":0}, "Stone Bricks":{"ID":98,"Damage":0}, "Mossy Stone Bricks":{"ID":98,"Damage":1}, "Cracked Stone Bricks":{"ID":98,"Damage":2}, "Chiseled Stone Bricks":{"ID":98,"Damage":3}, "Moss Stone":{"ID":48,"Damage":0}, "Oak Wood Planks":{"ID":5,"Damage":0}, "Spruce Wood Planks":{"ID":5,"Damage":1}, "Birch Wood Planks":{"ID":5,"Damage":2}, "Jungle Wood Planks":{"ID":5,"Damage":3}, "Acacia Wood Planks":{"ID":5,"Damage":4}, "Dark Oak Wood Planks":{"ID":5,"Damage":5}, "Bricks":{"ID":45,"Damage":0}, "Stone":{"ID":1,"Damage":0}, "Granite":{"ID":1,"Damage":1}, "Polished Granite":{"ID":1,"Damage":2}, "Diorite":{"ID":1,"Damage":3}, "Polished Diorite":{"ID":1,"Damage":4}, "Andesite":{"ID":1,"Damage":5}, "Polished Andesite":{"ID":1,"Damage":6}, "Dirt":{"ID":3,"Damage":0}, "Podzol":{"ID":243,"Damage":0}, "Grass":{"ID":2,"Damage":0}, "Mycelium":{"ID":110,"Damage":0}, "Clay Block":{"ID":82,"Damage":0}, "Hardened Clay":{"ID":172,"Damage":0}, "White Stained Clay":{"ID":159,"Damage":0}, "Orange Stained Clay":{"ID":159,"Damage":1}, "Magenta Stained Clay":{"ID":159,"Damage":2}, "Light Blue Stained Clay":{"ID":159,"Damage":3}, "Yellow Stained Clay":{"ID":159,"Damage":4}, "Lime Stained Clay":{"ID":159,"Damage":5}, "Pink Stained Clay":{"ID":159,"Damage":6}, "Gray Stained Clay":{"ID":159,"Damage":7}, "Light Gray Stained Clay":{"ID":159,"Damage":8}, "Cyan Stained Clay":{"ID":159,"Damage":9}, "Purple Stained Clay":{"ID":159,"Damage":10}, "Blue Stained Clay":{"ID":159,"Damage":11}, "Brown Stained Clay":{"ID":159,"Damage":12}, "Green Stained Clay":{"ID":159,"Damage":13}, "Red Stained Clay":{"ID":159,"Damage":14}, "Black Stained Clay":{"ID":159,"Damage":15}, "Sandstone":{"ID":24,"Damage":0}, "Chiseled Sandstone":{"ID":24,"Damage":1}, "Smooth Sandstone":{"ID":24,"Damage":2}, "Red Sandstone":{"ID":179,"Damage":0}, "Chiseled Red Sandstone":{"ID":179,"Damage":1}, "Smooth Red Sandstone":{"ID":179,"Damage":2}, "Sand":{"ID":12,"Damage":0}, "Red Sand":{"ID":12,"Damage":1}, "Gravel":{"ID":13,"Damage":0}, "Oak Wood":{"ID":17,"Damage":0}, "Spruce Wood":{"ID":17,"Damage":1}, "Birch Wood":{"ID":17,"Damage":2}, "Jungle Wood":{"ID":17,"Damage":3}, "Acacia Wood":{"ID":162,"Damage":0}, "Dark Oak Wood":{"ID":162,"Damage":1}, "Nether Bricks":{"ID":112,"Damage":0}, "Netherrack":{"ID":87,"Damage":0}, "Soul Sand":{"ID":88,"Damage":0}, "Bedrock":{"ID":7,"Damage":0}, "Cobblestone Stairs":{"ID":67,"Damage":0}, "Oak Wood Stairs":{"ID":53,"Damage":0}, "Spruce Wood Stairs":{"ID":134,"Damage":0}, "Birch Wood Stairs":{"ID":135,"Damage":0}, "Jungle Wood Stairs":{"ID":136,"Damage":0}, "Acacia Wood Stairs":{"ID":163,"Damage":0}, "Dark Oak Wood Stairs":{"ID":164,"Damage":0}, "Brick Stairs":{"ID":108,"Damage":0}, "Sandstone Stairs":{"ID":128,"Damage":0}, "Red Sandstone Stairs":{"ID":180,"Damage":0}, "Stone Brick Stairs":{"ID":109,"Damage":0}, "Nether Bricks Stairs":{"ID":114,"Damage":0}, "Quartz Stairs":{"ID":156,"Damage":0}, "Stone Slab":{"ID":44,"Damage":0}, "Cobblestone Slab":{"ID":44,"Damage":3}, "Oak Wooden Slab":{"ID":158,"Damage":0}, "Spruce Wooden Slab":{"ID":158,"Damage":1}, "Birch Wooden Slab":{"ID":158,"Damage":2}, "Jungle Wooden Slab":{"ID":158,"Damage":3}, "Acacia Wooden Slab":{"ID":158,"Damage":4}, "Dark Oak Wooden Slab":{"ID":158,"Damage":5}, "Bricks Slab":{"ID":44,"Damage":4}, "Sandstone Slab":{"ID":44,"Damage":1}, "Red Sandstone Slab":{"ID":182,"Damage":0}, "Stone Brick Slab":{"ID":44,"Damage":5}, "Quartz Slab":{"ID":44,"Damage":6}, "Nether Brick Slab":{"ID":44,"Damage":7}, "Quartz Block":{"ID":155,"Damage":0}, "Quartz Pillar":{"ID":155,"Damage":2}, "Chiseled Quartz Block":{"ID":155,"Damage":1}, "Coal Ore":{"ID":16,"Damage":0}, "Iron Ore":{"ID":15,"Damage":0}, "Gold Ore":{"ID":14,"Damage":0}, "Diamond Ore":{"ID":56,"Damage":0}, "Lapis Lazuli Ore":{"ID":21,"Damage":0}, "Redstone Ore":{"ID":73,"Damage":0}, "Emerald Ore":{"ID":129,"Damage":0}, "Nether Quartz Ore":{"ID":153,"Damage":0}, "Obsidian":{"ID":49,"Damage":0}, "Ice":{"ID":79,"Damage":0}, "Packed Ice":{"ID":174,"Damage":0}, "Snow Block":{"ID":80,"Damage":0}, "End Stone":{"ID":121,"Damage":0}, "Cobblestone Wall":{"ID":139,"Damage":0}, "Mossy Cobblestone Wall":{"ID":139,"Damage":1}, "Lily Pad":{"ID":111,"Damage":0}, "Gold Block":{"ID":41,"Damage":0}, "Iron Block":{"ID":42,"Damage":0}, "Diamond Block":{"ID":57,"Damage":0}, "Lapis Lazuli Block":{"ID":22,"Damage":0}, "Coal Block":{"ID":173,"Damage":0}, "Emerald Block":{"ID":133,"Damage":0}, "Redstone Block":{"ID":152,"Damage":0}, "Snow Layer":{"ID":78,"Damage":0}, "Glass":{"ID":20,"Damage":0}, "Glowstone":{"ID":89,"Damage":0}, "Vines":{"ID":106,"Damage":0}, "Ladder":{"ID":65,"Damage":0}, "Sponge":{"ID":19,"Damage":0}, "Glass Pane":{"ID":102,"Damage":0}, "Oak Door":{"ID":324,"Damage":1}, "Spruce Door":{"ID":427,"Damage":2}, "Birch Door":{"ID":428,"Damage":3}, "Jungle Door":{"ID":429,"Damage":4}, "Acacia Door":{"ID":430,"Damage":5}, "Dark Oak Door":{"ID":431,"Damage":6}, "Iron Door":{"ID":330,"Damage":0}, "Wooden Trapdoor":{"ID":96,"Damage":0}, "Iron Trapdoor":{"ID":167,"Damage":0}, "Oak Fence":{"ID":85,"Damage":0}, "Spruce Fence":{"ID":85,"Damage":1}, "Birch Fence":{"ID":85,"Damage":2}, "Jungle Fence":{"ID":85,"Damage":3}, "Acacia Fence":{"ID":85,"Damage":4}, "Dark Oak Fence":{"ID":85,"Damage":5}, "Nether Brick Fence":{"ID":113,"Damage":0}, "Oak Fence Gate":{"ID":107,"Damage":0}, "Spruce Fence Gate":{"ID":183,"Damage":0}, "Birch Fence Gate":{"ID":184,"Damage":0}, "Jungle Fence Gate":{"ID":185,"Damage":0}, "Acacia Fence Gate":{"ID":187,"Damage":0}, "Dark Oak Fence Gate":{"ID":186,"Damage":0}, "Iron Bars":{"ID":101,"Damage":0}, "Bed":{"ID":355,"Damage":0}, "Bookshelf":{"ID":47,"Damage":0}, "Sign":{"ID":323,"Damage":0}, "Painting":{"ID":321,"Damage":0}, "Item Frame":{"ID":389,"Damage":0}, "Crafting Table":{"ID":58,"Damage":0}, "Stonecutter":{"ID":245,"Damage":0}, "Chest":{"ID":54,"Damage":0}, "Trapped Chest":{"ID":146,"Damage":0}, "Furnace":{"ID":61,"Damage":0}, "Brewing Stand":{"ID":379,"Damage":0}, "Cauldron":{"ID":380,"Damage":0}, "Note Block":{"ID":25,"Damage":0}, "End Portal Frame":{"ID":120,"Damage":0}, "Anvil":{"ID":145,"Damage":0}, "Slightly Damaged Anvil":{"ID":145,"Damage":4}, "Very Damaged Anvil":{"ID":145,"Damage":8}, "Dandelion":{"ID":37,"Damage":0}, "Poppy":{"ID":38,"Damage":0}, "Blue Orchid":{"ID":38,"Damage":1}, "Allium":{"ID":38,"Damage":2}, "Azure Bluet":{"ID":38,"Damage":3}, "Red Tulip":{"ID":38,"Damage":4}, "Orange Tulip":{"ID":38,"Damage":5}, "White Tulip":{"ID":38,"Damage":6}, "Pink Tulip":{"ID":38,"Damage":7}, "Oxeye Daisy":{"ID":38,"Damage":8}, "Sunflower":{"ID":175,"Damage":0}, "Lilac":{"ID":175,"Damage":1}, "Double Tallgrass":{"ID":175,"Damage":2}, "Large Fern":{"ID":175,"Damage":3}, "Rose Bush":{"ID":175,"Damage":4}, "Peony":{"ID":175,"Damage":5}, "Brown Mushroom":{"ID":39,"Damage":0}, "Red Mushroom":{"ID":40,"Damage":0}, "Huge Mushroom Cap":{"ID":99,"Damage":14}, "Huge Red Mushroom Cap":{"ID":100,"Damage":14}, "Mushroom Block":{"ID":99,"Damage":0}, "Huge Mushroom Stem":{"ID":99,"Damage":15}, "Cactus":{"ID":81,"Damage":0}, "Melon Block":{"ID":103,"Damage":0}, "Pumpkin":{"ID":86,"Damage":0}, "Jack o'Lantern":{"ID":91,"Damage":0}, "Cobweb":{"ID":30,"Damage":0}, "Hay Bale":{"ID":170,"Damage":0}, "Tall Grass":{"ID":31,"Damage":1}, "Fern":{"ID":31,"Damage":2}, "Dead Bush":{"ID":32,"Damage":0}, "Oak Sapling":{"ID":6,"Damage":0}, "Spruce Sapling":{"ID":6,"Damage":1}, "Birch Sapling":{"ID":6,"Damage":2}, "Jungle Sapling":{"ID":6,"Damage":3}, "Acacia Sapling":{"ID":6,"Damage":4}, "Dark Oak Sapling":{"ID":6,"Damage":5}, "Oak Leaves":{"ID":18,"Damage":0}, "Spruce Leaves":{"ID":18,"Damage":1}, "Birch Leaves":{"ID":18,"Damage":2}, "Jungle Leaves":{"ID":18,"Damage":3}, "Acacia Leaves":{"ID":161,"Damage":0}, "Dark Oak Leaves":{"ID":161,"Damage":1}, "Cake":{"ID":354,"Damage":0}, "Skeleton Skull":{"ID":397,"Damage":0}, "Wither Skeleton Skull":{"ID":397,"Damage":1}, "Zombie Head":{"ID":397,"Damage":2}, "Head":{"ID":397,"Damage":3}, "Creeper Head":{"ID":397,"Damage":4}, "Flower Pot":{"ID":390,"Damage":0}, "Monster Spawner":{"ID":52,"Damage":0}, "Enchanting Table":{"ID":116,"Damage":0}, "Slime Block":{"ID":165,"Damage":0}, "White Wool":{"ID":35,"Damage":0}, "Light Gray Wool":{"ID":35,"Damage":8}, "Gray Wool":{"ID":35,"Damage":7}, "Black Wool":{"ID":35,"Damage":15}, "Brown Wool":{"ID":35,"Damage":12}, "Red Wool":{"ID":35,"Damage":14}, "Orange Wool":{"ID":35,"Damage":1}, "Yellow Wool":{"ID":35,"Damage":4}, "Lime Wool":{"ID":35,"Damage":5}, "Green Wool":{"ID":35,"Damage":13}, "Cyan Wool":{"ID":35,"Damage":9}, "Light Blue Wool":{"ID":35,"Damage":3}, "Blue Wool":{"ID":35,"Damage":11}, "Purple Wool":{"ID":35,"Damage":10}, "Magenta Wool":{"ID":35,"Damage":2}, "Pink Wool":{"ID":35,"Damage":6}, "White Carpet":{"ID":171,"Damage":0}, "Light Gray Carpet":{"ID":171,"Damage":8}, "Gray Carpet":{"ID":171,"Damage":7}, "Black Carpet":{"ID":171,"Damage":15}, "Brown Carpet":{"ID":171,"Damage":12}, "Red Carpet":{"ID":171,"Damage":14}, "Orange Carpet":{"ID":171,"Damage":1}, "Yellow Carpet":{"ID":171,"Damage":4}, "Lime Carpet":{"ID":171,"Damage":5}, "Green Carpet":{"ID":171,"Damage":13}, "Cyan Carpet":{"ID":171,"Damage":9}, "Light Blue Carpet":{"ID":171,"Damage":3}, "Blue Carpet":{"ID":171,"Damage":11}, "Purple Carpet":{"ID":171,"Damage":10}, "Magenta Carpet":{"ID":171,"Damage":2}, "Pink Carpet":{"ID":171,"Damage":6}, "Rail":{"ID":66,"Damage":0}, "Powered Rail":{"ID":27,"Damage":0}, "Detector Rail":{"ID":28,"Damage":0}, "Activator Rail":{"ID":126,"Damage":0}, "Torch":{"ID":50,"Damage":0}, "Bucket":{"ID":325,"Damage":0}, "Milk Bucket":{"ID":325,"Damage":1}, "Water Bucket":{"ID":325,"Damage":8}, "Lava Bucket":{"ID":325,"Damage":10}, "TNT":{"ID":46,"Damage":0}, "Lead":{"ID":420,"Damage":0}, "Name Tag":{"ID":421,"Damage":0}, "Redstone":{"ID":331,"Damage":0}, "Bow":{"ID":261,"Damage":0}, "Fishing Rod":{"ID":346,"Damage":0}, "Flint and Steel":{"ID":259,"Damage":0}, "Shears":{"ID":359,"Damage":0}, "Clock":{"ID":347,"Damage":0}, "Compass":{"ID":345,"Damage":0}, "Minecart":{"ID":328,"Damage":0}, "Minecart with Chest":{"ID":342,"Damage":0}, "Minecart with Hopper":{"ID":408,"Damage":0}, "Minecart with TNT":{"ID":407,"Damage":0}, "Oak Boat":{"ID":333,"Damage":0}, "Spruce Boat":{"ID":333,"Damage":1}, "Birch Boat":{"ID":333,"Damage":2}, "Jungle Boat":{"ID":333,"Damage":3}, "Acacia Boat":{"ID":333,"Damage":4}, "Dark Oak Boat":{"ID":333,"Damage":5}, "Saddle":{"ID":329,"Damage":0}, "Leather Horse Armour":{"ID":416,"Damage":0}, "Iron Horse Armour":{"ID":417,"Damage":0}, "Gold Horse Armour":{"ID":418,"Damage":0}, "Diamond Horse Armour":{"ID":419,"Damage":0}, "Spawn Villager":{"ID":383,"Damage":15}, "Spawn Chicken":{"ID":383,"Damage":10}, "Spawn Cow":{"ID":383,"Damage":11}, "Spawn Pig":{"ID":383,"Damage":12}, "Spawn Sheep":{"ID":383,"Damage":13}, "Spawn Wolf":{"ID":383,"Damage":14}, "Spawn Ocelot":{"ID":383,"Damage":22}, "Spawn Mooshroom":{"ID":383,"Damage":16}, "Spawn Bat":{"ID":383,"Damage":19}, "Spawn Rabbit":{"ID":383,"Damage":18}, "Spawn Horse":{"ID":383,"Damage":23}, "Spawn Donkey":{"ID":383,"Damage":24}, "Spawn Mule":{"ID":383,"Damage":25}, "Spawn Skeleton Horse":{"ID":383,"Damage":26}, "Spawn Zombie Horse":{"ID":383,"Damage":27}, "Spawn Creeper":{"ID":383,"Damage":33}, "Spawn Enderman":{"ID":383,"Damage":38}, "Spawn Silverfish":{"ID":383,"Damage":39}, "Spawn Skeleton":{"ID":383,"Damage":34}, "Spawn Wither Skeleton":{"ID":383,"Damage":48}, "Spawn Stray":{"ID":383,"Damage":46}, "Spawn Slime":{"ID":383,"Damage":37}, "Spawn Spider":{"ID":383,"Damage":35}, "Spawn Zombie":{"ID":383,"Damage":32}, "Spawn Zombie Pigman":{"ID":383,"Damage":36}, "Spawn Husk":{"ID":383,"Damage":47}, "Spawn Squid":{"ID":383,"Damage":17}, "Spawn Cave Spider":{"ID":383,"Damage":40}, "Spawn Witch":{"ID":383,"Damage":45}, "Spawn Magma Cube":{"ID":383,"Damage":42}, "Spawn Ghast":{"ID":383,"Damage":41}, "Spawn Blaze":{"ID":383,"Damage":43}, "Fire Charge":{"ID":385,"Damage":0}, "Wooden Sword":{"ID":268,"Damage":0}, "Wooden Hoe":{"ID":290,"Damage":0}, "Wooden Shovel":{"ID":269,"Damage":0}, "Wooden Pickaxe":{"ID":270,"Damage":0}, "Wooden Axe":{"ID":271,"Damage":0}, "Stone Sword":{"ID":272,"Damage":0}, "Stone Hoe":{"ID":291,"Damage":0}, "Stone Shovel":{"ID":273,"Damage":0}, "Stone Pickaxe":{"ID":274,"Damage":0}, "Stone Axe":{"ID":275,"Damage":0}, "Iron Sword":{"ID":267,"Damage":0}, "Iron Hoe":{"ID":292,"Damage":0}, "Iron Shovel":{"ID":256,"Damage":0}, "Iron Pickaxe":{"ID":257,"Damage":0}, "Iron Axe":{"ID":258,"Damage":0}, "Diamond Sword":{"ID":276,"Damage":0}, "Diamond Hoe":{"ID":293,"Damage":0}, "Diamond Shovel":{"ID":277,"Damage":0}, "Diamond Pickaxe":{"ID":278,"Damage":0}, "Diamond Axe":{"ID":279,"Damage":0}, "Gold Sword":{"ID":283,"Damage":0}, "Gold Hoe":{"ID":294,"Damage":0}, "Gold Shovel":{"ID":284,"Damage":0}, "Gold Pickaxe":{"ID":285,"Damage":0}, "Gold Axe":{"ID":286,"Damage":0}, "Leather Cap":{"ID":298,"Damage":0}, "Leather Tunic":{"ID":299,"Damage":0}, "Leather Pants":{"ID":300,"Damage":0}, "Leather Boots":{"ID":301,"Damage":0}, "Chainmail Helmet":{"ID":302,"Damage":0}, "Chain Chestplate":{"ID":303,"Damage":0}, "Chain Leggings":{"ID":304,"Damage":0}, "Chainmail Boots":{"ID":305,"Damage":0}, "Iron Helmet":{"ID":306,"Damage":0}, "Iron Chestplate":{"ID":307,"Damage":0}, "Iron Leggings":{"ID":308,"Damage":0}, "Iron Boots":{"ID":309,"Damage":0}, "Diamond Helmet":{"ID":310,"Damage":0}, "Diamond Chestplate":{"ID":311,"Damage":0}, "Diamond Leggings":{"ID":312,"Damage":0}, "Diamond Boots":{"ID":313,"Damage":0}, "Gold Helmet":{"ID":314,"Damage":0}, "Gold Chestplate":{"ID":315,"Damage":0}, "Gold Leggings":{"ID":316,"Damage":0}, "Gold Boots":{"ID":317,"Damage":0}, "Lever":{"ID":69,"Damage":0}, "Redstone Lamp":{"ID":123,"Damage":0}, "Redstone Torch":{"ID":76,"Damage":0}, "Wooden Pressure Plate":{"ID":72,"Damage":0}, "Stone Pressure Plate":{"ID":70,"Damage":0}, "Weighted Pressure Plate (Light)":{"ID":147,"Damage":0}, "Weighted Pressure Plate (Heavy)":{"ID":148,"Damage":0}, "Stone Button":{"ID":77,"Damage":0}, "Wooden Button":{"ID":143,"Damage":0}, "Daylight Sensor":{"ID":151,"Damage":0}, "Tripwire Hook":{"ID":131,"Damage":0}, "Redstone Repeater":{"ID":356,"Damage":0}, "Redstone Comparator":{"ID":404,"Damage":0}, "Dispenser":{"ID":23,"Damage":0}, "Dropper":{"ID":125,"Damage":0}, "Piston":{"ID":33,"Damage":0}, "Sticky Piston":{"ID":29,"Damage":0}, "Observer":{"ID":251,"Damage":0}, "Hopper":{"ID":410,"Damage":0}, "Snowball":{"ID":332,"Damage":0}, "Coal":{"ID":263,"Damage":0}, "Charcoal":{"ID":263,"Damage":1}, "Diamond":{"ID":264,"Damage":0}, "Iron Ingot":{"ID":265,"Damage":0}, "Gold Ingot":{"ID":266,"Damage":0}, "Emerald":{"ID":388,"Damage":0}, "Stick":{"ID":280,"Damage":0}, "Bowl":{"ID":281,"Damage":0}, "String":{"ID":287,"Damage":0}, "Feather":{"ID":288,"Damage":0}, "Flint":{"ID":318,"Damage":0}, "Leather":{"ID":334,"Damage":0}, "Clay":{"ID":337,"Damage":0}, "Sugar":{"ID":353,"Damage":0}, "Nether Quartz":{"ID":406,"Damage":0}, "Paper":{"ID":339,"Damage":0}, "Book":{"ID":340,"Damage":0}, "Arrow":{"ID":262,"Damage":0}, "Bone":{"ID":352,"Damage":0}, "Sugar Cane":{"ID":338,"Damage":0}, "Wheat":{"ID":296,"Damage":0}, "Arrow of Night Vision (0:22)":{"ID":262,"Damage":6}, "Arrow of Night Vision (1:00)":{"ID":262,"Damage":7}, "Arrow of Invisibility (0:22)":{"ID":262,"Damage":8}, "Arrow of Invisibility (1:00)":{"ID":262,"Damage":9}, "Arrow of Leaping (0:22)":{"ID":262,"Damage":10}, "Arrow of Leaping (1:00)":{"ID":262,"Damage":11}, "Arrow of Leaping II (0:11)":{"ID":262,"Damage":12}, "Arrow of Fire Resistance (0:22)":{"ID":262,"Damage":13}, "Arrow of Fire Resistance (1:00)":{"ID":262,"Damage":14}, "Arrow of Swiftness (0:22)":{"ID":262,"Damage":15}, "Arrow of Swiftness (1:00)":{"ID":262,"Damage":16}, "Arrow of Swiftness II (0:11)":{"ID":262,"Damage":17}, "Arrow of Slowness (0:11)":{"ID":262,"Damage":18}, "Arrow of Slowness (0:30)":{"ID":262,"Damage":19}, "Arrow of Water Breathing (0:22)":{"ID":262,"Damage":20}, "Arrow of Water Breathing (1:00)":{"ID":262,"Damage":21}, "Arrow of Healing":{"ID":262,"Damage":22}, "Arrow of Healing II":{"ID":262,"Damage":23}, "Arrow of Harming":{"ID":262,"Damage":24}, "Arrow of Harming II":{"ID":262,"Damage":25}, "Arrow of Poison (0:05)":{"ID":262,"Damage":26}, "Arrow of Poison (0:15)":{"ID":262,"Damage":27}, "Arrow of Poison II (0:02)":{"ID":262,"Damage":28}, "Arrow of Regeneration (0:05)":{"ID":262,"Damage":29}, "Arrow of Regeneration (0:15)":{"ID":262,"Damage":30}, "Arrow of Regeneration II (0:02)":{"ID":262,"Damage":31}, "Arrow of Strength (0:22)":{"ID":262,"Damage":32}, "Arrow of Strength (1:00)":{"ID":262,"Damage":33}, "Arrow of Strength II (0:11)":{"ID":262,"Damage":34}, "Arrow of Weakness (0:11)":{"ID":262,"Damage":35}, "Arrow of Weakness (0:30)":{"ID":262,"Damage":36}, "Wheat Seeds":{"ID":295,"Damage":0}, "Pumpkin Seeds":{"ID":361,"Damage":0}, "Melon Seeds":{"ID":362,"Damage":0}, "Beetroot Seeds":{"ID":458,"Damage":0}, "Egg":{"ID":344,"Damage":0}, "Apple":{"ID":260,"Damage":0}, "Golden Apple":{"ID":322,"Damage":0}, "Enchanted Golden Apple":{"ID":466,"Damage":0}, "Raw Fish":{"ID":349,"Damage":0}, "Raw Salmon":{"ID":460,"Damage":1}, "Clownfish":{"ID":461,"Damage":2}, "Pufferfish":{"ID":462,"Damage":3}, "Cooked Fish":{"ID":350,"Damage":0}, "Cooked Salmon":{"ID":463,"Damage":1}, "Rotten Flesh":{"ID":367,"Damage":0}, "Mushroom Stew":{"ID":282,"Damage":0}, "Bread":{"ID":297,"Damage":0}, "Raw Porkchop":{"ID":319,"Damage":0}, "Cooked Porkchop":{"ID":320,"Damage":0}, "Raw Chicken":{"ID":365,"Damage":0}, "Cooked Chicken":{"ID":366,"Damage":0}, "Raw Mutton":{"ID":423,"Damage":0}, "Cooked Mutton":{"ID":424,"Damage":0}, "Raw Beef":{"ID":363,"Damage":0}, "Steak":{"ID":364,"Damage":0}, "Melon":{"ID":360,"Damage":0}, "Carrot":{"ID":391,"Damage":0}, "Potato":{"ID":392,"Damage":0}, "Baked Potato":{"ID":393,"Damage":0}, "Poisonous Potato":{"ID":394,"Damage":0}, "Beetroot":{"ID":457,"Damage":0}, "Cookie":{"ID":357,"Damage":0}, "Pumpkin Pie":{"ID":400,"Damage":0}, "Raw Rabbit":{"ID":411,"Damage":0}, "Cooked Rabbit":{"ID":412,"Damage":0}, "Rabbit Stew":{"ID":413,"Damage":0}, "Magma Cream":{"ID":378,"Damage":0}, "Blaze Rod":{"ID":369,"Damage":0}, "Gold Nugget":{"ID":371,"Damage":0}, "Golden Carrot":{"ID":396,"Damage":0}, "Glistering Melon":{"ID":382,"Damage":0}, "Rabbit's Foot":{"ID":414,"Damage":0}, "Ghast Tear":{"ID":370,"Damage":0}, "Slimeball":{"ID":341,"Damage":0}, "Blaze Powder":{"ID":377,"Damage":0}, "Nether Wart":{"ID":372,"Damage":0}, "Gunpowder":{"ID":289,"Damage":0}, "Glowstone Dust":{"ID":348,"Damage":0}, "Spider Eye":{"ID":375,"Damage":0}, "Fermented Spider Eye":{"ID":376,"Damage":0}, "Carrot on a Stick":{"ID":398,"Damage":0}, "Bottle o' Enchanting":{"ID":384,"Damage":0}, "Inc Sac":{"ID":351,"Damage":0}, "Grey Dye":{"ID":351,"Damage":8}, "Light Grey Dye":{"ID":351,"Damage":7}, "Bone Meal":{"ID":351,"Damage":15}, "Light Blue Dye":{"ID":351,"Damage":12}, "Orange Dye":{"ID":351,"Damage":14}, "Rose Red":{"ID":351,"Damage":1}, "Lapis Lazuli":{"ID":351,"Damage":4}, "Purple Dye":{"ID":351,"Damage":5}, "Magenta Dye":{"ID":351,"Damage":13}, "Pink Dye":{"ID":351,"Damage":9}, "Cocoa Beans":{"ID":351,"Damage":3}, "Dandelion Yellow":{"ID":351,"Damage":11}, "Lime Dye":{"ID":351,"Damage":10}, "Cactus Green":{"ID":351,"Damage":2}, "Cyan Dye":{"ID":351,"Damage":6}, "Glass Bottle":{"ID":374,"Damage":0}, "Water Bottle":{"ID":373,"Damage":0}, "Mundane Potion":{"ID":373,"Damage":1}, "Mundane Potion (Extended)":{"ID":373,"Damage":2}, "Thick Potion":{"ID":373,"Damage":3}, "Awkward Potion":{"ID":373,"Damage":4}, "Potion of Night Vision (3:00)":{"ID":373,"Damage":5}, "Potion of Night Vision (8:00)":{"ID":373,"Damage":6}, "Potion of Invisibility (3:00)":{"ID":373,"Damage":7}, "Potion of Invisibility (8:00)":{"ID":373,"Damage":8}, "Potion of Leaping (3:00)":{"ID":373,"Damage":9}, "Potion of Leaping (8:00)":{"ID":373,"Damage":10}, "Potion of Leaping II (1:30)":{"ID":373,"Damage":11}, "Potion of Fire Resistance (3:00)":{"ID":373,"Damage":12}, "Potion of Fire Resistance (8:00)":{"ID":373,"Damage":13}, "Potion of Swiftness (3:00)":{"ID":373,"Damage":14}, "Potion of Swiftness (8:00)":{"ID":373,"Damage":15}, "Potion of Swiftness II (1:30)":{"ID":373,"Damage":16}, "Potion of Slowness (1:30)":{"ID":373,"Damage":17}, "Potion of Slowness (4:00)":{"ID":373,"Damage":18}, "Potion of Water Breathing (3:00)":{"ID":373,"Damage":19}, "Potion of Water Breathing (8:00)":{"ID":373,"Damage":20}, "Potion of Healing":{"ID":373,"Damage":21}, "Potion of Healing II":{"ID":373,"Damage":22}, "Potion of Harming":{"ID":373,"Damage":23}, "Potion of Harming II":{"ID":373,"Damage":24}, "Potion of Poison (0:45)":{"ID":373,"Damage":25}, "Potion of Poison (2:00)":{"ID":373,"Damage":26}, "Potion of Poison II (0:22)":{"ID":373,"Damage":27}, "Potion of Regeneration (0:45)":{"ID":373,"Damage":28}, "Potion of Regeneration (2:00)":{"ID":373,"Damage":29}, "Potion of Regeneration II (0:22)":{"ID":373,"Damage":30}, "Potion of Strength (3:00)":{"ID":373,"Damage":31}, "Potion of Strength (8:00)":{"ID":373,"Damage":32}, "Potion of Strength II (1:30)":{"ID":373,"Damage":33}, "Potion of Weakness (1:30)":{"ID":373,"Damage":34}, "Potion of Weakness (4:00)":{"ID":373,"Damage":35}, "Splash Potion of Night Vision (3:00)":{"ID":438,"Damage":5}, "Splash Potion of Night Vision (8:00)":{"ID":438,"Damage":6}, "Splash Potion of Invisibility (3:00)":{"ID":438,"Damage":7}, "Splash Potion of Invisibility (8:00)":{"ID":438,"Damage":8}, "Splash Potion of Leaping (3:00)":{"ID":438,"Damage":9}, "Splash Potion of Leaping (8:00)":{"ID":438,"Damage":10}, "Splash Potion of Leaping II (1:30)":{"ID":438,"Damage":11}, "Splash Potion of Fire Resistance (3:00)":{"ID":438,"Damage":12}, "Splash Potion of Fire Resistance (8:00)":{"ID":438,"Damage":13}, "Splash Potion of Swiftness (3:00)":{"ID":438,"Damage":14}, "Splash Potion of Swiftness (8:00)":{"ID":438,"Damage":15}, "Splash Potion of Swiftness II (1:30)":{"ID":438,"Damage":16}, "Splash Potion of Slowness (1:30)":{"ID":438,"Damage":17}, "Splash Potion of Slowness (4:00)":{"ID":438,"Damage":18}, "Splash Potion of Water Breathing (3:00)":{"ID":438,"Damage":19}, "Splash Potion of Water Breathing (8:00)":{"ID":438,"Damage":20}, "Splash Potion of Healing":{"ID":438,"Damage":21}, "Splash Potion of Healing II":{"ID":438,"Damage":22}, "Splash Potion of Harming":{"ID":438,"Damage":23}, "Splash Potion of Harming II":{"ID":438,"Damage":24}, "Splash Potion of Poison (0:45)":{"ID":438,"Damage":25}, "Splash Potion of Poison (2:00)":{"ID":438,"Damage":26}, "Splash Potion of Poison II (0:22)":{"ID":438,"Damage":27}, "Splash Potion of Regeneration (0:45)":{"ID":438,"Damage":28}, "Splash Potion of Regeneration (2:00)":{"ID":438,"Damage":29}, "Splash Potion of Regeneration II (0:22)":{"ID":438,"Damage":30}, "Splash Potion of Strength (3:00)":{"ID":438,"Damage":31}, "Splash Potion of Strength (8:00)":{"ID":438,"Damage":32}, "Splash Potion of Strength II (1:30)":{"ID":438,"Damage":33}, "Splash Potion of Weakness (1:30)":{"ID":438,"Damage":34}, "Splash Potion of Weakness (4:00)":{"ID":438,"Damage":35} } \ No newline at end of file +[ + { + "id": 138, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 66, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 27, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 28, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 126, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 98, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 98, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 98, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 98, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 48, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 3, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 243, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 2, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 110, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 82, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 9, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 159, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 13, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 139, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 139, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 17, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 17, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 17, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 17, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 162, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 162, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 87, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 88, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 7, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 67, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 53, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 134, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 135, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 136, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 163, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 164, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 108, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 128, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 180, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 109, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 114, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 156, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 44, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 44, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 111, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 158, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 158, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 158, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 158, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 158, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 158, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 44, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 44, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 182, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 44, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 44, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 44, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 155, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 155, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 155, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 168, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 168, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 168, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 169, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 263, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 263, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 388, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 281, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 288, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 318, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 415, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 337, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 353, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 336, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 405, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 16, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 15, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 14, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 56, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 21, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 73, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 129, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 153, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 42, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 57, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 22, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 173, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 133, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 152, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 49, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 79, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 174, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 80, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 78, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 89, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 106, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 65, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 19, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 19.1, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 50, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 102, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 325, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 325, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 325, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 325, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 340, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 352, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 324, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 427, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 428, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 429, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 430, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 431, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 330, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 395, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 96, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 167, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 85, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 85, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 85, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 85, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 85, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 85, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 113, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 107, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 183, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 184, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 185, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 187, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 186, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 101, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 355, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 47, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 323, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 321, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 389, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 58, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 245, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 54, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 146, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 61, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 379, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 380, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 25, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 46, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 121, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 120, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 145, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 145, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 145, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 37, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 38, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 38, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 38, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 38, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 38, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 38, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 38, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 38, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 38, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 175, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 175, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 175, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 175, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 175, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 175, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 39, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 40, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 99, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 100, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 99, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 99, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 81, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 103, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 86, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 91, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 30, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 170, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 338, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 31, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 31, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 32, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 6, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 6, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 6, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 6, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 6, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 6, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 18, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 18, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 18, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 18, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 161, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 161, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 9, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 16, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 17, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 18, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 19, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 20, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 21, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 22, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 23, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 24, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 25, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 26, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 27, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 28, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 29, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 30, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 31, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 32, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 33, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 34, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 35, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 36, + "count": 1, + "nbt": "" + }, + { + "id": 262, + "damage": 37, + "count": 1, + "nbt": "" + }, + { + "id": 295, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 361, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 362, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 458, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 344, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 260, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 322, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 466, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 349, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 460, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 461, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 462, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 350, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 463, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 367, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 282, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 297, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 319, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 320, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 365, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 366, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 423, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 424, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 363, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 364, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 200, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 201, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 203, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 206, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 208, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 240, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 391, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 392, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 393, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 394, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 457, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 354, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 357, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 400, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 411, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 412, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 413, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 399, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 420, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 421, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 378, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 369, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 396, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 382, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 414, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 370, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 377, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 372, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 289, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 348, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 375, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 376, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 397, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 397, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 397, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 397, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 397, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 261, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 346, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 259, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 359, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 347, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 345, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 398, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 328, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 342, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 408, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 407, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 333, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 333, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 333, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 333, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 333, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 333, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 329, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 416, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 417, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 418, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 419, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 390, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 22, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 16, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 19, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 18, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 23, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 24, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 25, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 26, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 27, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 33, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 38, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 39, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 34, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 48, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 46, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 37, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 35, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 32, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 36, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 47, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 17, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 40, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 45, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 49, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 50, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 42, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 41, + "count": 1, + "nbt": "" + }, + { + "id": 383, + "damage": 43, + "count": 1, + "nbt": "" + }, + { + "id": 97, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 97, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 97, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 97, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 97, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 97, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 384, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 385, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 268, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 290, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 269, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 270, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 271, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 272, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 291, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 273, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 274, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 275, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 267, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 292, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 256, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 257, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 258, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 276, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 293, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 277, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 278, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 279, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 283, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 294, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 284, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 285, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 286, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 298, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 299, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 300, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 301, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 302, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 303, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 304, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 305, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 306, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 307, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 308, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 309, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 310, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 311, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 312, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 313, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 314, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 315, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 316, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 317, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 69, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 123, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 76, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 72, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 70, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 147, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 148, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 143, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 77, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 151, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 131, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 356, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 404, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 23, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 125, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 33, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 29, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 251, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 410, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 332, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 422, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 52, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 116, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 165, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0000\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0000\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0000\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0000\u0000\u0002\u0003\u0000lvl\u0004\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0001\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0001\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0001\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0001\u0000\u0002\u0003\u0000lvl\u0004\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0002\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0002\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0002\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0002\u0000\u0002\u0003\u0000lvl\u0004\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0003\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0003\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0003\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0003\u0000\u0002\u0003\u0000lvl\u0004\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0004\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0004\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0004\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0004\u0000\u0002\u0003\u0000lvl\u0004\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0005\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0005\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0005\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0006\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0006\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0006\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0007\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0007\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0007\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\b\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\t\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\t\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\t\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\t\u0000\u0002\u0003\u0000lvl\u0004\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\t\u0000\u0002\u0003\u0000lvl\u0005\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\n\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\n\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\n\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\n\u0000\u0002\u0003\u0000lvl\u0004\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\n\u0000\u0002\u0003\u0000lvl\u0005\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000b\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000b\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000b\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000b\u0000\u0002\u0003\u0000lvl\u0004\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000b\u0000\u0002\u0003\u0000lvl\u0005\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\f\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\f\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\r\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\r\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000e\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000e\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000e\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000f\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000f\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000f\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000f\u0000\u0002\u0003\u0000lvl\u0004\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u000f\u0000\u0002\u0003\u0000lvl\u0005\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0010\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0011\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0011\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0011\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0012\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0012\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0012\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0013\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0013\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0013\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0013\u0000\u0002\u0003\u0000lvl\u0004\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0013\u0000\u0002\u0003\u0000lvl\u0005\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0014\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0014\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0015\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0016\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0017\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0017\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0017\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0018\u0000\u0002\u0003\u0000lvl\u0001\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0018\u0000\u0002\u0003\u0000lvl\u0002\u0000\u0000\u0000" + }, + { + "id": 403, + "damage": 0, + "count": 1, + "nbt": "\n\u0000\u0000\t\u0004\u0000ench\n\u0001\u0000\u0000\u0000\u0002\u0002\u0000id\u0018\u0000\u0002\u0003\u0000lvl\u0003\u0000\u0000\u0000" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 9, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 9, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 171, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 9, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 374, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 9, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 16, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 17, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 18, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 19, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 20, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 21, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 22, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 23, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 24, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 25, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 26, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 27, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 28, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 29, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 30, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 31, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 32, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 33, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 34, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 35, + "count": 1, + "nbt": "" + }, + { + "id": 373, + "damage": 36, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 9, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 16, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 17, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 18, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 19, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 20, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 21, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 22, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 23, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 24, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 25, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 26, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 27, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 28, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 29, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 30, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 31, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 32, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 33, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 34, + "count": 1, + "nbt": "" + }, + { + "id": 444, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 35, + "count": 1, + "nbt": "" + }, + { + "id": 438, + "damage": 36, + "count": 1, + "nbt": "" + } +] diff --git a/src/devmine/server/resources/devmine.yml b/src/devmine/server/resources/devmine.yml index 58710f7..ea3112b 100644 --- a/src/devmine/server/resources/devmine.yml +++ b/src/devmine/server/resources/devmine.yml @@ -1,4 +1,4 @@ -# Main configuration file for devmine-MP +# Main configuration file for DevMine-MP # These settings are the ones that cannot be included in server.properties # Some of these settings are safe, others can break your server if modified incorrectly # New settings/defaults won't appear automatically on this file when upgrading. @@ -24,6 +24,8 @@ settings: #Set this approximately to your number of cores. #If set to auto, it'll try to detect the number of cores (or use 2) async-workers: 4 + #Enables use of non-production, development builds. WARNING: DO NOT enable this unless you are sure you know what you are doing. + enable-testing: false memory: #Global soft memory limit in megabytes. Set to 0 to disable @@ -86,13 +88,17 @@ network: debug: #If > 1, it will show debug messages in the console - level: 5 + level: 1 #Enables /status, /gc commands: true +player: + #Choose whether to enable player data saving. + save-player-data: true + level-settings: #The default format that levels will use when created - default-format: mcregion + default-format: anvil #If true, converts from a format that is not the default to the default format on load #NOTE: This is currently not implemented convert-format: false @@ -146,23 +152,23 @@ auto-report: send-code: true send-settings: true send-phpinfo: false - host: crash.devmine.net + host: crash.pocketmine.net anonymous-statistics: #Sends anonymous statistics for data aggregation, plugin usage tracking enabled: true - host: stats.devmine.net - -auto-updater: - enabled: false - on-update: - warn-console: false - warn-ops: false - #Can be development, beta or stable. - preferred-channel: stable - #If using a development version, it will suggest changing the channel - suggest-channels: false - host: www.devmine.net + host: stats.pocketmine.net + +commands: + #Here you can customize server commands + #Specify command names to override the default set here. + #If no custom value is defined for a command, the default will be used. + #NOTE: Some commands cannot be disabled here, such as the important ones like /stop, /reload, etc. + default: true + #Set override values per command here + #For example, uncommenting the below will disable /plugins and /version + #version: false + #plugins: false aliases: #Examples: diff --git a/src/devmine/server/resources/devmine2_eng.yml b/src/devmine/server/resources/devmine2_eng.yml deleted file mode 100644 index f2b0f48..0000000 --- a/src/devmine/server/resources/devmine2_eng.yml +++ /dev/null @@ -1,168 +0,0 @@ -#devmine Advanced Configuration File - -#Version of this file -config: - version: 17 - -level: - #Set if turn on the weather system - weather: true - #Weather random duration - weather-random-duration-min: 6000 - weather-random-duration-max: 12000 - #Random lightning interval,default as 10s, 0 = disable - lightning-time: 200 - #Set if enable lightning with fire - lightning-fire: false - #Set if enable fire spread - fire-spread: false - -player: - #the switch of hunger system - hunger: true - #Minimum health when someone is attacking by being hungry - hunger-health: 10 - #Hunger Time-Counter, Default: 80=4sec - hunger-timer: 3000 - #Choose if turn on the experience system - experience: true - #Choose if keep inventory when a player died - keep-inventory: false - #The space of inventory - inventory-num: 36 - #Clear the inventory automatically when change the gamemode into creative - auto-clear-inventory : true - #Choose if keep experience when a player died - keep-experience: false - #If players get crash when join, set this below 10. disable=-1 - chunk-radius: -1 - -nether: - #Choose if the nether's allowed,the level of nether will generate automatically - allow-nether: true - #The name of nether's level - level-name: "nether" - -server: - #Pregenerate the experience data,0=disabled - experience-cache: 65535 - #Choose if spawning iron golem is allowed - allow-iron-golem: false - #Choose if spawning snow golem is allowed - allow-snow-golem: false - #Choose if disable server.log - disable-log: false - #Choose if enable auto anti fly - anti-fly: true - #Choose if enable async chunks request - async-chunk-request: true - #Choose how to remind player when a player join - #0 = Message, 1 = Tip, 2 = Popup - player-msg-type: 0 - login-msg: "§3@player joined the game" - logout-msg: "§3@player left the game" - #Choose if read recipes from json - recipes-from-json: false - #Choose if read creative item from json - creative-items-from-json: false - #Choose if minecart is free moving, follow rails or disable - #-1=disable, 0=free moving, 1=follow rails - minecart-moving-type: 0 - #Choose if enable movement check (no more pull back) - check-movement: true - #Set if enable limited creative (cannot drop item, cannot interact Chests and so on) - limited-creative: true - #Set if add DestroyBlockParticle - destroy-block-particle: true - #Set if enable splash potion - allow-splash-potion: true - #Set if enable advanced Command Selector - advanced-command-selector: false - -enchantment: - #Choose if anvil is allowed - enable-anvil: true - #Choose if EnchantingTable is allowed - enable-enchanting-table: true - #Choose if to count bookshelves, may cause server lag. - #If this option is false, server will use a random count (0~15) - count-bookshelf: false - -redstone: - ########################################## - ###Choose if redstone system is allowed### - ########################################## - #If not true then the redstone won't work# - ########################################## - enable: false - #Choose if allow frequancy pulse - frequency-pulse: false - #Set the frequency of pulse, Default: 1s - pulse-frequency: 1 - -synapse: - #If you want to use Synapse API or connect to a synapse server, enable this - enabled: false - server-ip: 127.0.0.1 - server-port: 10305 - #If this client is the lobby or the main server - is-main-server: true - server-password: 32bitlongkey - #Description of this client is the identifier of this client - description: "A Synapse client" - #Disable RakLib means that players can only join via Synapse - disable-rak: false - -dserver: - #The count of all multi-server unified - enable: false - #Query update automatically - query-auto-update: false - #Query update periodical - query-tick-update: true - #The max players' number of Motd - motd-max-players: 0 - #The max players' number of query,0=Default - query-max-players: 0 - #Show the number of all players on motd - motd-all-players: false - #Show the number of all players on Query - query-all-players: false - #Show the number of online players on motd - motd-players: false - #Show the number of online players on Query - query-players: false - #Update Frequency ,20=1s - time: 40 - #Auto-retry times when failed - retry-times: 3 - #the server list,Separate by ';',e.g. 1.example.com:19132;2.example.com:19133 - server-list: "" - -ai: - #AI switch - enable: false - #Zombie'AI,0=disabled,1=AI 1.0ver,2=new AI(Faultiness) - zombie: 1 - #PigZombie's AI - pigzombie: true - #the AI of cow and mushroom cow - cow: true - #Chicken's AI - chicken: true - #Sheep's AI - sheep: true - #Pigs' AI - pig: true - #Skeleton's AI - skeleton: true - #Creeper's AI - creeper: true - #Iron golem's AI - iron-golem: true - #Snow golem's AI - snow-golem: true - #Destory blocks if creeper exploded - creeper-explode-destroy-block: false - #Choose if allow mob auto generate - mobgenerate: false diff --git a/src/devmine/server/resources/devmine2_chs.yml b/src/devmine/server/resources/extended_chs.yml similarity index 63% rename from src/devmine/server/resources/devmine2_chs.yml rename to src/devmine/server/resources/extended_chs.yml index e9150fa..ec65d63 100644 --- a/src/devmine/server/resources/devmine2_chs.yml +++ b/src/devmine/server/resources/extended_chs.yml @@ -1,8 +1,18 @@ -#devmine高级配置文件 +# +# _______ _ +# |__ __| | | +# | | ___ ___ ___ ___ _ __ __ _ ___| |_ +# | |/ _ \/ __/ __|/ _ \ '__/ _` |/ __| __| +# | | __/\__ \__ \ __/ | | (_| | (__| |_ +# |_|\___||___/___/\___|_| \__,_|\___|\__| +# +# +# +#DevMine高级配置文件 #配置文件版本 config: - version: 17 + version: 27 level: #设置是否变换天气 @@ -20,16 +30,10 @@ level: player: #是否打开饥饿 hunger: true - #饥饿值扣血下限 - hunger-health: 10 - #饥饿值计时器,默认80=4秒 - hunger-timer: 3000 #是否打开经验系统 experience: true #是否开启死亡不掉落 keep-inventory: false - #背包格数 - inventory-num: 36 #是否开启切换模式自动清除背包 auto-clear-inventory: true #是否开启死亡经验不掉落 @@ -44,31 +48,18 @@ nether: level-name: "nether" server: - #经验数据预生成,0不启用 - experience-cache: 65535 #是否允许生成铁傀儡 allow-iron-golem: false #是否允许生成雪傀儡 allow-snow-golem: false #是否禁用server.log disable-log: false - #是否启用反飞行作弊 - anti-fly: true #是否启用异步方式发送区块 async-chunk-request: true #玩家进出服务器消息提醒方式。0为Message,1为Tip,2为Popup player-msg-type: 0 login-msg: "§3@player 加入了游戏" logout-msg: "§3@player 退出了游戏" - #是否从recipes.json读取合成公式 - recipes-from-json: false - #是否从creativeitems.json读取创造物品 - creative-items-from-json: false - #设置矿车行为方式 - #-1=禁用矿车移动, 0=自由移动, 1=沿铁轨行驶 - minecart-moving-type: 0 - #是否进行移动检测(不再拉回了) - check-movement: true #是否限制创造某些功能(禁止丢物品, 禁止操作箱子等等) limited-creative: true #是否开启方块破坏粒子 @@ -98,19 +89,6 @@ redstone: frequency-pulse: false #设置脉冲频率, 默认: 1s pulse-frequency: 1 - -synapse: - #如果你想使用 Synapse API 或连接到一个synapse服务器,请将enabled置为true - enabled: false - server-ip: 127.0.0.1 - server-port: 10305 - #设置该服务器是否为接待大厅服务器或主服务器 - is-main-server: true - server-password: 16bitlongkey - #设置该服务器唯一的标识符 - description: "A Synapse client" - #启用Disable RakLib设置玩家仅能通过接待大厅服务器或主服务器加入游戏 - disable-rak: false dserver: #多服统统一人数 @@ -137,31 +115,7 @@ dserver: retry-times: 3 #服务器列表,用;隔开,例如 1.example.com:19132;2.example.com:19133 server-list: "" - -ai: - #AI总开关 - enable: false - #僵尸的AI,0为关闭,1为1.0版AI,2为新AI(不完善) - zombie: 1 - #僵尸猪人的AI - pigzombie: true - #牛和哞菇的AI - cow: true - #鸡的AI - chicken: true - #羊的AI - sheep: true - #猪的AI - pig: true - #骷髅的AI - skeleton: true - #苦力怕的AI - creeper: true - #铁傀儡的AI - iron-golem: true - #雪傀儡的AI - snow-golem: true - #苦力怕爆炸是否破坏方块 - creeper-explode-destroy-block: false - #是否允许自动生成生物 - mobgenerate: false + +inventory: + #Set this to true if you have problems with anvils. Will process inventory transactions in a vanilla fashion with no anti-cheats or verification. + allow-cheats: true diff --git a/src/devmine/server/resources/extended_eng.yml b/src/devmine/server/resources/extended_eng.yml new file mode 100644 index 0000000..1faef3c --- /dev/null +++ b/src/devmine/server/resources/extended_eng.yml @@ -0,0 +1,115 @@ +# +# _______ _ +# |__ __| | | +# | | ___ ___ ___ ___ _ __ __ _ ___| |_ +# | |/ _ \/ __/ __|/ _ \ '__/ _` |/ __| __| +# | | __/\__ \__ \ __/ | | (_| | (__| |_ +# |_|\___||___/___/\___|_| \__,_|\___|\__| +# +# +# +#The advanced config for DevMine + +#Version of this file +config: + version: 27 + +level: + #This settting decides if weather is enabled in game (rain may cause lag to older devices) + weather: true + #This setting controls a random timer for weather durations (requires weather: true) + #The ranges that are set must follow the min-max range (min less than max (min < max)) + weather-random-duration-min: 6000 + weather-random-duration-max: 12000 + #This setting controls the interval of lightning strikes in game,default 200 as 10s, 0 = disable + lightning-time: 200 + #This setting will decide if lightning strikes have fire after they strike + lightning-fire: false + #This setting will decide if fire should spread after it is set on burnable materials (leaves, trees, etc.) + fire-spread: false + #Choose if the nether is allowed/loaded into the game. The level of nether will generate automatically even if false + allow-nether: true + #The name of nether's level will be set here + level-name: "nether" + +player: + #This setting decides if hunger will be enabled in game + #If set to false, hunger wont drop + hunger: true + #This setting decides if experience will be enalbed + #If set to false, then exp bottles wont drop exp dots, and exp level wont go up + experience: true + #This setting decides if the inventory of a player will be kept after they die + keep-inventory: false + #This setting decides if the inventory of a player will be cleared upon them changing their gamemode + auto-clear-inventory : true + #This setting will decide if the experience of a player will be kept after they die + keep-experience: false + #Radius of chunks in worlds, possibly for rendering, if players crash by too much processing, set this below 10. disable=-1 + chunk-radius: -1 + +server: + #This setting decides if the server.log file will not be made/written. + #You can set to True since it can help with disk space on a hosted server through computer + #But it is suggested to turn it on if you have players online, so you can see what console sees basically + disable-log: false + #This setting decides if the async chunks request will be enabled upon server loading/rebooting + async-chunk-request: true + #This setting chooses how to remind players when someone joins the game + #0 = Message, 1 = Tip, 2 = Popup + player-msg-type: 0 + login-msg: "§3@player joined the game" + logout-msg: "§3@player left the game" + #This setting decides if limited creative is enabled in game + #If set to true true, then players cannot drop items from hotbar, cannot open chests, and so on + limited-creative: true + #This setting decides if block particles upon destroying a block will spawn (may cause lag to older devices) + destroy-block-particle: true + #This setting decides if splash potions will be allowed to be thrown + #If set to false, then they will not be visible when thrown (wont splash either) + allow-splash-potion: true + #THis setting decides if Advanced Command Selector is enabled (recommended it is set to default (false)) + advanced-command-selector: false + +enchantment: + #This setting decides if Anvils are allowed to be used in game + #If the below setting is false, then anvils will not show the anvil gui + enable-anvil: true + #This setting decides if Enchantment Tables are allowed to be used in game + #If the below setting is false, then enchanting tables will not show the enchant table gui + enable-enchanting-table: true + #This setting decides if bookshelves are counted as entities (may cause server lag) + #If this option is false, the server will use a random count (recommended and the values range from 0~15) + count-bookshelf: false + +dserver: + #This setting decides if the server counts all multi-servers combined (recommended set to false) + enable: false + #This setting decides if the server will automatically update the Query + query-auto-update: false + #This setting decides if the server Query ticks update + query-tick-update: true + #This setting displays the # of max players on MOTD. 0 = Default + motd-max-players: 0 + #This setting displays the # of max players on Query. 0 = Default + query-max-players: 0 + #This setting decides if the server shows the # of all players on MOTD + motd-all-players: false + #This setting shows the number of all players on Query + query-all-players: false + #This setting shows the number of online players on MOTD + motd-players: false + #This setting shows the number of online players on Query + query-players: false + #This setting decides the interval for query/motd updating. 20=1s + time: 40 + #This setting decides the # of times the server retries when the server fails to load. 0 = Disable, 3 = Default + retry-times: 3 + #This setting displays the server list,Separate by ';',e.g. 1.example.com:19132;2.example.com:19133 + server-list: "" + +inventory: + #Set this setting to true if you have problems with anvils. + #This will process inventory transactions in a vanilla fashion with no anti-cheats or verification. + #If enchants do not work on PE or Windows 10, please enable cheats. + allow-cheats: false diff --git a/src/devmine/server/resources/extended_jpn.yml b/src/devmine/server/resources/extended_jpn.yml new file mode 100644 index 0000000..586ba23 --- /dev/null +++ b/src/devmine/server/resources/extended_jpn.yml @@ -0,0 +1,109 @@ +# +# _______ _ +# |__ __| | | +# | | ___ ___ ___ ___ _ __ __ _ ___| |_ +# | |/ _ \/ __/ __|/ _ \ '__/ _` |/ __| __| +# | | __/\__ \__ \ __/ | | (_| | (__| |_ +# |_|\___||___/___/\___|_| \__,_|\___|\__| +# +# +# +#DevMine設定用ファイル + +#ファイルバージョン +config: + version: 27 + +level: + #天候が有効にするかどうかを設定します。(有効化すると古いデバイスではラグの原因となる可能性があります) + weather: false + #天候がランダムになる期間の設定です。(この設定を使用するには天候を有効にする必要があります。) + #設定する範囲は最小範囲と最大範囲を設定する必要があります。(最小範囲の値は最大範囲の値より小さくする必要があります。) + weather-random-duration-min: 6000 + weather-random-duration-max: 12000 + #天候の落雷の間隔を設定します。既定値は200(10秒間)です。0を指定した場合は無効に設定します。 + lightning-time: 200 + #落雷時に火災を発生させるかどうかを設定します。 + lightning-fire: false + #可燃物(葉、木など)が燃えるかどうかを設定します + fire-spread: false + #ネザーの要素を有効にするかどうかを設定します。(無効に設定した場合でもネザーのワールドデータが自動的に生成されます。) + allow-nether: false + #ネザーのレベル名を設定します。 + level-name: "nether" + +player: + #空腹が有効にするかどうかを設定します。 + hunger: true + #経験値が有効にするかどうかを設定します。 + experience: false + #プレイヤーの死亡時にインベントリを保持するかどうかを設定します。 + keep-inventory: true + #ゲームモードの変更時にインベントリを保持するかどうかを設定します。 + auto-clear-inventory : false + #プレイヤーの死亡時に経験値を保持するかどうかを設定します。 + keep-experience: false + #ワールドの読み込むチャンク量の半径を設定します(10以上を指定すると処理過多によりクラッシュする可能性があります。-1を指定すると無効に設定します。) + chunk-radius: -1 + +server: + #サーバーのログをファイルに保存するかを設定します。 + #保存したログから過去のコンソールの状態を確認することができます。(有効化を推奨します。) + disable-log: false + #非同期チャンクの要求がサーバーの読み込み(再起動)時に有効にするかどうかを設定します。 + async-chunk-request: true + #プレイヤーの参加(退出)時にサーバー全体に表示するメッセージを設定します。 + #0 = Message, 1 = Tip, 2 = Popup + player-msg-type: 0 + login-msg: "§3@player joined the game" + logout-msg: "§3@player left the game" + #クリエイティブゲームモード時に制限が有効にするかどうかを設定します。 + #有効化すると一部機能(ホットバーからのドロップ、チェストを開けるなど)が使用できなくなります。 + limited-creative: true + #ブロックの破壊時にエフェクトを有効にするかどうかを設定します。(有効化すると古いデバイスではラグの原因となる可能性があります) + destroy-block-particle: true + #スプラッシュポーションを有効にするかどうかを設定します。 + allow-splash-potion: true + #高度なコマンド設定を有効にするかどうかを設定します。(無効化を推奨します。) + advanced-command-selector: false + +enchantment: + #エンチャント機能を有効にするかどうかを設定します。 + enable-anvil: true + #エンチャントテーブルを使用するかどうかを設定します。 + enable-enchanting-table: true + #本棚をエンティティとしてカウントするかを設定します。(有効化すると古いデバイスではラグの原因となる可能性があります) + #無効にするとエンチャント時にサーバーがランダムな数(0から15)を使用します。 + count-bookshelf: false + +dserver: + #複数の鯖稼働時にサーバー数をカウントするかを設定します。(無効化を推奨します。) + enable: false + #サーバーが自動的にクエリを更新するかどうかを設定します。 + query-auto-update: false + #サーバークエリを更新するかどうかを設定します。 + query-tick-update: true + #MOTDの最大プレーヤー数を設定します。(既定値: 0) + motd-max-players: 0 + #クエリの最大プレーヤー数を設定します。(既定値: 0) + query-max-players: 0 + #サーバーのMOTDに全プレイヤー数を表示するかどうかを設定します。 + motd-all-players: false + #クエリの全プレイヤー数を表示するかどうかを決定します。 + query-all-players: false + #MOTDにオンラインプレイヤー数を表示するかどうかを設定します。 + motd-players: false + #This setting shows the number of online players on Query + query-players: false + #クエリにオンラインプレイヤー数を表示するかどうかを設定します。 + time: 40 + #サーバーが読み込みに失敗した時に再試行を行う回数を設定します。(無効: 0 既定値: 3) + retry-times: 3 + #サーバーの一覧を表示するかどうかを決定します。(";"の部分でサーバー指定を区切ります。例: 1.example.com:19132; 2.example.com:19133) + server-list: "" + +inventory: + #インベントリ管理を行うかどうかを設定します。 + #無効にするとサーバーの在庫トランザクションを使用して処理します。 + #有効にするとPEまたはWindows10端末での不正を有効にします。 + allow-cheats: false diff --git a/src/devmine/server/resources/extended_kor.yml b/src/devmine/server/resources/extended_kor.yml new file mode 100644 index 0000000..b85f723 --- /dev/null +++ b/src/devmine/server/resources/extended_kor.yml @@ -0,0 +1,122 @@ +# +# _______ _ +# |__ __| | | +# | | ___ ___ ___ ___ _ __ __ _ ___| |_ +# | |/ _ \/ __/ __|/ _ \ '__/ _` |/ __| __| +# | | __/\__ \__ \ __/ | | (_| | (__| |_ +# |_|\___||___/___/\___|_| \__,_|\___|\__| +# +# +# +#DevMine 고급 구성 파일 + +#Version 파일의 버전 +config: + version: 27 + +level: + #날씨 시스템을 켜는 경우 설정하세요 + weather: true + #날씨 랜덤 기간 + weather-random-duration-min: 6000 + weather-random-duration-max: 12000 + #랜덤 번개 치는 주기,기본은 10초, 0 = 비활성화 + lightning-time: 200 + #번개가 불과 함께 치게 하려는 경우 설정하세요 + lightning-fire: false + #불이 번지는 것을 활성화 하려는 경우 설정하세요 + fire-spread: false + +player: + #배고픔 시스템 스위치 + hunger: true + #경험치 시스템을 켜는 경우 고르세요 + experience: true + #플레이어가 사망하였을때 인벤토리를 유지하려는 경우 고르세요 + keep-inventory: false + #게임 모드를 크리에이티브로 변경하는 경우 자동으로 인벤토리를 비웁니다 + auto-clear-inventory : true + #플레이어가 사망하였을때 경험치를 유지하려는 경우 고르세요 + keep-experience: false + #플레이어들이 참여했을때 크래시가 발생하는 경우, 이 값을 10 이하로 설정하세요. 비활성화=-1 + chunk-radius: -1 + +nether: + #지옥이 허용된 경우 고르세요. 지옥 레벨이 자동으로 생성됩니다. + allow-nether: true + #지옥 레벨의 이름 + level-name: "nether" + +server: + #철 골램을 생성하는 것이 허용된 경우 고르세요 + allow-iron-golem: false + #눈 골렘을 생성하는 것이 허용된 경우 고르세요 + allow-snow-golem: false + #server.log를 비활성화 하는 경우 고르세요 + disable-log: false + #비동기 청크 요청을 활성화 하는 경우 고르세요 + async-chunk-request: true + #플레이어가 참여할 때 뜨는 메시지를 고릅니다 + #0 = 메시지, 1 = 팁, 2 = 팝업 + player-msg-type: 0 + login-msg: "§3@player님이 게임에 참여했습니다" + logout-msg: "§3@player님이 게임을 떠났습니다" + #제한된 크리에이티브를 활성화 하는 경우 설정하세요 (아이템 드롭 불가, 상자 열기 불가 등) + limited-creative: true + #블럭 파괴 파티클을 추가하는 경우 설정하세요 + destroy-block-particle: true + #투척용 포션을 활성화 하는 경우 고르세요 + allow-splash-potion: true + #고급 명령어 선택기를 활성화 하는 경우 설정하세요 + advanced-command-selector: false + +enchantment: + #모루가 허용된 경우 고르세요 + enable-anvil: true + #마법 부여대가 허용된 경우 고르세요 + enable-enchanting-table: true + #책장의 수를 세려는 경우 활성화 하세요. 서버 랙을 유발할 수도 있습니다. + #만약 이 옵션이 false인 경우, 서버는 랜덤 카운트를 사용할 것 입니다 (0~15) + count-bookshelf: false + +redstone: + ################################################ + ######레드스톤 시스템이 허용된 경우 고르세요####### + ################################################ + #만약 true가 아닌 경우 레드스톤이 작동하지 않습니다# + ################################################ + enable: false + #주파수 펄스를 허용하는 경우 고르세요 + frequency-pulse: false + #펄스 주파수 설정, 기본: 1초 + pulse-frequency: 1 + +dserver: + #모든 멀티 (다중) 서버의 수 통합 + enable: false + #자동으로 쿼리 업데이트 + query-auto-update: false + #쿼리 업데이트 주기 + query-tick-update: true + #Motd 최대 플레이어 숫자 + motd-max-players: 0 + #쿼리 최대 플레이어 숫자,0=기본 + query-max-players: 0 + #motd에서 모든 플레이어의 숫자 표시 + motd-all-players: false + #쿼리에서 모든 플레이어의 숫자 표시 + query-all-players: false + #motd에서 온라인 플레이어의 숫자 표시 + motd-players: false + #쿼리에서 온라인 플레이어의 숫자 표시 + query-players: false + #업데이트 주기, 20=1초 + time: 40 + #실패한 경우 다시 시도할 빈도 + retry-times: 3 + #서버 목록,';'를 사용하여 분리하세요,예시: 1.example.com:19132;2.example.com:19133 + server-list: "" + +inventory: + #모루와 관련된 문제가 있는 경우 true로 설정하세요. 인벤토리 처리를 vanila fashion (기본 방식)으로 치트 방지나 확인 없이 진행합니다. + allow-cheats: true diff --git a/src/devmine/server/resources/devmine2_vie.yml b/src/devmine/server/resources/extended_vie.yml similarity index 63% rename from src/devmine/server/resources/devmine2_vie.yml rename to src/devmine/server/resources/extended_vie.yml index 4d7e4d2..d62b92b 100644 --- a/src/devmine/server/resources/devmine2_vie.yml +++ b/src/devmine/server/resources/extended_vie.yml @@ -1,8 +1,18 @@ -#Cài đặt devmine cho server (devmine VN Version) +# +# _______ _ +# |__ __| | | +# | | ___ ___ ___ ___ _ __ __ _ ___| |_ +# | |/ _ \/ __/ __|/ _ \ '__/ _` |/ __| __| +# | | __/\__ \__ \ __/ | | (_| | (__| |_ +# |_|\___||___/___/\___|_| \__,_|\___|\__| +# +# +# +#Cài đặt DevMine cho server (DevMine VN Version) #Phiên bản file cài đặt config: - version: 17 + version: 27 level: #Chỉnh nếu muốn bật/tắt thời tiết (true/false) @@ -20,16 +30,10 @@ level: player: #Bật/tắt nếu muốn thêm chế độ đói (true/false) hunger: true - #Số máu đói tối đa nếu có người tấn công (mặc định là 20) - hunger-health: 10 - #Thời gian "tấn công" cơn đói, Mặc định là 80=4 giây - hunger-timer: 3000 #Bật/tắt nếu muốn thêm chế độ điểm kinh nghiệm (true/false) experience: true #Bật/tắt nếu muốn server chết không mất đồ (true/false) keep-inventory: false - #Số lượng đồ trong kho đồ (mặc định là 36 slot) - inventory-num: 36 #Bật/tắt nếu tự động quét hết đồ trong kho đồ khi chuyển sang chế độ sáng tạo (true/false) auto-clear-inventory : true #Bật/tắt nếu muốn chết không mất kinh nghiệm (true/false) @@ -44,16 +48,12 @@ nether: level-name: "nether" server: - #Tái tạo lại hệ thống điểm kinh nghiệm,0=hủy bỏ chế độ - experience-cache: 65535 #Bật/tắt nếu muốn thêm Iron Golem vào server (true/false) allow-iron-golem: false #Bật/tắt nếu muốn thêm Snow Golem vào server (true/false) allow-snow-golem: false #Bật/tắt nếu muốn hủy server.log (true/false) disable-log: false - #Bật/tắt nếu muốn hủy chế độ bay (true/false) - anti-fly: true #Bật/tắt nếu muốn yêu cầu khối Async (mặc định: true) (true/false) async-chunk-request: true #Chọn để thông báo người chơi đã vào hoặc rời (nếu bạn không biết có thể bỏ qua) @@ -61,15 +61,6 @@ server: player-msg-type: 0 login-msg: "§3@player joined the game" logout-msg: "§3@player left the game" - #Bật/tắt nếu muốn sử dụng đồ chế tạo qua file json (mặc định: false) (true/false) - recipes-from-json: false - #Bật/tắt nếu muốn sử dụng đồ cre qua file json (mặc định: false) (true/false) - creative-items-from-json: false - #Chọn nếu muốn sử dụng xe ray tự do, theo đường ray hoặc hủy bỏ (mặc định: 1) - #-1=disable, 0=free moving, 1=follow rails - minecart-moving-type: 0 - #Bật/tắt nếu muốn kiểm tra tốc độ (không còn đẩy lùi mỗi khi đi) (true/false) - check-movement: true #Bật/tắt nếu kích hoạt chế độ sáng tạo giới hạn (Không thể rớt đồ, mở rương và hơn thế nữa) (mặc định: false) (true/false) limited-creative: true #Bật/tắt nếu muốn kích hoạt DestroyBlockParticle (phá block tự nhiên) (true/false) @@ -100,20 +91,6 @@ redstone: #Đánh số tỷ lệ hoạt động, mặc định: 1 giây pulse-frequency: 1 -synapse: - #Nếu muốn kích hoạt API của Synapse hoặc kết nối vào server Synapse, kích hoạt chế nđộ này - enabled: false - server-ip: 127.0.0.1 - server-port: 10305 - #Nếu Client này là server chính hoặc sv lobby - is-main-server: true - #Mật khẩu Synapse (có thể tham khảo ở server.properties tại Synapse) - server-password: 16bitlongkey - #Mô tả về hệ thống Synapse của bạn - description: "A Synapse client" - #Hủy RakLib tức là chỉ có thể vào Synapse mà không vào server này (mặc định là false) - disable-rak: false - dserver: #Tất cả các server gộp vào. Bật/tắt để hoạt động (true/false) enable: false @@ -139,31 +116,7 @@ dserver: retry-times: 3 #the server list,Separate by ';',e.g. 1.example.com:19132;2.example.com:19133 server-list: "" - -ai: - #Bật/tắt AI (true/false) (bên dưới là kích hoạt các AI nếu muốn cho vào server, đánh true/false) - enable: false - #Zombie'AI,0=hủy bỏ,1=AI 2=AI mới(Siêu nhân) - zombie: 1 - #AI Zombie Lợn - pigzombie: true - #AI bò và bò nấm - cow: true - #AI gà - chicken: true - #AI cừu - sheep: true - #AI lợn - pig: true - #AI người xương - skeleton: true - #AI Creeper - creeper: true - #AI Iron Golem (người sắt) - iron-golem: true - #AI Snow Golem (người tuyết) - snow-golem: true - #Phá hủy các khối nếu creeper nổ (true/false) - creeper-explode-destroy-block: false - #Bật/tắt nếu muốn kích hoạt chế độ mob tự spawn (true/false) - mobgenerate: false + +inventory: + #Set this to true if you have problems with anvils. Will process inventory transactions in a vanilla fashion with no anti-cheats or verification. + allow-cheats: true diff --git a/src/devmine/server/resources/devmine2_zho.yml b/src/devmine/server/resources/extended_zho.yml similarity index 63% rename from src/devmine/server/resources/devmine2_zho.yml rename to src/devmine/server/resources/extended_zho.yml index a5adb98..0d78283 100644 --- a/src/devmine/server/resources/devmine2_zho.yml +++ b/src/devmine/server/resources/extended_zho.yml @@ -1,8 +1,18 @@ -#devmine進階設定檔案 +# +# _______ _ +# |__ __| | | +# | | ___ ___ ___ ___ _ __ __ _ ___| |_ +# | |/ _ \/ __/ __|/ _ \ '__/ _` |/ __| __| +# | | __/\__ \__ \ __/ | | (_| | (__| |_ +# |_|\___||___/___/\___|_| \__,_|\___|\__| +# +# +# +#DevMine進階設定檔案 #設定檔案版本 config: - version: 17 + version: 27 level: #設定是否變換天氣 @@ -20,16 +30,10 @@ level: player: #是否打開飢餓 hunger: true - #飢餓值扣血下限 - hunger-health: 10 - #飢餓值飢餓值計時器,預設80=4秒 - hunger-timer: 3000 #是否打開經驗系統 experience: true #是否開啟死亡不掉落 keep-inventory: false - #背包格數 - inventory-num: 36 #是否開啟切換模式自動清除背包 auto-clear-inventory: true #是否開啟死亡經驗不掉落 @@ -44,31 +48,18 @@ nether: level-name: "nether" server: - #經驗數據預生成,0不啟用 - experience-cache: 65535 #是否允許生成鐵傀儡 allow-iron-golem: false #是否允許生成雪傀儡 allow-snow-golem: false #是否停用server.log disable-log: false - #是否啟用反飛行作弊 - anti-fly: true #是否啟用異步發送區塊 async-chunk-request: true #玩家進出伺服器訊息提醒方式。0為Message,1為Tip,2為Popup player-msg-type: 0 login-msg: "§3@player 加入了遊戲" logout-msg: "§3@player 離開了遊戲" - #是否從recipes.json讀取合成公式 - recipes-from-json: false - #是否從creativeitems.json讀取創造物品 - creative-items-from-json: false - #設置礦車行為方式 - #-1=禁用礦車移動, 0=自由移動, 1=沿鐵軌行駛 - minecart-moving-type: 0 - #是否進行移動檢測(不再拉回了) - check-movement: true #是否限制創造某些功能(禁止丟物品, 禁止操作箱子等等) limited-creative: true #是否開啟方塊破壞粒子效果 @@ -100,19 +91,6 @@ redstone: #設定脈衝頻率, 預設: 1s pulse-frequency: 1 -synapse: - #如果你想使用 Synapse API 或連接到一個synapse伺服器,請將enabled置為true - enabled: false - server-ip: 127.0.0.1 - server-port: 10305 - #設置該伺服器是否為接待大廳伺服器或主要伺服器 - is-main-server: true - server-password: 16bitlongkey - #設置該伺服器唯一的識別字 - description: "A Synapse client" - #啟用Disable RakLib設置玩家僅能通過接待大廳伺服器或主要伺服器加入遊戲 - disable-rak: false - dserver: #多服統一人數 enable: false @@ -138,31 +116,7 @@ dserver: retry-times: 3 #伺服器列表,用;隔開,例如 1.example.com:19132;2.example.com:19133 server-list: "" - -ai: - #AI總開關 - enable: false - #殭屍的AI,0為關閉,1為1.0版AI,2為新AI(不完善) - zombie: 1 - #殭屍豬人的AI - pigzombie: true - #牛和哞菇的AI - cow: true - #雞的AI - chicken: true - #羊的AI - sheep: true - #豬的AI - pig: true - #骷髏的AI - skeleton: true - #苦力帕的AI - creeper: true - #鐵傀儡的AI - iron-golem: true - #雪傀儡的AI - snow-golem: true - #苦力帕爆炸是否破壞方塊 - creeper-explode-destroy-block: false - #是否允許自動生成生物 - mobgenerate: false + +inventory: + #Set this to true if you have problems with anvils. Will process inventory transactions in a vanilla fashion with no anti-cheats or verification. + allow-cheats: true diff --git a/src/devmine/server/resources/recipes.json b/src/devmine/server/resources/recipes.json index 25d8a08..bfe23bc 100644 --- a/src/devmine/server/resources/recipes.json +++ b/src/devmine/server/resources/recipes.json @@ -1 +1,14952 @@ -[{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":270,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":269,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":271,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":290,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":274,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":273,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":275,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":291,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":257,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":256,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":258,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":292,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":278,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":277,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":279,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":293,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":285,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":284,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":286,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":294,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":359,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":268,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":272,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":267,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":276,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":283,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":287,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":287,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":287,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":261,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":318,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":288,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":262,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":266,"Count":9,"Damage":0,"NBT":null},{"ID":266,"Count":9,"Damage":0,"NBT":null},{"ID":266,"Count":9,"Damage":0,"NBT":null},{"ID":266,"Count":9,"Damage":0,"NBT":null},{"ID":266,"Count":9,"Damage":0,"NBT":null},{"ID":266,"Count":9,"Damage":0,"NBT":null},{"ID":266,"Count":9,"Damage":0,"NBT":null},{"ID":266,"Count":9,"Damage":0,"NBT":null},{"ID":266,"Count":9,"Damage":0,"NBT":null}],"Result":[{"ID":41,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":41,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":266,"Count":9,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":9,"Damage":0,"NBT":null},{"ID":265,"Count":9,"Damage":0,"NBT":null},{"ID":265,"Count":9,"Damage":0,"NBT":null},{"ID":265,"Count":9,"Damage":0,"NBT":null},{"ID":265,"Count":9,"Damage":0,"NBT":null},{"ID":265,"Count":9,"Damage":0,"NBT":null},{"ID":265,"Count":9,"Damage":0,"NBT":null},{"ID":265,"Count":9,"Damage":0,"NBT":null},{"ID":265,"Count":9,"Damage":0,"NBT":null}],"Result":[{"ID":42,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":42,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":265,"Count":9,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":264,"Count":9,"Damage":0,"NBT":null},{"ID":264,"Count":9,"Damage":0,"NBT":null},{"ID":264,"Count":9,"Damage":0,"NBT":null},{"ID":264,"Count":9,"Damage":0,"NBT":null},{"ID":264,"Count":9,"Damage":0,"NBT":null},{"ID":264,"Count":9,"Damage":0,"NBT":null},{"ID":264,"Count":9,"Damage":0,"NBT":null},{"ID":264,"Count":9,"Damage":0,"NBT":null},{"ID":264,"Count":9,"Damage":0,"NBT":null}],"Result":[{"ID":57,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":57,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":264,"Count":9,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":388,"Count":9,"Damage":0,"NBT":null},{"ID":388,"Count":9,"Damage":0,"NBT":null},{"ID":388,"Count":9,"Damage":0,"NBT":null},{"ID":388,"Count":9,"Damage":0,"NBT":null},{"ID":388,"Count":9,"Damage":0,"NBT":null},{"ID":388,"Count":9,"Damage":0,"NBT":null},{"ID":388,"Count":9,"Damage":0,"NBT":null},{"ID":388,"Count":9,"Damage":0,"NBT":null},{"ID":388,"Count":9,"Damage":0,"NBT":null}],"Result":[{"ID":133,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":133,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":388,"Count":9,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":331,"Count":9,"Damage":0,"NBT":null},{"ID":331,"Count":9,"Damage":0,"NBT":null},{"ID":331,"Count":9,"Damage":0,"NBT":null},{"ID":331,"Count":9,"Damage":0,"NBT":null},{"ID":331,"Count":9,"Damage":0,"NBT":null},{"ID":331,"Count":9,"Damage":0,"NBT":null},{"ID":331,"Count":9,"Damage":0,"NBT":null},{"ID":331,"Count":9,"Damage":0,"NBT":null},{"ID":331,"Count":9,"Damage":0,"NBT":null}],"Result":[{"ID":152,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":152,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":331,"Count":9,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":351,"Count":9,"Damage":4,"NBT":null},{"ID":351,"Count":9,"Damage":4,"NBT":null},{"ID":351,"Count":9,"Damage":4,"NBT":null},{"ID":351,"Count":9,"Damage":4,"NBT":null},{"ID":351,"Count":9,"Damage":4,"NBT":null},{"ID":351,"Count":9,"Damage":4,"NBT":null},{"ID":351,"Count":9,"Damage":4,"NBT":null},{"ID":351,"Count":9,"Damage":4,"NBT":null},{"ID":351,"Count":9,"Damage":4,"NBT":null}],"Result":[{"ID":22,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":22,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":351,"Count":9,"Damage":4,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":296,"Count":9,"Damage":0,"NBT":null},{"ID":296,"Count":9,"Damage":0,"NBT":null},{"ID":296,"Count":9,"Damage":0,"NBT":null},{"ID":296,"Count":9,"Damage":0,"NBT":null},{"ID":296,"Count":9,"Damage":0,"NBT":null},{"ID":296,"Count":9,"Damage":0,"NBT":null},{"ID":296,"Count":9,"Damage":0,"NBT":null},{"ID":296,"Count":9,"Damage":0,"NBT":null},{"ID":296,"Count":9,"Damage":0,"NBT":null}],"Result":[{"ID":170,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":170,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":296,"Count":9,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":263,"Count":9,"Damage":0,"NBT":null},{"ID":263,"Count":9,"Damage":0,"NBT":null},{"ID":263,"Count":9,"Damage":0,"NBT":null},{"ID":263,"Count":9,"Damage":0,"NBT":null},{"ID":263,"Count":9,"Damage":0,"NBT":null},{"ID":263,"Count":9,"Damage":0,"NBT":null},{"ID":263,"Count":9,"Damage":0,"NBT":null},{"ID":263,"Count":9,"Damage":0,"NBT":null},{"ID":263,"Count":9,"Damage":0,"NBT":null}],"Result":[{"ID":173,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":173,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":263,"Count":9,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":266,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":371,"Count":9,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":39,"Count":1,"Damage":-1,"NBT":null},{"ID":40,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":281,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":282,"Count":1,"Damage":0,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":39,"Count":1,"Damage":-1,"NBT":null},{"ID":40,"Count":1,"Damage":-1,"NBT":null},{"ID":281,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":282,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":457,"Count":1,"Damage":0,"NBT":null},{"ID":457,"Count":1,"Damage":0,"NBT":null},{"ID":457,"Count":1,"Damage":0,"NBT":null},{"ID":457,"Count":1,"Damage":0,"NBT":null},{"ID":457,"Count":1,"Damage":0,"NBT":null},{"ID":457,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":281,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":459,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":296,"Count":1,"Damage":0,"NBT":null},{"ID":351,"Count":1,"Damage":3,"NBT":null},{"ID":296,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":357,"Count":8,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":360,"Count":1,"Damage":0,"NBT":null},{"ID":360,"Count":1,"Damage":0,"NBT":null},{"ID":360,"Count":1,"Damage":0,"NBT":null},{"ID":360,"Count":1,"Damage":0,"NBT":null},{"ID":360,"Count":1,"Damage":0,"NBT":null},{"ID":360,"Count":1,"Damage":0,"NBT":null},{"ID":360,"Count":1,"Damage":0,"NBT":null},{"ID":360,"Count":1,"Damage":0,"NBT":null},{"ID":360,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":103,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":360,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":362,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":86,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":361,"Count":4,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":86,"Count":1,"Damage":-1,"NBT":null},{"ID":353,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":344,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":400,"Count":1,"Damage":0,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":86,"Count":1,"Damage":-1,"NBT":null},{"ID":353,"Count":1,"Damage":0,"NBT":null},{"ID":344,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":400,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":375,"Count":1,"Damage":0,"NBT":null},{"ID":353,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":39,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":376,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":54,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":131,"Count":1,"Damage":-1,"NBT":null},{"ID":54,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":146,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":61,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":58,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":12,"Count":1,"Damage":0,"NBT":null},{"ID":12,"Count":1,"Damage":0,"NBT":null},{"ID":12,"Count":1,"Damage":0,"NBT":null},{"ID":12,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":24,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":24,"Count":1,"Damage":-1,"NBT":null},{"ID":24,"Count":1,"Damage":-1,"NBT":null},{"ID":24,"Count":1,"Damage":-1,"NBT":null},{"ID":24,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":24,"Count":4,"Damage":2,"NBT":null}]},{"Height":2,"Width":1,"Type":1,"Ingredients":[{"ID":44,"Count":1,"Damage":1,"NBT":null},{"ID":44,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":24,"Count":1,"Damage":1,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":1,"Count":1,"Damage":0,"NBT":null},{"ID":1,"Count":1,"Damage":0,"NBT":null},{"ID":1,"Count":1,"Damage":0,"NBT":null},{"ID":1,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":98,"Count":4,"Damage":0,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":98,"Count":1,"Damage":-1,"NBT":null},{"ID":106,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":98,"Count":1,"Damage":1,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":98,"Count":1,"Damage":-1,"NBT":null},{"ID":106,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":98,"Count":1,"Damage":1,"NBT":null}]},{"Height":2,"Width":1,"Type":1,"Ingredients":[{"ID":44,"Count":1,"Damage":5,"NBT":null},{"ID":44,"Count":1,"Damage":5,"NBT":null}],"Result":[{"ID":98,"Count":1,"Damage":3,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":106,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":48,"Count":1,"Damage":0,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":106,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":48,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":101,"Count":16,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":20,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":102,"Count":16,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":405,"Count":1,"Damage":0,"NBT":null},{"ID":405,"Count":1,"Damage":0,"NBT":null},{"ID":405,"Count":1,"Damage":0,"NBT":null},{"ID":405,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":112,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":406,"Count":1,"Damage":0,"NBT":null},{"ID":406,"Count":1,"Damage":0,"NBT":null},{"ID":406,"Count":1,"Damage":0,"NBT":null},{"ID":406,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":155,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":1,"Type":1,"Ingredients":[{"ID":44,"Count":1,"Damage":6,"NBT":null},{"ID":44,"Count":1,"Damage":6,"NBT":null}],"Result":[{"ID":155,"Count":1,"Damage":1,"NBT":null}]},{"Height":2,"Width":1,"Type":1,"Ingredients":[{"ID":155,"Count":1,"Damage":0,"NBT":null},{"ID":155,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":155,"Count":2,"Damage":2,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":406,"Count":1,"Damage":0,"NBT":null},{"ID":406,"Count":1,"Damage":0,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":1,"Count":2,"Damage":3,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":1,"Count":1,"Damage":3,"NBT":null},{"ID":406,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":1,"Count":1,"Damage":1,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":1,"Count":1,"Damage":3,"NBT":null},{"ID":406,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":1,"Count":1,"Damage":1,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":1,"Count":1,"Damage":3,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":1,"Count":2,"Damage":5,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":1,"Count":1,"Damage":3,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":1,"Count":2,"Damage":5,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":1,"Count":1,"Damage":3,"NBT":null},{"ID":1,"Count":1,"Damage":3,"NBT":null},{"ID":1,"Count":1,"Damage":3,"NBT":null},{"ID":1,"Count":1,"Damage":3,"NBT":null}],"Result":[{"ID":1,"Count":4,"Damage":4,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":1,"Count":1,"Damage":1,"NBT":null},{"ID":1,"Count":1,"Damage":1,"NBT":null},{"ID":1,"Count":1,"Damage":1,"NBT":null},{"ID":1,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":1,"Count":4,"Damage":2,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":1,"Count":1,"Damage":5,"NBT":null},{"ID":1,"Count":1,"Damage":5,"NBT":null},{"ID":1,"Count":1,"Damage":5,"NBT":null},{"ID":1,"Count":1,"Damage":5,"NBT":null}],"Result":[{"ID":1,"Count":4,"Damage":6,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":298,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":299,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":300,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":301,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":306,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":307,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":308,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":309,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":310,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":311,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":312,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":313,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":314,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":315,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":316,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":317,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":0,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":15,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":14,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":2,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":13,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":3,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":12,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":11,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":5,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":10,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":6,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":9,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":7,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":8,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":8,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":7,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":9,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":6,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":10,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":5,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":11,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":4,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":12,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":3,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":13,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":2,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":14,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":1,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":15,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":37,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":351,"Count":1,"Damage":11,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":244,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":1,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":38,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":351,"Count":1,"Damage":1,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":352,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":351,"Count":3,"Damage":15,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":9,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":9,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":351,"Count":1,"Damage":11,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":14,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":351,"Count":1,"Damage":11,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":14,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":2,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":10,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":2,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":10,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":0,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":8,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":0,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":8,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":8,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":7,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":8,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":7,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":0,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":3,"Damage":7,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":0,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":3,"Damage":7,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":0,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":351,"Count":1,"Damage":11,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":3,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":0,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":351,"Count":1,"Damage":11,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":3,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":12,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":12,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":351,"Count":1,"Damage":2,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":6,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":351,"Count":1,"Damage":2,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":6,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":5,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":5,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":5,"NBT":null},{"ID":351,"Count":1,"Damage":9,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":13,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":5,"NBT":null},{"ID":351,"Count":1,"Damage":9,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":13,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":351,"Count":1,"Damage":9,"NBT":null}],"Result":[{"ID":351,"Count":3,"Damage":13,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":351,"Count":1,"Damage":9,"NBT":null}],"Result":[{"ID":351,"Count":3,"Damage":13,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":351,"Count":4,"Damage":13,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":351,"Count":4,"Damage":13,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":38,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":351,"Count":1,"Damage":12,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":38,"Count":1,"Damage":2,"NBT":null}],"Result":[{"ID":351,"Count":1,"Damage":13,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":38,"Count":1,"Damage":3,"NBT":null}],"Result":[{"ID":351,"Count":1,"Damage":7,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":38,"Count":1,"Damage":4,"NBT":null}],"Result":[{"ID":351,"Count":1,"Damage":1,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":38,"Count":1,"Damage":5,"NBT":null}],"Result":[{"ID":351,"Count":1,"Damage":14,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":38,"Count":1,"Damage":6,"NBT":null}],"Result":[{"ID":351,"Count":1,"Damage":7,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":38,"Count":1,"Damage":7,"NBT":null}],"Result":[{"ID":351,"Count":1,"Damage":9,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":38,"Count":1,"Damage":8,"NBT":null}],"Result":[{"ID":351,"Count":1,"Damage":7,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":175,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":11,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":175,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":13,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":175,"Count":1,"Damage":4,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":1,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":175,"Count":1,"Damage":5,"NBT":null}],"Result":[{"ID":351,"Count":2,"Damage":9,"NBT":null}]},{"Type":5},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":338,"Count":1,"Damage":0,"NBT":null},{"ID":338,"Count":1,"Damage":0,"NBT":null},{"ID":338,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":339,"Count":3,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":339,"Count":1,"Damage":0,"NBT":null},{"ID":339,"Count":1,"Damage":0,"NBT":null},{"ID":339,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":340,"Count":1,"Damage":0,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":339,"Count":1,"Damage":0,"NBT":null},{"ID":339,"Count":1,"Damage":0,"NBT":null},{"ID":339,"Count":1,"Damage":0,"NBT":null},{"ID":334,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":340,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":139,"Count":6,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":48,"Count":1,"Damage":-1,"NBT":null},{"ID":48,"Count":1,"Damage":-1,"NBT":null},{"ID":48,"Count":1,"Damage":-1,"NBT":null},{"ID":48,"Count":1,"Damage":-1,"NBT":null},{"ID":48,"Count":1,"Damage":-1,"NBT":null},{"ID":48,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":139,"Count":6,"Damage":1,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":113,"Count":6,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":85,"Count":3,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":85,"Count":3,"Damage":1,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null}],"Result":[{"ID":85,"Count":3,"Damage":2,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null}],"Result":[{"ID":85,"Count":3,"Damage":3,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null}],"Result":[{"ID":85,"Count":3,"Damage":4,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null}],"Result":[{"ID":85,"Count":3,"Damage":5,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":107,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":183,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":184,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":185,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":187,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":186,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":42,"Count":1,"Damage":-1,"NBT":null},{"ID":42,"Count":1,"Damage":-1,"NBT":null},{"ID":42,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":145,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":340,"Count":1,"Damage":0,"NBT":null},{"ID":340,"Count":1,"Damage":0,"NBT":null},{"ID":340,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":47,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":332,"Count":1,"Damage":0,"NBT":null},{"ID":332,"Count":1,"Damage":0,"NBT":null},{"ID":332,"Count":1,"Damage":0,"NBT":null},{"ID":332,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":80,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":80,"Count":1,"Damage":-1,"NBT":null},{"ID":80,"Count":1,"Damage":-1,"NBT":null},{"ID":80,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":78,"Count":6,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":337,"Count":1,"Damage":0,"NBT":null},{"ID":337,"Count":1,"Damage":0,"NBT":null},{"ID":337,"Count":1,"Damage":0,"NBT":null},{"ID":337,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":82,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":336,"Count":1,"Damage":0,"NBT":null},{"ID":336,"Count":1,"Damage":0,"NBT":null},{"ID":336,"Count":1,"Damage":0,"NBT":null},{"ID":336,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":45,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":348,"Count":1,"Damage":0,"NBT":null},{"ID":348,"Count":1,"Damage":0,"NBT":null},{"ID":348,"Count":1,"Damage":0,"NBT":null},{"ID":348,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":89,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":287,"Count":1,"Damage":0,"NBT":null},{"ID":287,"Count":1,"Damage":0,"NBT":null},{"ID":287,"Count":1,"Damage":0,"NBT":null},{"ID":287,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":35,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":289,"Count":1,"Damage":0,"NBT":null},{"ID":12,"Count":1,"Damage":-1,"NBT":null},{"ID":289,"Count":1,"Damage":0,"NBT":null},{"ID":12,"Count":1,"Damage":-1,"NBT":null},{"ID":289,"Count":1,"Damage":0,"NBT":null},{"ID":12,"Count":1,"Damage":-1,"NBT":null},{"ID":289,"Count":1,"Damage":0,"NBT":null},{"ID":12,"Count":1,"Damage":-1,"NBT":null},{"ID":289,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":46,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":44,"Count":6,"Damage":3,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":1,"Count":1,"Damage":-1,"NBT":null},{"ID":1,"Count":1,"Damage":-1,"NBT":null},{"ID":1,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":44,"Count":6,"Damage":0,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":24,"Count":1,"Damage":-1,"NBT":null},{"ID":24,"Count":1,"Damage":-1,"NBT":null},{"ID":24,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":44,"Count":6,"Damage":1,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":158,"Count":6,"Damage":0,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":158,"Count":6,"Damage":1,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null}],"Result":[{"ID":158,"Count":6,"Damage":2,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null}],"Result":[{"ID":158,"Count":6,"Damage":3,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null}],"Result":[{"ID":158,"Count":6,"Damage":4,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null}],"Result":[{"ID":158,"Count":6,"Damage":5,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":45,"Count":1,"Damage":-1,"NBT":null},{"ID":45,"Count":1,"Damage":-1,"NBT":null},{"ID":45,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":44,"Count":6,"Damage":4,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":98,"Count":1,"Damage":-1,"NBT":null},{"ID":98,"Count":1,"Damage":-1,"NBT":null},{"ID":98,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":44,"Count":6,"Damage":5,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":44,"Count":6,"Damage":7,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":155,"Count":1,"Damage":-1,"NBT":null},{"ID":155,"Count":1,"Damage":-1,"NBT":null},{"ID":155,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":44,"Count":6,"Damage":6,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":65,"Count":3,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":324,"Count":3,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":427,"Count":3,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null}],"Result":[{"ID":428,"Count":3,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null}],"Result":[{"ID":429,"Count":3,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null}],"Result":[{"ID":430,"Count":3,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null}],"Result":[{"ID":431,"Count":3,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":96,"Count":2,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":167,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":1,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":131,"Count":2,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":331,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":25,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":2,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":330,"Count":3,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":323,"Count":3,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":325,"Count":1,"Damage":1,"NBT":null},{"ID":325,"Count":1,"Damage":1,"NBT":null},{"ID":325,"Count":1,"Damage":1,"NBT":null},{"ID":353,"Count":1,"Damage":0,"NBT":null},{"ID":344,"Count":1,"Damage":0,"NBT":null},{"ID":353,"Count":1,"Damage":0,"NBT":null},{"ID":296,"Count":1,"Damage":0,"NBT":null},{"ID":296,"Count":1,"Damage":0,"NBT":null},{"ID":296,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":354,"Count":1,"Damage":0,"NBT":null},{"ID":325,"Count":3,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":338,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":353,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":391,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":396,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":360,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null},{"ID":371,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":382,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":369,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":377,"Count":2,"Damage":0,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":377,"Count":1,"Damage":0,"NBT":null},{"ID":341,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":378,"Count":1,"Damage":0,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":377,"Count":1,"Damage":0,"NBT":null},{"ID":341,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":378,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":39,"Count":1,"Damage":-1,"NBT":null},{"ID":353,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":375,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":376,"Count":1,"Damage":0,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":39,"Count":1,"Damage":-1,"NBT":null},{"ID":353,"Count":1,"Damage":0,"NBT":null},{"ID":375,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":376,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":17,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":5,"Count":4,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":17,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":5,"Count":4,"Damage":1,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":17,"Count":1,"Damage":2,"NBT":null}],"Result":[{"ID":5,"Count":4,"Damage":2,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":17,"Count":1,"Damage":3,"NBT":null}],"Result":[{"ID":5,"Count":4,"Damage":3,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":162,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":5,"Count":4,"Damage":4,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":162,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":5,"Count":4,"Damage":5,"NBT":null}]},{"Height":2,"Width":1,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":280,"Count":4,"Damage":0,"NBT":null}]},{"Height":2,"Width":1,"Type":1,"Ingredients":[{"ID":263,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":50,"Count":4,"Damage":0,"NBT":null}]},{"Height":2,"Width":1,"Type":1,"Ingredients":[{"ID":263,"Count":1,"Damage":1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":50,"Count":4,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":281,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":412,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":391,"Count":1,"Damage":0,"NBT":null},{"ID":393,"Count":1,"Damage":0,"NBT":null},{"ID":39,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":281,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":413,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":412,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":391,"Count":1,"Damage":0,"NBT":null},{"ID":393,"Count":1,"Damage":0,"NBT":null},{"ID":40,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":281,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":413,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":374,"Count":3,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":336,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":336,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":336,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":390,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":66,"Count":16,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":331,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":27,"Count":6,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":70,"Count":1,"Damage":-1,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":331,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":28,"Count":6,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":76,"Count":1,"Damage":-1,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":126,"Count":6,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":328,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":369,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":379,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":1,"Type":1,"Ingredients":[{"ID":86,"Count":1,"Damage":-1,"NBT":null},{"ID":50,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":91,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":269,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":333,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":269,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":333,"Count":1,"Damage":1,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":269,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null}],"Result":[{"ID":333,"Count":1,"Damage":2,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":269,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null}],"Result":[{"ID":333,"Count":1,"Damage":3,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":269,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null}],"Result":[{"ID":333,"Count":1,"Damage":4,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":269,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null}],"Result":[{"ID":333,"Count":1,"Damage":5,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":325,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":318,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":259,"Count":1,"Damage":0,"NBT":null}]},{"Type":0,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":318,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":259,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":3,"Type":1,"Ingredients":[{"ID":296,"Count":1,"Damage":0,"NBT":null},{"ID":296,"Count":1,"Damage":0,"NBT":null},{"ID":296,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":297,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":53,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null},{"ID":5,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":134,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null},{"ID":5,"Count":1,"Damage":2,"NBT":null}],"Result":[{"ID":135,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null},{"ID":5,"Count":1,"Damage":3,"NBT":null}],"Result":[{"ID":136,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null},{"ID":5,"Count":1,"Damage":4,"NBT":null}],"Result":[{"ID":163,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null},{"ID":5,"Count":1,"Damage":5,"NBT":null}],"Result":[{"ID":164,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":67,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":45,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":45,"Count":1,"Damage":-1,"NBT":null},{"ID":45,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":45,"Count":1,"Damage":-1,"NBT":null},{"ID":45,"Count":1,"Damage":-1,"NBT":null},{"ID":45,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":108,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":24,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":24,"Count":1,"Damage":-1,"NBT":null},{"ID":24,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":24,"Count":1,"Damage":-1,"NBT":null},{"ID":24,"Count":1,"Damage":-1,"NBT":null},{"ID":24,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":128,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":98,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":98,"Count":1,"Damage":-1,"NBT":null},{"ID":98,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":98,"Count":1,"Damage":-1,"NBT":null},{"ID":98,"Count":1,"Damage":-1,"NBT":null},{"ID":98,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":109,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":155,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":155,"Count":1,"Damage":-1,"NBT":null},{"ID":155,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":155,"Count":1,"Damage":-1,"NBT":null},{"ID":155,"Count":1,"Damage":-1,"NBT":null},{"ID":155,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":156,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null},{"ID":112,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":114,"Count":4,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":287,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":287,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":346,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":35,"Count":1,"Damage":-1,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":321,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":260,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":322,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":41,"Count":1,"Damage":-1,"NBT":null},{"ID":41,"Count":1,"Damage":-1,"NBT":null},{"ID":41,"Count":1,"Damage":-1,"NBT":null},{"ID":41,"Count":1,"Damage":-1,"NBT":null},{"ID":260,"Count":1,"Damage":0,"NBT":null},{"ID":41,"Count":1,"Damage":-1,"NBT":null},{"ID":41,"Count":1,"Damage":-1,"NBT":null},{"ID":41,"Count":1,"Damage":-1,"NBT":null},{"ID":41,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":466,"Count":1,"Damage":1,"NBT":null}]},{"Height":2,"Width":1,"Type":1,"Ingredients":[{"ID":280,"Count":1,"Damage":0,"NBT":null},{"ID":4,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":69,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":1,"Type":1,"Ingredients":[{"ID":331,"Count":1,"Damage":0,"NBT":null},{"ID":280,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":76,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":20,"Count":1,"Damage":-1,"NBT":null},{"ID":406,"Count":1,"Damage":0,"NBT":null},{"ID":406,"Count":1,"Damage":0,"NBT":null},{"ID":406,"Count":1,"Damage":0,"NBT":null},{"ID":158,"Count":1,"Damage":-1,"NBT":null},{"ID":158,"Count":1,"Damage":-1,"NBT":null},{"ID":158,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":151,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":331,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":331,"Count":1,"Damage":0,"NBT":null},{"ID":89,"Count":1,"Damage":-1,"NBT":null},{"ID":331,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":331,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":123,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":331,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":347,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":331,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null}],"Result":[{"ID":345,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":1,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":77,"Count":1,"Damage":5,"NBT":null}]},{"Height":1,"Width":1,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":143,"Count":1,"Damage":5,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":1,"Count":1,"Damage":0,"NBT":null},{"ID":1,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":70,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":72,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":266,"Count":1,"Damage":0,"NBT":null},{"ID":266,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":147,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":265,"Count":1,"Damage":0,"NBT":null},{"ID":265,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":148,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":3,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":-1,"NBT":null},{"ID":35,"Count":1,"Damage":-1,"NBT":null},{"ID":35,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null},{"ID":5,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":355,"Count":1,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":340,"Count":1,"Damage":0,"NBT":null},{"ID":0,"Count":0,"Damage":0,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":49,"Count":1,"Damage":-1,"NBT":null},{"ID":264,"Count":1,"Damage":0,"NBT":null},{"ID":49,"Count":1,"Damage":-1,"NBT":null},{"ID":49,"Count":1,"Damage":-1,"NBT":null},{"ID":49,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":116,"Count":1,"Damage":0,"NBT":null}]},{"Height":2,"Width":2,"Type":1,"Ingredients":[{"ID":415,"Count":1,"Damage":0,"NBT":null},{"ID":415,"Count":1,"Damage":0,"NBT":null},{"ID":415,"Count":1,"Damage":0,"NBT":null},{"ID":415,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":334,"Count":1,"Damage":0,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":0,"NBT":null},{"ID":35,"Count":1,"Damage":0,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":0,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":0,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":15,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":1,"NBT":null},{"ID":35,"Count":1,"Damage":1,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":1,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":14,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":2,"NBT":null},{"ID":35,"Count":1,"Damage":2,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":2,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":2,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":13,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":3,"NBT":null},{"ID":35,"Count":1,"Damage":3,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":3,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":3,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":12,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":4,"NBT":null},{"ID":35,"Count":1,"Damage":4,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":4,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":4,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":11,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":5,"NBT":null},{"ID":35,"Count":1,"Damage":5,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":5,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":5,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":10,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":6,"NBT":null},{"ID":35,"Count":1,"Damage":6,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":6,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":6,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":9,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":7,"NBT":null},{"ID":35,"Count":1,"Damage":7,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":7,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":7,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":8,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":8,"NBT":null},{"ID":35,"Count":1,"Damage":8,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":8,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":8,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":7,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":9,"NBT":null},{"ID":35,"Count":1,"Damage":9,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":9,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":9,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":6,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":10,"NBT":null},{"ID":35,"Count":1,"Damage":10,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":10,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":10,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":5,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":11,"NBT":null},{"ID":35,"Count":1,"Damage":11,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":11,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":11,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":4,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":12,"NBT":null},{"ID":35,"Count":1,"Damage":12,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":12,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":12,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":3,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":13,"NBT":null},{"ID":35,"Count":1,"Damage":13,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":13,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":13,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":2,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":14,"NBT":null},{"ID":35,"Count":1,"Damage":14,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":14,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":14,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":1,"NBT":null}]},{"Height":1,"Width":2,"Type":1,"Ingredients":[{"ID":35,"Count":1,"Damage":15,"NBT":null},{"ID":35,"Count":1,"Damage":15,"NBT":null}],"Result":[{"ID":171,"Count":3,"Damage":15,"NBT":null}]},{"Height":3,"Width":3,"Type":1,"Ingredients":[{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":351,"Count":1,"Damage":15,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null},{"ID":172,"Count":1,"Damage":-1,"NBT":null}],"Result":[{"ID":159,"Count":8,"Damage":0,"NBT":null}]},{"Type":2,"Ingredients":4,"Result":{"ID":1,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":12,"Result":{"ID":20,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":14,"Result":{"ID":266,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":15,"Result":{"ID":265,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":16,"Result":{"ID":263,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":17,"Result":{"ID":263,"Count":1,"Damage":1,"NBT":null}},{"Type":2,"Ingredients":21,"Result":{"ID":351,"Count":1,"Damage":4,"NBT":null}},{"Type":2,"Ingredients":56,"Result":{"ID":264,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":73,"Result":{"ID":331,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":81,"Result":{"ID":351,"Count":1,"Damage":2,"NBT":null}},{"Type":2,"Ingredients":82,"Result":{"ID":172,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":87,"Result":{"ID":405,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":129,"Result":{"ID":388,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":153,"Result":{"ID":406,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":162,"Result":{"ID":263,"Count":1,"Damage":1,"NBT":null}},{"Type":2,"Ingredients":319,"Result":{"ID":320,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":337,"Result":{"ID":336,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":349,"Result":{"ID":350,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":363,"Result":{"ID":364,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":365,"Result":{"ID":366,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":392,"Result":{"ID":393,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":411,"Result":{"ID":412,"Count":1,"Damage":0,"NBT":null}},{"Type":2,"Ingredients":460,"Result":{"ID":463,"Count":1,"Damage":0,"NBT":null}},{"Type":3,"Ingredients":{"ID":98,"Damage":0},"Result":{"ID":98,"Count":1,"Damage":2,"NBT":null}}] +[ + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 270, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "13387c33-d81b-23b3-830c-43916c85faa6" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 269, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "ca36ebc4-3dee-1729d-84e8-e8e79c9e1c9a" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 271, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "40373810-bbd7-16e8f-8115-50fe39dd1685" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 290, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "ca398dbf-d513-20c1e-8428-e0d2d8391286" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 274, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "943c4b32-04ab-5364-8487-9670e5d95389" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 273, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "af3a62c3-c8df-89f6-8096-c2fcced7ccb2" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 275, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "fc33909d-34d1-217d2-8895-cc88b6a5fb89" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 291, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "9f3a9835-3a5a-19bd6-8e96-24cbd46819a2" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 257, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "313e8ba0-a33e-65c9-888c-44570b7d2f8f" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 256, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "633fc524-3d0e-5dc3-861e-0f4c6208b89f" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 258, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "f833afe8-c61c-97fc-8c12-d8155bcede89" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 292, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "b03b64ea-50c0-1429-828f-fc071917058b" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 278, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "ea3efd87-898a-6136-8d07-f527c8b79e81" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 277, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "b23e5490-b46a-71d9-8b23-9bb9517353a6" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 279, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "a6355395-169c-3eb9-8ade-649ae50d77b2" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 293, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "77389db5-eaa4-2f63-8079-24f523f3c18d" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 285, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "97306087-e59d-769e-842c-5cd8b12ccb87" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 284, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "d130f385-d022-5f8f-80e0-1e1198cf68bb" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 286, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "4432cd3e-e203-18319-82f4-74af8752339a" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 294, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "143f0926-a95f-200d1-86de-fce4a72d2294" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 359, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "5b38ac4e-f3de-2ae2-8ab6-4c673a0eebb6" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 268, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "a837eb85-e874-2cb2-80c9-6e16b37333b7" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 272, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "793c5dca-8e92-17bd4-809e-e87e9a12c388" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 267, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "2939bba5-7857-19e21-8bd3-716ccb4a4898" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 276, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "e23a6be6-4ce3-5a18-84f8-5351f7d0d7bf" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 283, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "513aee59-a0e3-1659d-87c0-448d54a95180" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 261, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "2e30dba6-f549-207c-844f-37fd7d208abc" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 318, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 288, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 262, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "3c35a824-ef23-20b18-8ca6-09fa02ecce95" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 266, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "output": [ + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "6739c9d4-8375-205a5-8aef-7c7ce1eec3ba" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 266, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "uuid": "e539975d-4070-23c9-8c39-f04b7868b6ba" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "output": [ + { + "id": 42, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "533d846a-58c4-20045-8140-763c9c5b49ba" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 42, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 265, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "uuid": "0e3a1c7b-4539-2023f-88bf-86db048967bd" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 264, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "output": [ + { + "id": 57, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "cb3eadaa-ae94-6b3c-8308-6201140d82b8" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 57, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 264, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "uuid": "5831dc8d-9575-180e3-89e5-bd042b5248b7" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 388, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 388, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 388, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 388, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 388, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 388, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 388, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 388, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 388, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "output": [ + { + "id": 133, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "653e89aa-07f4-1b43-8136-7a0f312cd09e" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 133, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 388, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "uuid": "0b35735a-2ab7-7b5c-8334-700e3f86e1b7" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 331, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "output": [ + { + "id": 152, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "8d3efd1b-c19a-7f32-8ad5-fc9a03415f91" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 152, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 331, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "uuid": "9d3afa65-1d05-5db7-8c81-d0cf8a0e90b7" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 351, + "damage": 4, + "count": 9, + "nbt": "" + }, + { + "id": 351, + "damage": 4, + "count": 9, + "nbt": "" + }, + { + "id": 351, + "damage": 4, + "count": 9, + "nbt": "" + }, + { + "id": 351, + "damage": 4, + "count": 9, + "nbt": "" + }, + { + "id": 351, + "damage": 4, + "count": 9, + "nbt": "" + }, + { + "id": 351, + "damage": 4, + "count": 9, + "nbt": "" + }, + { + "id": 351, + "damage": 4, + "count": 9, + "nbt": "" + }, + { + "id": 351, + "damage": 4, + "count": 9, + "nbt": "" + }, + { + "id": 351, + "damage": 4, + "count": 9, + "nbt": "" + } + ], + "output": [ + { + "id": 22, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "163e3e34-795f-219b8-87bc-7bff10dab288" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 22, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 4, + "count": 9, + "nbt": "" + } + ], + "uuid": "473a4e5a-ae32-21ac2-8168-ee30955b6fb2" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 296, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "output": [ + { + "id": 170, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "5d314660-04b4-5f2d-8e0c-1a8c3011ba90" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 170, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 296, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "uuid": "b334e793-ea22-18563-88b8-11ed96a34c8d" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 263, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 263, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 263, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 263, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 263, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 263, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 263, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 263, + "damage": 0, + "count": 9, + "nbt": "" + }, + { + "id": 263, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "output": [ + { + "id": 173, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "c43e61a4-0052-21801-8052-da34c7bdd3b9" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 173, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 263, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "uuid": "f9358289-0944-9847-819c-88b64ef3939a" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "c43e0c92-9d09-0fa9-8967-34329fc67896" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 371, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "uuid": "f531916f-c2ec-16793-8181-0794f5926caf" + }, + { + "type": 0, + "input": [ + { + "id": 39, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 40, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 281, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 282, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "10315792-917f-21bdf-82d2-17b1b3b8f5b2" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 457, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 457, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 457, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 457, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 457, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 457, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 281, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 459, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "6135a4cf-703e-17fde-84e1-8e063641ff96" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 296, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 357, + "damage": 0, + "count": 8, + "nbt": "" + } + ], + "uuid": "26364317-3900-43c7-8ab9-e62a7c988e86" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 103, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "f73f1f68-0f2e-268a-8578-3481404c06ba" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 362, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "f73e5cf7-81ff-7e72-8e32-5a5fff2138b1" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 86, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 361, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "a3361d2d-aace-1948-81e4-d9604ddee289" + }, + { + "type": 0, + "input": [ + { + "id": 86, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 353, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 344, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 400, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "4835a3d9-a3e2-2dd9-8e20-1af8a6b450ac" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 375, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 353, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 39, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 376, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "853baf35-bd10-5317-8bca-97a22b8ebbb5" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 54, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "3739a955-e776-8a91-8902-452479549698" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 131, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 54, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 146, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "2a3c7903-c47e-1b27-8fdd-e1eb2759b3b1" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 61, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "af3752d4-3915-20039-8f23-8a5a8b6feba8" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 58, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "f139d3b7-4a33-9270-8f07-4c56e4a157ac" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 12, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 24, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "1237d0d4-d79c-208ae-8c1c-2f0e0c8a898a" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 12, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 179, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "0d3ba993-1b63-0227-8e6b-31af5f0d9a8b" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 24, + "damage": 2, + "count": 4, + "nbt": "" + } + ], + "uuid": "f53b7322-c879-6a58-82b4-12f926ecbf8d" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 179, + "damage": 2, + "count": 4, + "nbt": "" + } + ], + "uuid": "1a330f96-65f5-16efb-831d-b36b4dd99585" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 44, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 44, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 24, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "7d34375b-52c2-4c14-8f53-f96905cf8682" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 182, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 182, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 179, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "463e48b7-80a4-162d4-8860-b2f5442f9196" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 1, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 98, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "5539c0bb-5f6d-8a41-8bf0-2c44a5e48589" + }, + { + "type": 0, + "input": [ + { + "id": 98, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 106, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 98, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "ec3cbd06-edb1-4380-8836-8901e4e5189f" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 44, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 44, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 98, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "uuid": "d7381fd2-4939-6b98-8db3-1990e7423994" + }, + { + "type": 0, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 106, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 48, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "b6327b55-9835-2c47-827e-b104d66b7b95" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 101, + "damage": 0, + "count": 16, + "nbt": "" + } + ], + "uuid": "003f3a81-e205-17da3-874f-5cabd3c9d3b7" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 102, + "damage": 0, + "count": 16, + "nbt": "" + } + ], + "uuid": "7634a7e5-28b4-317d-81ab-23a71d31ac87" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 405, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 405, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 405, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 405, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "9a3e5181-e76e-12ed-8a37-8f3cc2133ca4" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 155, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "b03d2d83-1a70-7476-82f5-961879c515b7" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 44, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 44, + "damage": 6, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 155, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "c638da1b-2003-2447-88df-edce58267a85" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 155, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 155, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 155, + "damage": 2, + "count": 2, + "nbt": "" + } + ], + "uuid": "7b3dbc9b-d92d-215ae-8e7a-39e4d0712bb6" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 1, + "damage": 3, + "count": 2, + "nbt": "" + } + ], + "uuid": "8a3f0594-d0a0-8903-8ee4-82d22c055c87" + }, + { + "type": 0, + "input": [ + { + "id": 1, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 1, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "f53959e4-89af-20e1c-8b5a-f9fc697787b8" + }, + { + "type": 0, + "input": [ + { + "id": 1, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 1, + "damage": 5, + "count": 2, + "nbt": "" + } + ], + "uuid": "213fe490-a4ff-205cf-86c2-2d64c9e55f92" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 1, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 1, + "damage": 4, + "count": 4, + "nbt": "" + } + ], + "uuid": "d134e2e5-8b40-75a8-82a0-2dd661fad38b" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 1, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 1, + "damage": 2, + "count": 4, + "nbt": "" + } + ], + "uuid": "6e331222-764d-183fc-88cc-6b8cbf393690" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 1, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 1, + "damage": 6, + "count": 4, + "nbt": "" + } + ], + "uuid": "9f36bd4d-91e7-2464-8229-070b857b5884" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 399, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 49, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 49, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 49, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 138, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "4a356c07-2f44-9b0c-83c5-7b65eb07a394" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 298, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "673fcdd6-1602-00b8-86a7-e9ad7e40deb6" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 299, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "9837fa81-83c7-4503-8e19-7d390b115da4" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 300, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "2834de94-1362-29ec-8549-1e952ada33ae" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 301, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "683af90e-0dda-90f8-8f5d-2f10aa583397" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 306, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "df347afd-11f4-8914-8607-3a7899373eb4" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 307, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "4436e66d-382f-198e-88ba-d3f55e3f848a" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 308, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "fb337f74-48dd-184ca-8eac-b3446b027481" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 309, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "993860d1-6c28-190c4-83b4-4585eb3465ab" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 310, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "ad30d289-52dd-4996-85db-4c78131d5683" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 311, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "533c7935-a552-8b4e-8b4d-fb699e819686" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 312, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "1d3519b4-5366-3a41-85e0-58332d37d784" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 313, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "d035bfe6-35f7-197d1-85f2-7e2f840f0db5" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 314, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "e8347bf2-a079-855c-846e-335d170b2680" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 315, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "fa309dc1-c639-1a6f-8b9c-20d9bc6ca793" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 316, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "503c7b16-c6e5-208fa-85d6-29174a054ab4" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 317, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "b034008a-d274-47e3-8c28-9c12e3c9f7a3" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 15, + "count": 1, + "nbt": "" + } + ], + "uuid": "04364b84-cc80-167fd-80ac-9fad5970b5af" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 14, + "count": 1, + "nbt": "" + } + ], + "uuid": "533c9aca-8e8a-17643-8a20-f482b44c9899" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 13, + "count": 1, + "nbt": "" + } + ], + "uuid": "3d3731f7-524c-5e5c-8605-66fef3d8a8b5" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 12, + "count": 1, + "nbt": "" + } + ], + "uuid": "3537a3dd-3b82-4e0a-8c1b-7068c28aafa7" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 11, + "count": 1, + "nbt": "" + } + ], + "uuid": "453b1847-0674-161a6-89cf-4c06eca5108b" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 10, + "count": 1, + "nbt": "" + } + ], + "uuid": "b03d4d9e-3fad-1841-82d0-5db864495c87" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 9, + "count": 1, + "nbt": "" + } + ], + "uuid": "7f3beb95-ebca-3fc4-8bb9-f964002093b6" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 8, + "count": 1, + "nbt": "" + } + ], + "uuid": "f6376768-3b7f-199e7-8155-6ff64878f985" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 7, + "count": 1, + "nbt": "" + } + ], + "uuid": "bb38cd2d-b9e5-2347-86ef-cbfc5e1d45b5" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 9, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 6, + "count": 1, + "nbt": "" + } + ], + "uuid": "5539f558-6125-4b85-8150-faa50290d885" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "uuid": "f537010d-fa9d-19aaf-8ebf-294c3b05c1ae" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 4, + "count": 1, + "nbt": "" + } + ], + "uuid": "c33b1a65-f6dd-1d87-88a4-3278cac9c8a9" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "uuid": "3834f859-0abe-79fa-8940-a79414ee5eb7" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "uuid": "e73d1d2b-0d78-112a-8184-5fa4707dfda9" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "bd3e44e9-b305-2836-897f-d91b6da79582" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "8f3fcbaf-6d04-7b9b-8932-6fcb70884dbf" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 37, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 11, + "count": 1, + "nbt": "" + } + ], + "uuid": "da326b07-e40d-20b4e-8b39-451a5217e188" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 244, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 1, + "count": 2, + "nbt": "" + } + ], + "uuid": "fa38554a-658e-4eb4-82a9-e868504bacbc" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 38, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "88385a1c-ebeb-3610-8479-8f0358209c8e" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 352, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 15, + "count": 3, + "nbt": "" + } + ], + "uuid": "1a38a3ae-ad87-8ad3-8c50-b76554b0f394" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 9, + "count": 2, + "nbt": "" + } + ], + "uuid": "703a2385-a9ae-3cf7-8936-eb1e17281e82" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 11, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 14, + "count": 2, + "nbt": "" + } + ], + "uuid": "513dfe85-4e63-495e-80e2-49a78c2aa3a8" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 10, + "count": 2, + "nbt": "" + } + ], + "uuid": "d4307f35-69d8-5432-8a25-1e9f9c66b788" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 8, + "count": 2, + "nbt": "" + } + ], + "uuid": "f8349529-93a7-0b16-8cca-bdb8b33e34a2" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 7, + "count": 2, + "nbt": "" + } + ], + "uuid": "913c80af-800a-1ec1-8588-677f79cc899c" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 7, + "count": 3, + "nbt": "" + } + ], + "uuid": "953d5c5b-3545-098b-8fb7-ebe65664a3be" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 12, + "count": 2, + "nbt": "" + } + ], + "uuid": "a73dbbf3-413f-2014f-8957-1d7e3ed6db87" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 6, + "count": 2, + "nbt": "" + } + ], + "uuid": "733b2f8a-dcdf-4d25-870e-89376868c8b8" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 5, + "count": 2, + "nbt": "" + } + ], + "uuid": "c63f707b-85f7-230d-8db0-558c674744ae" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 9, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 13, + "count": 2, + "nbt": "" + } + ], + "uuid": "94377363-a663-48a7-88d7-b6c9fa45abb8" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 9, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 13, + "count": 3, + "nbt": "" + } + ], + "uuid": "693a7c99-2488-589b-8d54-fc093ae57982" + }, + { + "type": 0, + "input": [ + { + "id": 351, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 13, + "count": 4, + "nbt": "" + } + ], + "uuid": "bb3678e2-6644-5aa2-85d6-d7e739ac02ae" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 38, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 12, + "count": 1, + "nbt": "" + } + ], + "uuid": "ad3e942c-bfad-6e74-8b9b-0c20becfe3b3" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 38, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 13, + "count": 1, + "nbt": "" + } + ], + "uuid": "073187b9-5140-177e0-85b7-117023e007bf" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 38, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 7, + "count": 1, + "nbt": "" + } + ], + "uuid": "f03ff2cb-a6fc-32fe-8cf6-71684d5b77b4" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 38, + "damage": 4, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "f13322a7-2559-8574-8b2e-576c2c2604a9" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 38, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 14, + "count": 1, + "nbt": "" + } + ], + "uuid": "b430cf98-cf07-2c18-8ad2-a42c84473aad" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 38, + "damage": 6, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 7, + "count": 1, + "nbt": "" + } + ], + "uuid": "a53c125e-6eaf-5e97-8b38-df5e96762b9a" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 38, + "damage": 7, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 9, + "count": 1, + "nbt": "" + } + ], + "uuid": "633104b8-58ee-0179-8942-1c62b1267ba5" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 38, + "damage": 8, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 7, + "count": 1, + "nbt": "" + } + ], + "uuid": "fb3bab87-2dac-17510-8bd0-bbb1eaf085a1" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 175, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 11, + "count": 2, + "nbt": "" + } + ], + "uuid": "b73d8d72-dace-4ccf-84df-5d53e27a26bc" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 175, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 13, + "count": 2, + "nbt": "" + } + ], + "uuid": "18317779-61ec-81ca-80d4-881821f8e389" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 175, + "damage": 4, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 1, + "count": 2, + "nbt": "" + } + ], + "uuid": "793b2a0d-ebf1-7d49-8034-8c347f456abb" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 175, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 9, + "count": 2, + "nbt": "" + } + ], + "uuid": "7f3b58d0-815e-19326-8a54-66099ef559a1" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 457, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "0a3b4e25-59eb-164b-8eb3-b6faf41285bc" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 395, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "7632831a-fcbd-530a-89eb-5eb9c6ad3fb2" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 345, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 395, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "uuid": "013d970e-1463-289f-8592-ca8bf8c90196" + }, + { + "type": 4, + "uuid": "9d4d10ba-5597-9385-8443-e9a8b7efcca4" + }, + { + "type": 4, + "uuid": "ae40a14b-75b0-92d3-8ef6-568d86af8987" + }, + { + "type": 4, + "uuid": "4b43944b-9422-18dae-8793-2cbb99446786" + }, + { + "type": 4, + "uuid": "00000000-0000-0000-8100-000000000000" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 338, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 338, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 338, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 339, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "f937e5b9-c087-212c-8f2c-87e06376ebae" + }, + { + "type": 0, + "input": [ + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 339, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 340, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "0c32c667-5bec-9468-812e-28e237196183" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 139, + "damage": 0, + "count": 6, + "nbt": "" + } + ], + "uuid": "5739e606-feba-250b-838d-2ef4a2bec38d" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 48, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 48, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 48, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 48, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 48, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 48, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 139, + "damage": 1, + "count": 6, + "nbt": "" + } + ], + "uuid": "283ba987-a395-4565-8a7d-48d6debbefae" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 113, + "damage": 0, + "count": 6, + "nbt": "" + } + ], + "uuid": "01386bac-e083-174d7-87c1-6b6e147bb0be" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 85, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "143afa77-bf9b-0d4d-848d-d7df12563b83" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 85, + "damage": 1, + "count": 3, + "nbt": "" + } + ], + "uuid": "ac334f2e-d0fd-19bb8-81ef-88d3d9ae289a" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 85, + "damage": 2, + "count": 3, + "nbt": "" + } + ], + "uuid": "f33173f8-fe6f-181db-8c32-0422056700b5" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 85, + "damage": 3, + "count": 3, + "nbt": "" + } + ], + "uuid": "1d34da01-4493-06bc-8fc3-9e876137ecbf" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 85, + "damage": 4, + "count": 3, + "nbt": "" + } + ], + "uuid": "ca3ff9b6-e59c-18bca-819b-84cb14326898" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 85, + "damage": 5, + "count": 3, + "nbt": "" + } + ], + "uuid": "c838aaad-11de-8b22-87aa-10e222668ca4" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 107, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "0636f7e6-bae8-2067c-85ea-3e470a78c592" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 183, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "bd31a9d5-211a-8b2e-85b6-d123639d8d91" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 184, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "fd31d9fe-8717-376c-849c-7b5490e355af" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 185, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "0a3dc215-13ef-17948-8233-322d59ba2989" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 187, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "a437a184-c7d1-18c6d-86bb-6ee04440f197" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 186, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "3e38a6c8-f48a-4e76-811e-4c510b56a7b7" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 42, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 42, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 42, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 145, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "df37edec-9c33-1812b-8344-a1592dfb8394" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 340, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 340, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 340, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 47, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "923ba5e7-358e-432a-8fc2-c0788073449f" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 332, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 332, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 332, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 332, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 80, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "9c31bed1-b8fd-828f-8c32-f53fbfefebb7" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 80, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 80, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 80, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 78, + "damage": 0, + "count": 6, + "nbt": "" + } + ], + "uuid": "043dddad-eee6-5f0e-8964-d1c40346d98c" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 337, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 337, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 337, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 337, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 82, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "e63b33b3-0c10-18f7c-8f20-9b565aa35fbd" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 336, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 336, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 336, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 336, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "4e340160-8f6e-6b9d-86a3-9bfcdd55d996" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 348, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 348, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 348, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 348, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 89, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "903af4db-d097-17438-8047-cecbccf31da8" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "9031e39c-6766-210f6-89c5-eefd142298b0" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 289, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 289, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 289, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 289, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 12, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 289, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 46, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "693a8cc8-797f-88f5-8beb-f3ec53a6ce82" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 44, + "damage": 3, + "count": 6, + "nbt": "" + } + ], + "uuid": "cb3dca63-a275-199cf-8216-d15c3e5b7e9f" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 1, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 1, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 1, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 44, + "damage": 0, + "count": 6, + "nbt": "" + } + ], + "uuid": "f7352bfd-ce7a-20537-831f-0c2283fb0481" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 44, + "damage": 1, + "count": 6, + "nbt": "" + } + ], + "uuid": "1e32dc31-0714-16ff-8acf-d95bd4904ab2" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 182, + "damage": 0, + "count": 6, + "nbt": "" + } + ], + "uuid": "4f3769cb-4c7d-165e9-88a7-68af16b90099" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 158, + "damage": 0, + "count": 6, + "nbt": "" + } + ], + "uuid": "fe33ff85-a0c3-215a5-81f4-8c3e5f1d9f9a" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 158, + "damage": 1, + "count": 6, + "nbt": "" + } + ], + "uuid": "b63b5f66-445a-2032a-8cd2-2758e4bcd2a5" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 158, + "damage": 2, + "count": 6, + "nbt": "" + } + ], + "uuid": "81369280-31a9-5ce9-8d2d-b24051d05eaa" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 158, + "damage": 3, + "count": 6, + "nbt": "" + } + ], + "uuid": "513df8b7-f7f6-4648-836c-4fc7f1319688" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 158, + "damage": 4, + "count": 6, + "nbt": "" + } + ], + "uuid": "6b362120-c678-5071-8548-c70419dd70a6" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 158, + "damage": 5, + "count": 6, + "nbt": "" + } + ], + "uuid": "963f566d-aa54-867f-8abe-591afb445f90" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 44, + "damage": 4, + "count": 6, + "nbt": "" + } + ], + "uuid": "d532fb19-0480-18cd7-8801-b14b6a5c5391" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 98, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 98, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 98, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 44, + "damage": 5, + "count": 6, + "nbt": "" + } + ], + "uuid": "b538ad0b-2ead-1c81-8dcb-8ebb116baa97" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 44, + "damage": 7, + "count": 6, + "nbt": "" + } + ], + "uuid": "133eb226-2b28-5d64-850a-f713df8d159c" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 155, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 155, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 155, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 44, + "damage": 6, + "count": 6, + "nbt": "" + } + ], + "uuid": "363241a1-be27-79de-8b9f-891f4c8aa183" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 65, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "b23a2b62-c823-4746-8faf-d746bc51e889" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 324, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "aa3c82e0-546f-3a59-80a7-94335f32808d" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 427, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "9d30ce98-b096-0cd1-8bba-e62aa01620b9" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 428, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "943be750-dcad-3b92-8ed7-52346cfbb781" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 429, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "cb3e5089-6357-16a94-8b56-9084630eec82" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 430, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "2b3f8c25-097e-16a08-8665-9a888ea37d8e" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 431, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "7e30d0ec-43e7-16b26-8487-f23659d58c9a" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 96, + "damage": 0, + "count": 2, + "nbt": "" + } + ], + "uuid": "793b418f-2d0c-9742-86c7-87b7ff5d59a5" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 167, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "933220f5-0a5b-1ddb-8464-f9cd7330c4bd" + }, + { + "type": 1, + "width": 1, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 131, + "damage": 0, + "count": 2, + "nbt": "" + } + ], + "uuid": "eb3993c6-4966-7400-8458-79d519637c94" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 25, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "9b3e71d3-0aea-181d1-8952-88df8cc0998b" + }, + { + "type": 1, + "width": 2, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 330, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "113c116a-4bdd-2c82-8cae-e9aaad83818d" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 323, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "d73d638f-e1a0-8789-84f9-534adf6a59a6" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 325, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 325, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 325, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 353, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 344, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 353, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 354, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 325, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "52374f85-3b86-36dc-8f68-e019cb9097b0" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 338, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 353, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "9b3da15f-4585-4a90-8266-8c0aab0bfa99" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 391, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 396, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "443d3e0c-57a4-20a7f-8dce-5f16f42330a9" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 360, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 371, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 382, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "ff330fe8-d369-20ad1-8b69-9791441adebc" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 369, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 377, + "damage": 0, + "count": 2, + "nbt": "" + } + ], + "uuid": "2f3a5443-2ac8-4275-838b-996ad4f26db2" + }, + { + "type": 0, + "input": [ + { + "id": 377, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 378, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "4038d800-8fb4-0dab-8f73-c7dab6f8948a" + }, + { + "type": 0, + "input": [ + { + "id": 39, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 353, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 375, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 376, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "0e3f0d56-420c-973e-8fc5-fa05857bb1bd" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 17, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 5, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "9532e42b-9838-20985-89ae-bd2398f4319d" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 17, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 5, + "damage": 1, + "count": 4, + "nbt": "" + } + ], + "uuid": "9139df2a-0a58-3744-82b5-06027d8bbeb1" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 17, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 5, + "damage": 2, + "count": 4, + "nbt": "" + } + ], + "uuid": "20372dea-786e-36a4-881e-f299d194638d" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 17, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 5, + "damage": 3, + "count": 4, + "nbt": "" + } + ], + "uuid": "043daecf-7a02-2d1b-8a41-58a0ab0b8e86" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 162, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 5, + "damage": 4, + "count": 4, + "nbt": "" + } + ], + "uuid": "51356814-c55d-16217-8078-fd9c85fa06a1" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 162, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 5, + "damage": 5, + "count": 4, + "nbt": "" + } + ], + "uuid": "e23b51f8-1471-249a-830c-0cc03c4fc5a0" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 280, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "a932ee29-a8e7-193f0-83f2-910956f621bf" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 263, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 50, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "fe34ef95-93db-7f7c-8ad6-b84c832fb4ad" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 263, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 50, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "1f3bc964-9757-10c4-87d5-40a942620db4" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 281, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "063e8d8e-cd2f-1813a-8b3a-f5975b483fad" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 412, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 391, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 393, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 39, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 281, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 413, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "b033ffc0-06d0-20e83-8308-890873d88999" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 412, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 391, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 393, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 40, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 281, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 413, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "943703ef-e894-18cef-80d5-d4f2cb8f4eaf" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 374, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "f1368798-786f-16f90-8714-e4defce23ba9" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 336, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 336, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 336, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 390, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "98396687-d74d-191d0-8fb6-83fc1a14ed8a" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 66, + "damage": 0, + "count": 16, + "nbt": "" + } + ], + "uuid": "12396394-6e4d-2021d-8db2-227dbe363881" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 27, + "damage": 0, + "count": 6, + "nbt": "" + } + ], + "uuid": "0737b773-de9c-17de5-80e9-bc68fbd32b85" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 70, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 28, + "damage": 0, + "count": 6, + "nbt": "" + } + ], + "uuid": "d43bc98f-3c27-9b77-8727-11284a41b7a8" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 76, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 126, + "damage": 0, + "count": 6, + "nbt": "" + } + ], + "uuid": "ba3fd066-df68-17989-8078-e48bd6d606b5" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 328, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "d93d6d0c-a308-6160-8110-ad20464c358a" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 54, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 328, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 342, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "a631a8df-5cc0-16f0c-867c-fe0973800da4" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 410, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 328, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 408, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "fd3aa856-0e8c-6410-86cd-bb5e08969e89" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 380, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "1135e179-ed8f-724e-8649-90a465b56d99" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 369, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 379, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "843066a3-5804-1b06-89eb-35c98f9d5785" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 86, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 50, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 91, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "af317658-15e7-71a2-8a11-89b3481559b7" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 269, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 333, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "1d3ce00c-aee0-171bc-8133-7eb03689a380" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 269, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 333, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "e937f189-5321-4f0a-88e2-b4e9f8d30ca6" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 269, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 333, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "uuid": "95315ff2-63a2-1749c-8983-be469335d1b3" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 269, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 333, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "uuid": "7234157e-d2d2-5638-838e-df1897d12db1" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 269, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 333, + "damage": 4, + "count": 1, + "nbt": "" + } + ], + "uuid": "6138cd6b-3717-18383-80ce-fda2c11da08a" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 269, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 333, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "uuid": "96313eaa-7dbf-949b-8edd-bd4badcf9399" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 325, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "cc392ea3-49b3-2072f-8242-e7d91ac3d390" + }, + { + "type": 0, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 318, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 259, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "8f31b9ff-312e-966b-803d-b806836b31be" + }, + { + "type": 1, + "width": 3, + "height": 1, + "input": [ + { + "id": 296, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 296, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 297, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "303e3f31-56f5-16d39-8c8d-96874580a9ab" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 53, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "cb3c593b-7414-183f7-8927-62c0a2c75197" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 134, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "6c37bac0-a51f-0571-812a-ef430ae00a87" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 135, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "9a3c9adf-f23a-1778e-8859-fc870e96158a" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 136, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "9336af7f-b351-244e-8c5c-0b823adaf0b0" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 4, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 163, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "8b3603e7-a8dd-3bba-8615-20b20505449e" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 164, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "e33eee43-5d72-19754-8ec5-822870b386a9" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 67, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "bb3460d3-8997-7d02-8196-4b71e427dfb8" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 45, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 108, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "8d3bf0ad-9f02-797d-805c-02bf983189be" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 24, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 128, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "d33ed090-0fce-19ea6-8dac-00651c3e90b7" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 179, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 180, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "6c3891f7-ded9-16932-8b00-4838ac5d608c" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 98, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 98, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 98, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 98, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 98, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 98, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 109, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "553a8c32-b87a-3e9c-8837-5cad230a3aaa" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 155, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 155, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 155, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 155, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 155, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 155, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 156, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "6c3ff696-909b-19c6d-8f1e-cea94f1a7995" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 112, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 114, + "damage": 0, + "count": 4, + "nbt": "" + } + ], + "uuid": "103a725c-3e94-17bec-8496-40bdbf0cb4b8" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 346, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "dc386314-3166-214c7-8a91-ea1c18d67d9f" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 346, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 391, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 398, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "c330edca-ae67-3af4-8b3f-6303d79d909f" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 321, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "e83e7e85-288b-196c8-8614-62e523879081" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 260, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 322, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "fd316646-e200-95d8-87b6-6ca0f5750cb3" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 260, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 41, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 466, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "ff398c65-4396-218fb-8049-443fb0c781a3" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 69, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "633716df-5f35-4a20-885e-4a90c936e79c" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 76, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "be315a78-bbe0-16776-85ea-d9a764bd5a86" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 158, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 158, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 158, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 151, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "963e3c2c-4d85-2e30-8267-3bf4ece0208f" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 76, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 76, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 1, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 1, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 356, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "4931434b-34c3-17ffa-887c-198ac93d23a3" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 89, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 123, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "3c39b728-b5a9-7446-8139-bd28c2378dbe" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 347, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "c73bfdb9-a22c-78b2-8c3d-7b4fe32d3f87" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 345, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "883bd06b-7cd9-16b00-8632-3e7dd1fc0383" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 1, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 77, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "uuid": "59336f4a-3779-294d-88b9-3d07362348a0" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 143, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "uuid": "d23ffc8f-a186-208a4-8dec-3c2728df4198" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 1, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 70, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "df335d8a-ecb5-512e-81c5-2fc27328c392" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 72, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "f834a618-d53a-19957-8722-a64267adfa89" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 147, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "243ce0d7-1558-21919-8d60-0123e996cab3" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 148, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "e637105a-d5b3-3b3a-87eb-d99e36ae5dae" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 261, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 23, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "uuid": "a038022f-34ca-1875a-82d5-18bc657ba5ae" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 125, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "uuid": "8139a179-4b34-00b8-8bf4-46695d55cbaf" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 54, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + } + ], + "output": [ + { + "id": 410, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "e23cda6f-6daf-182f8-855c-94c7a20d5f8d" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 251, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "153fdde1-4894-6126-8f99-fabefc2407be" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 4, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 33, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "b3378bfc-9019-21ed-8f53-9e8eb9c8b693" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 33, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 29, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "6b3b2692-7ea7-18d0a-822c-c50c6b2ba5be" + }, + { + "type": 1, + "width": 3, + "height": 2, + "input": [ + { + "id": 35, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 5, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 355, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "1931d9a5-f889-20a42-84bd-401b3061aebd" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 340, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 49, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 49, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 49, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 49, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 116, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "d337074e-dc9c-196b3-8884-eb09340ed19a" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 415, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 415, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 415, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 415, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "2b3ee980-0df6-16955-85c0-e0dfb2777195" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 76, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 76, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 76, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": -1, + "count": 1, + "nbt": "" + }, + { + "id": 1, + "damage": -1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 404, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "e4300866-0a0c-5295-8d06-c0dea3c301b4" + }, + { + "type": 1, + "width": 1, + "height": 2, + "input": [ + { + "id": 46, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 328, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 407, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "5a3eadfb-bf29-20c54-8074-2284395a1bbd" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 280, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 389, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "7d39def0-7ea7-1634b-8ea6-819c51f87ebf" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "973cf759-eef3-0248-8b56-17a9b873a9a4" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 15, + "count": 8, + "nbt": "" + } + ], + "uuid": "6c3f1f6d-60bb-21bbb-8533-1b925084819c" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 1, + "count": 3, + "nbt": "" + } + ], + "uuid": "ae33e547-38ed-1b02-8479-ab14a5311da8" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 14, + "count": 8, + "nbt": "" + } + ], + "uuid": "d6352f46-c5b8-84d0-881d-afabfad97193" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 2, + "count": 3, + "nbt": "" + } + ], + "uuid": "6839aaff-8031-20fb5-822a-366047d668a0" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 2, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 13, + "count": 8, + "nbt": "" + } + ], + "uuid": "2c3dc75d-3e9b-204b4-85b7-b5028779349b" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 3, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 3, + "count": 3, + "nbt": "" + } + ], + "uuid": "fb30f9cd-a930-18fab-8e03-fb036e101d87" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 3, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 12, + "count": 8, + "nbt": "" + } + ], + "uuid": "c5394dd2-3381-217c3-8cf1-749610e7a08f" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 4, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 4, + "count": 3, + "nbt": "" + } + ], + "uuid": "bb3a6db2-d2bf-196ad-8486-8cdde46041ad" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 4, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 11, + "count": 8, + "nbt": "" + } + ], + "uuid": "683efe9b-92aa-38dc-8fd6-125ca33bee8a" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 5, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 5, + "count": 3, + "nbt": "" + } + ], + "uuid": "f533c922-a890-1836f-8560-d8875810bdb7" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 5, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 10, + "count": 8, + "nbt": "" + } + ], + "uuid": "3438e1df-747c-78d6-8191-7c2f94bf47aa" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 6, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 6, + "count": 3, + "nbt": "" + } + ], + "uuid": "ac3abd77-521e-3100-8dbf-dbae6fb051bd" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 6, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 9, + "count": 8, + "nbt": "" + } + ], + "uuid": "5c3313fd-d7af-712d-87e7-a359cd551ebe" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 7, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 7, + "count": 3, + "nbt": "" + } + ], + "uuid": "d134b88a-736d-43a2-8a65-daf2661571ae" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 7, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 8, + "count": 8, + "nbt": "" + } + ], + "uuid": "73327981-f62d-18ba-8690-7594e5abb49c" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 8, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 8, + "count": 3, + "nbt": "" + } + ], + "uuid": "f73f390a-dcda-1b0d-867c-281d1fe3fdb3" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 8, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 7, + "count": 8, + "nbt": "" + } + ], + "uuid": "f63c016f-64ab-18487-89ca-ed82305eed97" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 9, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 9, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 9, + "count": 3, + "nbt": "" + } + ], + "uuid": "553610c2-d087-3b1e-81ed-b1b3a46c67ab" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 9, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 6, + "count": 8, + "nbt": "" + } + ], + "uuid": "2d32da8f-d759-1ae1-8add-88dc0659dab1" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 10, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 10, + "count": 3, + "nbt": "" + } + ], + "uuid": "9934c19a-f75e-09ff-890f-e021f24e83ad" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 10, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 5, + "count": 8, + "nbt": "" + } + ], + "uuid": "8c34ebe7-5b9c-48fe-8c4b-a16c98881bb0" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 11, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 11, + "count": 3, + "nbt": "" + } + ], + "uuid": "663574e6-f090-5794-8d73-54a0df9b2cbc" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 11, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 4, + "count": 8, + "nbt": "" + } + ], + "uuid": "7f3422e3-bbe3-438b-8454-e6255b1e9384" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 12, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 12, + "count": 3, + "nbt": "" + } + ], + "uuid": "c23e93c1-bbb9-7296-833f-e1025ccd6c97" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 12, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 3, + "count": 8, + "nbt": "" + } + ], + "uuid": "4e348054-243b-1999e-86cf-87c046869e82" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 13, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 13, + "count": 3, + "nbt": "" + } + ], + "uuid": "3b3694fb-f238-188e8-8664-e9e6aa6d5ab3" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 13, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 2, + "count": 8, + "nbt": "" + } + ], + "uuid": "8a3975d2-245d-8b49-8331-3020e4a93e8f" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 14, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 14, + "count": 3, + "nbt": "" + } + ], + "uuid": "55381222-6bed-163ff-8b86-66b00d15a6bc" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 14, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 1, + "count": 8, + "nbt": "" + } + ], + "uuid": "0f361379-8b83-17712-8d14-4859d16cdc84" + }, + { + "type": 1, + "width": 2, + "height": 1, + "input": [ + { + "id": 35, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 35, + "damage": 15, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 171, + "damage": 15, + "count": 3, + "nbt": "" + } + ], + "uuid": "9b3eacf7-f43f-20928-875e-cf0240d7b9b9" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 15, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 159, + "damage": 0, + "count": 8, + "nbt": "" + } + ], + "uuid": "8d36ce45-6d4f-16939-81df-45ec5a7d7ea4" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 165, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "09341aef-c038-18add-8c46-474405aa65ab" + }, + { + "type": 1, + "width": 1, + "height": 1, + "input": [ + { + "id": 165, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 341, + "damage": 0, + "count": 9, + "nbt": "" + } + ], + "uuid": "923920d4-cdad-05dc-8bcb-1f12ba9e9290" + }, + { + "type": 0, + "input": [ + { + "id": 377, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 263, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 289, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 385, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "803424d6-e9ee-17609-8fe9-f79b838073a0" + }, + { + "type": 0, + "input": [ + { + "id": 377, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 263, + "damage": 1, + "count": 1, + "nbt": "" + }, + { + "id": 289, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 385, + "damage": 0, + "count": 3, + "nbt": "" + } + ], + "uuid": "833402ed-838d-67d8-8b76-caa2bd6335a8" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 341, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 287, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 420, + "damage": 0, + "count": 2, + "nbt": "" + } + ], + "uuid": "78365d60-6143-1e81-8d52-a532bf21fc9b" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 0, + "damage": 0, + "count": 0, + "nbt": "" + }, + { + "id": 334, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 416, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "7d3f642b-4a50-175af-8278-a18ecae09798" + }, + { + "type": 1, + "width": 2, + "height": 2, + "input": [ + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 168, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "ca382cbf-2440-4ff7-891e-c5bf0f7b6a8a" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 168, + "damage": 2, + "count": 1, + "nbt": "" + } + ], + "uuid": "e63e3357-ed35-167f1-894e-6b3d705d5998" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 351, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 168, + "damage": 1, + "count": 1, + "nbt": "" + } + ], + "uuid": "cd396373-9875-18c09-8438-d6b6e9e79ba2" + }, + { + "type": 1, + "width": 3, + "height": 3, + "input": [ + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 422, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 422, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 422, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 422, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 422, + "damage": 0, + "count": 1, + "nbt": "" + }, + { + "id": 409, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "output": [ + { + "id": 169, + "damage": 0, + "count": 1, + "nbt": "" + } + ], + "uuid": "fe3b5ffb-800a-11fa-8256-fefe92cee3b2" + }, + { + "type": 2, + "inputId": 4, + "output": { + "id": 1, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 12, + "output": { + "id": 20, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 14, + "output": { + "id": 266, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 15, + "output": { + "id": 265, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 16, + "output": { + "id": 263, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 17, + "output": { + "id": 263, + "damage": 1, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 21, + "output": { + "id": 351, + "damage": 4, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 56, + "output": { + "id": 264, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 73, + "output": { + "id": 331, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 81, + "output": { + "id": 351, + "damage": 2, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 82, + "output": { + "id": 172, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 87, + "output": { + "id": 405, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 129, + "output": { + "id": 388, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 153, + "output": { + "id": 406, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 162, + "output": { + "id": 263, + "damage": 1, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 319, + "output": { + "id": 320, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 337, + "output": { + "id": 336, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 349, + "output": { + "id": 350, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 363, + "output": { + "id": 364, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 365, + "output": { + "id": 366, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 392, + "output": { + "id": 393, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 411, + "output": { + "id": 412, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 423, + "output": { + "id": 424, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 2, + "inputId": 460, + "output": { + "id": 463, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 3, + "inputId": 19, + "inputDamage": 1, + "output": { + "id": 19, + "damage": 0, + "count": 1, + "nbt": "" + } + }, + { + "type": 3, + "inputId": 98, + "inputDamage": 0, + "output": { + "id": 98, + "damage": 2, + "count": 1, + "nbt": "" + } + } +] \ No newline at end of file diff --git a/src/devmine/server/tasks/AsyncPool.php b/src/devmine/server/tasks/AsyncPool.php index 2f4a71d..269407b 100644 --- a/src/devmine/server/tasks/AsyncPool.php +++ b/src/devmine/server/tasks/AsyncPool.php @@ -4,8 +4,8 @@ namespace devmine\server\tasks; -use devmine\server\events\Timings; -use devmine\Server; +use devmine\events\Timings; +use devmine\server\server; class AsyncPool{ diff --git a/src/devmine/server/tasks/AsyncTask.php b/src/devmine/server/tasks/AsyncTask.php index ba3d6d2..64dcb9b 100644 --- a/src/devmine/server/tasks/AsyncTask.php +++ b/src/devmine/server/tasks/AsyncTask.php @@ -4,12 +4,12 @@ namespace devmine\server\tasks; -use devmine\Server; +use devmine\server\server; /** * Class used to run async tasks in other threads. * - * WARNING: Do not call devmine-MP API methods, or save objects from/on other Threads!! + * WARNING: Do not call DevMine-MP API methods, or save objects from/on other Threads!! */ abstract class AsyncTask extends \Threaded implements \Collectable{ diff --git a/src/devmine/server/tasks/AsyncWorker.php b/src/devmine/server/tasks/AsyncWorker.php index 5fadf7b..2dc356e 100644 --- a/src/devmine/server/tasks/AsyncWorker.php +++ b/src/devmine/server/tasks/AsyncWorker.php @@ -4,7 +4,7 @@ namespace devmine\server\tasks; -use devmine\Worker; +use devmine\server\Worker; class AsyncWorker extends Worker{ diff --git a/src/devmine/server/tasks/CallbackTask.php b/src/devmine/server/tasks/CallbackTask.php index 5b6f5fd..a34522d 100644 --- a/src/devmine/server/tasks/CallbackTask.php +++ b/src/devmine/server/tasks/CallbackTask.php @@ -10,7 +10,11 @@ * * If you want to do a task in a Plugin, consider extending PluginTask to your needs * + * @deprecated + * Do NOT use this anymore, it was deprecated a long time ago at DevMine + * and will be removed at some stage in the future. */ + class CallbackTask extends Task{ /** @var callable */ diff --git a/src/devmine/server/tasks/DServerTask.php b/src/devmine/server/tasks/DServerTask.php index 2090990..d3c706b 100644 --- a/src/devmine/server/tasks/DServerTask.php +++ b/src/devmine/server/tasks/DServerTask.php @@ -5,7 +5,7 @@ */ namespace devmine\server\tasks; -use devmine\Server; +use devmine\server\server; class DServerTask extends AsyncTask{ diff --git a/src/devmine/server/tasks/PluginTask.php b/src/devmine/server/tasks/PluginTask.php index dd90584..7ecc1fa 100644 --- a/src/devmine/server/tasks/PluginTask.php +++ b/src/devmine/server/tasks/PluginTask.php @@ -4,7 +4,7 @@ namespace devmine\server\tasks; -use devmine\pluginfeatures\Plugin; +use devmine\consumer\plugin\Plugin; /** * Base class for plugin tasks. Allows the Server to delete them easily when needed diff --git a/src/devmine/server/tasks/SendUsageTask.php b/src/devmine/server/tasks/SendUsageTask.php index 9321581..efaeb29 100644 --- a/src/devmine/server/tasks/SendUsageTask.php +++ b/src/devmine/server/tasks/SendUsageTask.php @@ -5,8 +5,9 @@ namespace devmine\server\tasks; use devmine\server\network\protocol\Info; -use devmine\Server; +use devmine\server\server; use devmine\utilities\main\Utils; +use devmine\utilities\main\UUID; use devmine\utilities\main\VersionString; class SendUsageTask extends AsyncTask{ @@ -19,12 +20,12 @@ class SendUsageTask extends AsyncTask{ public $data; public function __construct(Server $server, $type, $playerList = []){ - $endpoint = "http://" . $server->getProperty("anonymous-statistics.host", "stats.devmine.net") . "/"; + $endpoint = "http://" . $server->getProperty("anonymous-statistics.host", "stats.pocketmine.net") . "/"; $data = []; $data["uniqueServerId"] = $server->getServerUniqueId(); $data["uniqueMachineId"] = Utils::getMachineUniqueId(); - $data["uniqueRequestId"] = Utils::dataToUUID($server->getServerUniqueId(), microtime(true)); + $data["uniqueRequestId"] = UUID::fromData($server->getServerUniqueId(), microtime(true)); switch($type){ case self::TYPE_OPEN: diff --git a/src/devmine/server/tasks/ServerScheduler.php b/src/devmine/server/tasks/ServerScheduler.php index fce6353..48d55ce 100644 --- a/src/devmine/server/tasks/ServerScheduler.php +++ b/src/devmine/server/tasks/ServerScheduler.php @@ -7,8 +7,8 @@ */ namespace devmine\server\tasks; -use devmine\pluginfeatures\Plugin; -use devmine\Server; +use devmine\consumer\plugin\Plugin; +use devmine\server\server; use devmine\utilities\main\MainLogger; use devmine\utilities\main\PluginException; use devmine\utilities\main\ReversePriorityQueue; diff --git a/src/devmine/server/tasks/TaskHandler.php b/src/devmine/server/tasks/TaskHandler.php index 6399eac..3052e09 100644 --- a/src/devmine/server/tasks/TaskHandler.php +++ b/src/devmine/server/tasks/TaskHandler.php @@ -4,7 +4,7 @@ namespace devmine\server\tasks; -use devmine\server\events\Timings; +use devmine\events\Timings; class TaskHandler{ @@ -26,7 +26,7 @@ class TaskHandler{ /** @var bool */ protected $cancelled = false; - /** @var \devmine\server\events\TimingsHandler */ + /** @var \devmine\events\TimingsHandler */ public $timings; public $timingName = null; diff --git a/src/devmine/server/updater/AutoUpdater.php b/src/devmine/server/updater/AutoUpdater.php deleted file mode 100644 index f7a50b2..0000000 --- a/src/devmine/server/updater/AutoUpdater.php +++ /dev/null @@ -1,132 +0,0 @@ -server = $server; - $this->endpoint = "http://$endpoint/api/"; - - /*if($server->getProperty("auto-updater.enabled", true)){ - $this->check(); - if($this->hasUpdate()){ - if($this->server->getProperty("auto-updater.on-update.warn-console", true)){ - $this->showConsoleUpdate(); - } - }elseif($this->server->getProperty("auto-updater.preferred-channel", true)){ - $version = new VersionString(); - if(!$version->isDev() and $this->getChannel() !== "stable"){ - $this->showChannelSuggestionStable(); - }elseif($version->isDev() and $this->getChannel() === "stable"){ - $this->showChannelSuggestionBeta(); - } - } - }*/ - } - - protected function check(){ - $response = Utils::getURL($this->endpoint . "?channel=" . $this->getChannel(), 4); - $response = json_decode($response, true); - if(!is_array($response)){ - return; - } - - $this->updateInfo = [ - "version" => $response["version"], - "api_version" => $response["api_version"], - "build" => $response["build"], - "date" => $response["date"], - "details_url" => isset($response["details_url"]) ? $response["details_url"] : null, - "download_url" => $response["download_url"] - ]; - - $this->checkUpdate(); - } - - /** - * @return bool - */ - public function hasUpdate(){ - return $this->hasUpdate; - } - - public function showConsoleUpdate(){ - $logger = $this->server->getLogger(); - $newVersion = new VersionString($this->updateInfo["version"]); - $logger->warning("----- devmine-MP Auto Updater -----"); - $logger->warning("Your version of devmine-MP is out of date. Version " . $newVersion->get(false) . " (build #" . $newVersion->getBuild() . ") was released on " . date("D M j h:i:s Y", $this->updateInfo["date"])); - if($this->updateInfo["details_url"] !== null){ - $logger->warning("Details: " . $this->updateInfo["details_url"]); - } - $logger->warning("Download: " . $this->updateInfo["download_url"]); - $logger->warning("----- -------------------------- -----"); - } - - public function showPlayerUpdate(Player $player){ - $player->sendMessage(TextFormat::DARK_PURPLE . "The version of devmine-MP that this server is running is out of date. Please consider updating to the latest version."); - $player->sendMessage(TextFormat::DARK_PURPLE . "Check the console for more details."); - } - - protected function showChannelSuggestionStable(){ - $logger = $this->server->getLogger(); - $logger->info("----- devmine-MP Auto Updater -----"); - $logger->info("It appears you're running a Stable build, when you've specified that you prefer to run " . ucfirst($this->getChannel()) . " builds."); - $logger->info("If you would like to be kept informed about new Stable builds only, it is recommended that you change 'preferred-channel' in your devmine.yml to 'stable'."); - $logger->info("----- -------------------------- -----"); - } - - protected function showChannelSuggestionBeta(){ - $logger = $this->server->getLogger(); - $logger->info("----- devmine-MP Auto Updater -----"); - $logger->info("It appears you're running a Beta build, when you've specified that you prefer to run Stable builds."); - $logger->info("If you would like to be kept informed about new Beta or Development builds, it is recommended that you change 'preferred-channel' in your devmine.yml to 'beta' or 'development'."); - $logger->info("----- -------------------------- -----"); - } - - public function getUpdateInfo(){ - return $this->updateInfo; - } - - public function doCheck(){ - $this->check(); - } - - protected function checkUpdate(){ - if($this->updateInfo === null){ - return; - } - $currentVersion = new VersionString($this->server->getdevmineVersion()); - $newVersion = new VersionString($this->updateInfo["version"]); - - if($currentVersion->compare($newVersion) > 0 and ($currentVersion->get() !== $newVersion->get() or $currentVersion->getBuild() > 0)){ - $this->hasUpdate = true; - }else{ - $this->hasUpdate = false; - } - - } - - public function getChannel(){ - $channel = strtolower($this->server->getProperty("auto-updater.preferred-channel", "stable")); - if($channel !== "stable" and $channel !== "beta" and $channel !== "development"){ - $channel = "stable"; - } - - return $channel; - } -} \ No newline at end of file diff --git a/src/devmine/utilities/installer/Installer.php b/src/devmine/utilities/installer/Installer.php index d4fe755..66fc40b 100644 --- a/src/devmine/utilities/installer/Installer.php +++ b/src/devmine/utilities/installer/Installer.php @@ -19,11 +19,20 @@ class Installer{ const DEFAULT_GAMEMODE = 0; const DEFAULT_LEVEL_NAME = "world"; const DEFAULT_LEVEL_TYPE = "DEFAULT"; + + const LEVEL_TYPES = [ + "DEFAULT", + "FLAT", + "NORMAL", + "NORMAL2", + "HELL", //nether type, in case anyone wants to generate a blue-skies nether, which actually does look pretty awesome + "VOID" + ]; private $defaultLang; public function __construct(){ - echo "[*] devmine set-up wizard\n"; + echo "[*] DevMine set-up wizard\n"; echo "[*] Please select a language:\n"; foreach(InstallerLang::$languages as $short => $native){ echo " $native => $short\n"; @@ -43,7 +52,7 @@ public function __construct(){ echo "[*] " . $this->lang->language_has_been_selected . "\n"; if(!$this->showLicense()){ - @\devmine\kill(getmypid()); + @\DevMine\kill(getmypid()); exit(-1); } @@ -66,7 +75,7 @@ public function getDefaultLang(){ } private function showLicense(){ - echo $this->lang->welcome_to_devmine . "\n"; + echo $this->lang->welcome_to_DevMine . "\n"; echo <<lang->name_your_server . " (" . self::DEFAULT_NAME . "): "; $server_name = $this->getInput(self::DEFAULT_NAME); $config->set("server-name", $server_name); - $config->set("motd", $server_name); //MOTD is now used as server name + $config->set("motd", $server_name); echo "[*] " . $this->lang->port_warning . "\n"; do{ echo "[?] " . $this->lang->server_port . " (" . self::DEFAULT_PORT . "): "; @@ -109,21 +118,22 @@ private function generateBaseConfig(){ }while($port <= 0 or $port > 65535); $config->set("server-port", $port); + echo "[*] " . $this->lang->online_mode_info . "\n"; + echo "[?] " . $this->lang->online_mode . " (y/N): "; + $config->set("online-mode", strtolower($this->getInput("y")) == "y"); + echo "[?] " . $this->lang->level_name . " (" . self::DEFAULT_LEVEL_NAME . "): "; $config->set("level-name", $this->getInput(self::DEFAULT_LEVEL_NAME)); do{ echo "[?] " . $this->lang->level_type . " (" . self::DEFAULT_LEVEL_TYPE . "): "; $type = strtoupper((string) $this->getInput(self::DEFAULT_LEVEL_TYPE)); - if($type != "FLAT" and $type != "DEFAULT"){ + if(!in_array($type, self::LEVEL_TYPES)){ echo "[!] " . $this->lang->invalid_level_type . "\n"; } - }while($type != "FLAT" and $type != "DEFAULT"); + }while(!in_array($type, self::LEVEL_TYPES)); $config->set("level-type", $type); - - /*echo "[*] " . $this->lang->ram_warning . "\n"; - echo "[?] " . $this->lang->server_ram . " (" . self::DEFAULT_MEMORY . "): "; - $config->set("memory-limit", ((int) $this->getInput(self::DEFAULT_MEMORY)) . "M");*/ + echo "[*] " . $this->lang->gamemode_info . "\n"; do{ echo "[?] " . $this->lang->default_gamemode . ": (" . self::DEFAULT_GAMEMODE . "): "; @@ -156,13 +166,13 @@ private function generateUserFiles(){ if($op === ""){ echo "[!] " . $this->lang->op_warning . "\n"; }else{ - $ops = new Config(\devmine\DATA . "ops.txt", Config::ENUM); + $ops = new Config(\DevMine\DATA . "ops.txt", Config::ENUM); $ops->set($op, true); $ops->save(); } echo "[*] " . $this->lang->whitelist_info . "\n"; echo "[?] " . $this->lang->whitelist_enable . " (y/N): "; - $config = new Config(\devmine\DATA . "server.properties", Config::PROPERTIES); + $config = new Config(\DevMine\DATA . "server.properties", Config::PROPERTIES); if(strtolower($this->getInput("n")) === "y"){ echo "[!] " . $this->lang->whitelist_warning . "\n"; $config->set("white-list", true); @@ -173,7 +183,7 @@ private function generateUserFiles(){ } private function networkFunctions(){ - $config = new Config(\devmine\DATA . "server.properties", Config::PROPERTIES); + $config = new Config(\DevMine\DATA . "server.properties", Config::PROPERTIES); echo "[!] " . $this->lang->query_warning1 . "\n"; echo "[!] " . $this->lang->query_warning2 . "\n"; echo "[?] " . $this->lang->query_disable . " (y/N): "; @@ -187,20 +197,13 @@ private function networkFunctions(){ echo "[?] " . $this->lang->rcon_enable . " (y/N): "; if(strtolower($this->getInput("n")) === "y"){ $config->set("enable-rcon", true); - $password = substr(base64_encode(@Utils::getRandomBytes(20, false)), 3, 10); + $password = substr(base64_encode(random_bytes(20)), 3, 10); $config->set("rcon.password", $password); echo "[*] " . $this->lang->rcon_password . ": " . $password . "\n"; }else{ $config->set("enable-rcon", false); } - /*echo "[*] " . $this->lang->usage_info . "\n"; - echo "[?] " . $this->lang->usage_disable . " (y/N): "; - if(strtolower($this->getInput("n")) === "y"){ - $config->set("send-usage", false); - }else{ - $config->set("send-usage", true); - }*/ $config->save(); @@ -216,8 +219,8 @@ private function networkFunctions(){ private function endWizard(){ echo "[*] " . $this->lang->you_have_finished . "\n"; - echo "[*] " . $this->lang->devmine_plugins . "\n"; - echo "[*] " . $this->lang->devmine_will_start . "\n\n\n"; + echo "[*] " . $this->lang->DevMine_plugins . "\n"; + echo "[*] " . $this->lang->DevMine_will_start . "\n\n\n"; sleep(4); } diff --git a/src/devmine/utilities/installer/InstallerLang.php b/src/devmine/utilities/installer/InstallerLang.php index 00079e6..4fbacd8 100644 --- a/src/devmine/utilities/installer/InstallerLang.php +++ b/src/devmine/utilities/installer/InstallerLang.php @@ -11,19 +11,22 @@ class InstallerLang{ "chs" => "简体中文", "zho" => "繁體中文", "jpn" => "日本語", - "rus" => "Русский" + "rus" => "Русский", + "ita" => "Italiano", + "kor" => "한국어", + "deu" => "Deutsch" ]; private $texts = []; private $lang; private $langfile; public function __construct($lang = ""){ - if(file_exists(\devmine\PATH . "src/devmine/languages/installer/" . $lang . ".ini")){ + if(file_exists(\DevMine\PATH . "src/DevMine/lang/Installer/" . $lang . ".ini")){ $this->lang = $lang; - $this->langfile = \devmine\PATH . "src/devmine/languages/installer/" . $lang . ".ini"; + $this->langfile = \DevMine\PATH . "src/DevMine/lang/Installer/" . $lang . ".ini"; }else{ $files = []; - foreach(new \DirectoryIterator(\devmine\PATH . "src/devmine/languages/installer/") as $file){ + foreach(new \DirectoryIterator(\DevMine\PATH . "src/DevMine/lang/Installer/") as $file){ if($file->getExtension() === "ini" and substr($file->getFilename(), 0, 2) === $lang){ $files[$file->getFilename()] = $file->getSize(); } @@ -35,14 +38,14 @@ public function __construct($lang = ""){ $l = key($files); $l = substr($l, 0, -4); $this->lang = isset(self::$languages[$l]) ? $l : $lang; - $this->langfile = \devmine\PATH . "src/devmine/languages/installer/" . $l . ".ini"; + $this->langfile = \DevMine\PATH . "src/DevMine/lang/Installer/" . $l . ".ini"; }else{ $this->lang = "en"; - $this->langfile = \devmine\PATH . "src/devmine/languages/installer/eng.ini"; + $this->langfile = \DevMine\PATH . "src/DevMine/lang/Installer/eng.ini"; } } - $this->loadLang(\devmine\PATH . "src/devmine/languages/installer/eng.ini", "eng"); + $this->loadLang(\DevMine\PATH . "src/DevMine/lang/Installer/eng.ini", "eng"); if($this->lang !== "en"){ $this->loadLang($this->langfile, $this->lang); } diff --git a/src/devmine/utilities/languages/BaseLang.php b/src/devmine/utilities/languages/BaseLang.php index f64de26..ed5b709 100644 --- a/src/devmine/utilities/languages/BaseLang.php +++ b/src/devmine/utilities/languages/BaseLang.php @@ -4,8 +4,8 @@ namespace devmine\utilities\languages; -use devmine\server\events\TextContainer; -use devmine\server\events\TranslationContainer; +use devmine\events\TextContainer; +use devmine\events\TranslationContainer; class BaseLang{ @@ -21,7 +21,7 @@ public function __construct($lang, $path = null, $fallback = self::FALLBACK_LANG $this->langName = strtolower($lang); if($path === null){ - $path = \devmine\PATH . "src/devmine/languages/locale/"; + $path = \DevMine\PATH . "src/DevMine/lang/locale/"; } $this->loadLang($path . $this->langName . ".ini", $this->lang); @@ -75,7 +75,7 @@ public function translateString($str, array $params = [], $onlyPrefix = null){ $baseText = str_replace("{%$i}", $this->parseTranslation((string) $p), $baseText, $onlyPrefix); } - return $baseText; + return str_replace("%0", "", $baseText); //fixes a client bug where %0 in translation will cause freeze } public function translate(TextContainer $c){ diff --git a/src/devmine/utilities/languages/Installer/chs.ini b/src/devmine/utilities/languages/Installer/chs.ini index 3547bbc..02cc023 100644 --- a/src/devmine/utilities/languages/Installer/chs.ini +++ b/src/devmine/utilities/languages/Installer/chs.ini @@ -1,9 +1,9 @@ language_has_been_selected = 您现在选择了简体中文. skip_installer = 您想跳过安装向导吗? -welcome_to_devmine = 欢迎来到devmine!\n在开始使用您的新服务器之前,您需要接受以下协议\ndevmine使用了LGPL协议,\n你可以在这个文件夹中找到LICENCE文件。 +welcome_to_DevMine = 欢迎来到DevMine!\n在开始使用您的新服务器之前,您需要接受以下协议\nDevMine使用了LGPL协议,\n你可以在这个文件夹中找到LICENCE文件。 accept_license = 您接受协议内容吗? -you_have_to_accept_the_license = 您要接受LGPL协议才可继续使用devmine +you_have_to_accept_the_license = 您要接受LGPL协议才可继续使用DevMine setting_up_server_now = 你现在要开始设置您的服务器了。 default_values_info = 如果您希望使用默认设置,请直接按下回车键。 @@ -13,7 +13,9 @@ name_your_server = 给你的服务器起个名字吧: port_warning = 如果这是您第一次设置服务器,尽量不要改变端口。 server_port = 设置你的服务器端口: invalid_port = 服务器端口不正确。 -ram_warning = 设置devmine可用的最大内存. +online_mode_info = 联机模式下, 服务器将强制玩家需要 Xbox 登录\n当联机时, 建议让服务器开启此功能 +online_mode = 您想启用联机模式? +ram_warning = 设置DevMine可用的最大内存. server_ram = 分配给服务器的内存(RAM)(MB): gamemode_info = 选择模式: (0)生存模式 或 (1)创造模式 default_gamemode = 默认游戏模式 @@ -38,13 +40,12 @@ query_disable = 您希望禁用Query请求吗? rcon_info = RCON可用来远程连接到服务器控制台(需要密码). rcon_enable = 您希望启用RCON吗? rcon_password = RCON密码 (您也以后更改它) : -usage_info = 匿名数据让我们可以获得全球的devmine-MP和它的插件的统计信息. 您可以在 stats.devmine.net 查看统计信息. - +usage_info = 匿名数据让我们可以获得全球的DevMine-MP和它的插件的统计信息. 您可以在 stats.pocketmine.net 查看统计信息. usage_disable = 您希望禁用匿名数据吗? ip_get = 获得你的外部IP和内部IP ip_warning = 您的外部IP是 {{EXTERNAL_IP}} . 您可能需要端口转发到您的内网IP {{INTERNAL_IP}} . ip_confirm = 请确认,如没有问题请按下\"回车\"键 you_have_finished = 您已经成功完成了服务器设置向导. -devmine_will_start = 现在,尽情使用吧~. 输入 \"/help\" 来看所有可用的命令. -devmine_plugins = 请查看插件源来添加新的功能, 迷你游戏或者对服务器的高级保护. +DevMine_will_start = 现在,尽情使用吧~. 输入 \"/help\" 来看所有可用的命令. +DevMine_plugins = 请查看插件源来添加新的功能, 迷你游戏或者对服务器的高级保护. diff --git a/src/devmine/utilities/languages/Installer/deu.ini b/src/devmine/utilities/languages/Installer/deu.ini new file mode 100644 index 0000000..7f11855 --- /dev/null +++ b/src/devmine/utilities/languages/Installer/deu.ini @@ -0,0 +1,51 @@ +language_has_been_selected = Deutsch wurde erfolgreich als Sprache ausgewählt. +skip_installer = Möchtest du den Einrichtungsassistenten überspringen? + +welcome_to_DevMine = Willkommen bei DevMine!\nBevor es mit der Einrichtung deines neuen Servers losgehen kann, musst du die Lizenz akzeptieren.\nDevMine ist unter der GPL Lizenz Version 3 und neuer lizenziert, welche du in der Datei LICENCE nachlesen kannst. +accept_license = Akzeptierst du die Lizenz? +you_have_to_accept_the_license = Um DevMine weiterverwenden zu können, musst du der Lizenz zustimmen. + +setting_up_server_now = Du bist nun dabei, deinen Server einzurichten. +default_values_info = Drücke einfach Enter, um die Standardwerte zu übernehmen. +server_properties = Du kannst sie auch später in der Datei server.properties ändern. + +name_your_server = Gib deinem Server einen Namen. +port_warning = Ändere nicht den Wert für den Standart-Port, falls dies dein erster Server ist. +server_port = Server-Port +invalid_port = Ungültiger Server-Port +online_mode_info = Im Online-Modus wird der Spieler gezwungen, sich mit seinem XBOX-Account zu authentifizieren.\nEs wird die Aktivierung des Online-Modus empfohlen, falls der Server für externe Spieler geöffnet ist. +online_mode = Möchtest du den Online-Modus aktivieren? +ram_warning = Der RAM ist die maximale Menge an Arbeitsspeicher, welchen DevMine verwenden darf. Es wird ein Wert von 128-256 MB empfohlen. +server_ram = Server RAM in MB +gamemode_info = Wähle zwischen Kreativmodus (1) oder Überlebensmodus (0) +default_gamemode = Standard Spielmodus +max_players = Max. Online-Spieler +spawn_protection_info = Der Spawnschutz (spawn protection) verhindert das Setzen oder Abbauen von Blöcken im Spawn-Bereich, außer für OPs. +spawn_protection = Spawnschutz aktivieren? +level_name = Bestimme den Namen der Welt +level_type = Lege fest, welchen Welttyp der Server verwenden soll +invalid_level_type = Ungültiger Welttyp +announce_player_achievements = Sollen die Spieler benachrichtigt werden, wenn ein Erfolg erzielt wird? + +op_info = Ein OP ist ein Spieler, der Admin ist. OPs können mehr Befehle ausführen als normale Spieler. +op_who = OP Spielername (z.B. dein Spielername) +op_warning = Du kannst später weitere OP Spieler hinzufügen, indem du eingibst /op +whitelist_info = Mit Aktivierung der Whitelist dürfen nur noch Spieler joinen, die darin enthalten sind. +whitelist_enable = Möchtest du die Whitelist aktivieren? +whitelist_warning = Du musst die Spieler dann noch zur Whitelist hinzufügen + +query_warning1 = Query ist ein Protokoll, das von verschiedenen Tools verwendet wird, um Informationen zu deinem Servers und die darauf angemeldeten Spieler abzufragen. +query_warning2 = Wenn du es deaktivierst, kannst du keine Serverlisten nutzen. +query_disable = Möchtest du Query deaktivieren? +rcon_info = RCON ist ein Protokoll, über welches man sich aus der Ferne mit einem Passwort zur Serverkonsole verbinden kann. +rcon_enable = Möchtest du RCON aktivieren? +rcon_password = RCON Passwort (du kannst es später ändern) +usage_info = Die anonymen Nutzungsdaten ermöglichen uns, eine globale Statistik für DevMine-MP und dessen Plugins zu generieren. Du kannst sie dir auf stats.pocketmine.net ansehen. +usage_disable = Möchtest du die anonymen Nutzungsdaten deaktivieren? +ip_get = Deine interne und externe IP-Adresse wird ermittelt +ip_warning = Deine externe IP ist {{EXTERNAL_IP}}. Möglicherweise muss eine Port-Weiterleitung zu deiner internen IP {{INTERNAL_IP}} eingerichtet werden. +ip_confirm = Stelle sicher, dass du das geprüft hast. Falls du eine Weiterleitung benötigst, aber nicht einrichtest, wird kein externer Spieler joinen können. [Drücke Enter] + +you_have_finished = Du hast den Einrichtungsassistenten nun erfolgreich abgeschlossen. +DevMine_will_start = DevMine wird jetzt gestartet. Gib /help ein, um dir eine Liste verfügbarer Befehle anzeigen zu lassen. +DevMine_plugins = Prüfe auch das Plugin-Repository im Web, um deinem Server weitere Features, Minigames oder erweiterten Schutz hinzuzufügen. diff --git a/src/devmine/utilities/languages/Installer/eng.ini b/src/devmine/utilities/languages/Installer/eng.ini index 3514bfc..a8d6230 100644 --- a/src/devmine/utilities/languages/Installer/eng.ini +++ b/src/devmine/utilities/languages/Installer/eng.ini @@ -1,9 +1,9 @@ language_has_been_selected = English has been correctly selected. skip_installer = Do you want to skip the set-up wizard? -welcome_to_devmine = Welcome to devmine!\nBefore starting setting up your new server you have to accept the license.\ndevmine is licensed under the LGPL License,\nthat you can read opening the LICENSE file on this folder. +welcome_to_DevMine = Welcome to DevMine!\nBefore starting setting up your new server you have to accept the license.\nT is licensed under the LGPL License,\nthat you can read opening the LICENSE file on this folder. accept_license = Do you accept the License? -you_have_to_accept_the_license = You have to accept the LGPL license to continue using devmine +you_have_to_accept_the_license = You have to accept the LGPL license to continue using DevMine setting_up_server_now = You are going to set up your server now. default_values_info = If you don't want to change the default value, just press Enter. @@ -13,10 +13,10 @@ name_your_server = Give a name to your server port_warning = Do not change the default port value if this is your first server. server_port = Server port invalid_port = Invalid server port -ram_warning = The RAM is the maximum amount of memory devmine will use. A value of 128-256 MB is recommended -server_ram = Server RAM in MB -gamemode_info = Choose between Creative (1) or Survival (0) -default_gamemode = Default Game mode +online_mode_info = In online mode, the server will force the user to login via XBOX.\nEnabling online mode is recommended if the server is opened to external players. +online_mode = Do you want to enable online mode? +gamemode_info = Choose between Creative (1), Survival (0), or Spectator (3) +default_gamemode = Default gamemode max_players = Max. online players spawn_protection_info = The spawn protection disallows placing/breaking blocks in the spawn zone except for OPs spawn_protection = Enable spawn protection? @@ -38,12 +38,11 @@ query_disable = Do you want to disable Query? rcon_info = RCON is a protocol to remote connect with the server console using a password. rcon_enable = Do you want to enable RCON? rcon_password = RCON password (you can change it later) -usage_info = The anonymous usage data allows us to calculate global statistics for devmine-MP and its plugins. You can view them on stats.devmine.net +usage_info = The anonymous usage data allows us to calculate global statistics for DevMine-MP and its plugins. You can view them on stats.pocketmine.net usage_disable = Do you want to disable the anonymous usage? ip_get = Getting your external IP and internal IP ip_warning = Your external IP is {{EXTERNAL_IP}}. You may have to port-forward to your internal IP {{INTERNAL_IP}} ip_confirm = Be sure to check it, if you have to forward and you skip that, no external players will be able to join. [Press Enter] you_have_finished = You have finished the set-up wizard correctly -devmine_will_start = devmine will now start. Type /help to view the list of available commands. -devmine_plugins = Check the Plugin Repository to add new features, minigames, or advanced protection to your server +DevMine_will_start = DevMine will now start. Type /help to view the list of available commands. diff --git a/src/devmine/utilities/languages/Installer/fra.ini b/src/devmine/utilities/languages/Installer/fra.ini index e3a961b..c95c67a 100644 --- a/src/devmine/utilities/languages/Installer/fra.ini +++ b/src/devmine/utilities/languages/Installer/fra.ini @@ -1,9 +1,9 @@ language_has_been_selected = Français a été correctement sélectionné. skip_installer = Voulez-vous passer l'assistant d'installation? -welcome_to_devmine = Bienvenue sur devmine!\nAvant de commencer à paramétrer votre nouveau serveur, vous devez accepter la license d'utilisation.\ndevmine est sous licence LGPL,\nvous pouvez la lire en ouvrant le fichier LICENSE dans ce dossier. +welcome_to_DevMine = Bienvenue sur DevMine!\nAvant de commencer à paramétrer votre nouveau serveur, vous devez accepter la license d'utilisation.\nDevMine est sous licence LGPL,\nvous pouvez la lire en ouvrant le fichier LICENSE dans ce dossier. accept_license = Acceptez-vous la Licence? -you_have_to_accept_the_license = Vous devez accepter la licence LGPL pour continuer à utiliser devmine +you_have_to_accept_the_license = Vous devez accepter la licence LGPL pour continuer à utiliser DevMine setting_up_server_now = Vous êtes maintenant prêt à paramétrer votre serveur. default_values_info = Si vous ne voulez pas changer la valeur par défaut, appuyez sur entrée. @@ -13,7 +13,7 @@ name_your_server = Donnez un nom à votre serveur port_warning = Ne changez pas la valeur par défaut du port si c'est votre premier serveur. server_port = Port du serveur invalid_port = Port du serveur invalide -ram_warning = La RAM est au maximum de sa capacité par rapport à la mémoire utilisée par devmine-MP. Une valeur de 128-256 MB est recommandée +ram_warning = La RAM est au maximum de sa capacité par rapport à la mémoire utilisée par DevMine-MP. Une valeur de 128-256 MB est recommandée server_ram = RAM du serveur en MB gamemode_info = Choisir entre Créatif (1) ou Survie (0) default_gamemode = Mode de jeu par défaut @@ -38,12 +38,12 @@ query_disable = Voulez-vous désactiver Query? rcon_info = RCON est un protocole pour se connecter à distance à la console du serveur par un mot de passe. rcon_enable = Voulez-vous activer RCON? rcon_password = Mot de passe RCON (vous pouvez le changer plus tard) -usage_info = Les données d'utilisation anonyme vous permettent de calculer les statistiques globales de devmine-MP et ses plugins. Vous pouvez les voir sur stats.devmine.net +usage_info = Les données d'utilisation anonyme vous permettent de calculer les statistiques globales de DevMine-MP et ses plugins. Vous pouvez les voir sur stats.pocketmine.net usage_disable = Voulez-vous désactiver l'utilisation anonyme? ip_get = Obtention de votre IP externe et IP interne ip_warning = Votre IP externe est {{EXTERNAL_IP}}. Vous pourriez avoir à transmettre au port votre IP interne {{INTERNAL_IP}} ip_confirm = Vérifiez-le bien, si vous avancez et sautez cette étape, les joueurs extérieurs ne pourront pas rejoindre votre serveur. [Tapez Enter] you_have_finished = Vous avez correctement terminé l'assistant d'installation -devmine_will_start = devmine va maintenant démarrer. Tapez /help pour voir la liste des commandes disponibles. -devmine_plugins = Vérification du répertoire de plugin pour ajouter des nouvelles caractéristiques, mini-jeux, ou une protection avancée de votre serveur +DevMine_will_start = DevMine va maintenant démarrer. Tapez /help pour voir la liste des commandes disponibles. +DevMine_plugins = Vérification du répertoire de plugin pour ajouter des nouvelles caractéristiques, mini-jeux, ou une protection avancée de votre serveur diff --git a/src/devmine/utilities/languages/Installer/ita.ini b/src/devmine/utilities/languages/Installer/ita.ini new file mode 100644 index 0000000..b4ae613 --- /dev/null +++ b/src/devmine/utilities/languages/Installer/ita.ini @@ -0,0 +1,51 @@ +language_has_been_selected = Hai selezionato correttamente l'italiano. +skip_installer = Vuoi saltare la procedura guidata di installazione? + +welcome_to_DevMine = Benvenuto in DevMine!\nPrima di iniziare la configurazione del nuovo server e' necessario accettare la licenza.\nDevMine e' rilasciato sotto la licenza LGPL,\nche si puo' leggere aprendo il file di licenza su questa cartella. +accept_license = Accettate la licenza? +you_have_to_accept_the_license = Bisogna accettare la licenza LGPL per continuare ad utilizzare DevMine + +setting_up_server_now = Si sta per configurare il server ora. +default_values_info = Se non si desidera modificare il valore di default, basta premere Invio. +server_properties = E' possibile modificarli in seguito aprendo il file server.properties. + +name_your_server = Nome del server +port_warning = Non modificare il valore della porta di default se questo e' il vostro primo server. +server_port = Porta del server +invalid_port = Porta del server invalida +online_mode_info = In modalita' online, il server costringera' l'utente a effettuare il login tramite XBOX. \nL'attivazione della modalita' online e' consigliato se il server e' aperto ai giocatori esterni. +online_mode = Vuoi abilitare la modalita' online? +ram_warning = La RAM e' la quantita' massima di memoria che DevMine utilizzera'. Si consiglia un valore di 128-256 MB +server_ram = Server RAM in MB +gamemode_info = Scegliere tra Creativa (1) o sopravvivenza (0) +default_gamemode = Modalita' di gioco predefinito +max_players = Max. giocatori online +spawn_protection_info = La protezione di spawn non consente il piazzamento di blocchi e la loro rottura nella zona di spawn ad eccezione degli operatori +spawn_protection = Attiva protezione spawn? +level_name = Impostare il nome del livello +level_type = Impostare il tipo di livello di server +invalid_level_type = Tipo di livello non valido +announce_player_achievements = Annuncia quando un giocatore ottiene un obbiettivo? + +op_info = Un operatore e' il giocatore di amministrazione del server. Gli operatori possono eseguire piu' comandi di giocatori normali +op_who = Nome delgli operatori (esempio, il tuo nome) +op_warning = Sarete in grado di aggiungere un operatore in seguito utilizzando / op +whitelist_info = Il white-list consente solo a certi giocatori di unirsi. +whitelist_enable = Desideri attivare la white-list? +whitelist_warning = Dovrai aggiungere i giocatori alla whitelist + +query_warning1 = Query e' un protocollo utilizzato da diversi strumenti per ottenere informazioni del server e giocatori loggati. +query_warning2 = Se si disattiva, non sarai in grado di utilizzare gli elenchi di server. +query_disable = Vuoi disattivare Query? +rcon_info = RCON e' un protocollo per la connessione remota con la console del server utilizzando una password. +rcon_enable = Vuoi abilitare RCON? +rcon_password = password RCON (si puo' cambiare in un secondo momento) +usage_info = I dati di utilizzo anonimi ci permette di calcolare le statistiche globali per DevMine-MP e dei suoi plug-in. e' possibile visualizzarle su stats.pocketmine.net +usage_disable = Vuoi per disattivare l'uso di dati anonimo? +ip_get = Ottenendo il vostro IP esterno e IP interno +ip_warning = Il tuo IP esterno e' {{EXTERNAL_IP}}. Potrebbe essere necessario port-forward per il tuo IP interno {{INTERNAL_IP}} +ip_confirm = Assicuratevi di controllarlo, se devi fare il port-forward e non lo fai, nessun giocatore esterno sara' in grado di entrare. [Premere Invio] + +you_have_finished = e' terminata correttamente la procedura guidata di installazione +DevMine_will_start = DevMine ora si avviera'. Digita /help per visualizzare l'elenco dei comandi disponibili. +DevMine_plugins = Controllare il Repository Plugin per aggiungere nuove funzionalita', minigiochi, o protezione avanzata per il vostro server diff --git a/src/devmine/utilities/languages/Installer/jpn.ini b/src/devmine/utilities/languages/Installer/jpn.ini index e260ef8..404f5f8 100644 --- a/src/devmine/utilities/languages/Installer/jpn.ini +++ b/src/devmine/utilities/languages/Installer/jpn.ini @@ -1,9 +1,9 @@ language_has_been_selected = 日本語に設定されました skip_installer = セットアップウィザードをスキップしますか? -welcome_to_devmine = devmineをインストールして頂きありがとうございます!サーバのセットアップを開始するにはライセンスに同意する必要があります。devmineはLGPLライセンスに基づいて認可されており、これについてはこのフォルダ内のLICENSEファイルから確認することができます。 +welcome_to_DevMine = DevMineをインストールして頂きありがとうございます!サーバのセットアップを開始するにはライセンスに同意する必要があります。DevMineはLGPLライセンスに基づいて認可されており、これについてはこのフォルダ内のLICENSEファイルから確認することができます。 accept_license = ライセンスに同意しますか? -you_have_to_accept_the_license = devmineを使用するにはLGPLライセンスに同意する必要があります +you_have_to_accept_the_license = DevMineを使用するにはLGPLライセンスに同意する必要があります setting_up_server_now = サーバのセットアップを開始します default_values_info = 設定を変更しない場合は、Enterキーを押してください。 @@ -13,7 +13,9 @@ name_your_server = あなたのサーバに名前を付けてください port_warning = これが初めてのサーバの場合は、ポート番号をデフォルトから変更しないでください server_port = サーバポート invalid_port = 無効なサーバポートです -ram_warning = RAMはdevmineが使用し得るメモリの最大値を示しています。128-256MBの範囲内で指定することを推奨します。 +online_mode_info = オンラインモードでは、ユーザーがXBOXを経由してログインすることを強制します。\nサーバーが外部に開放されている場合はオンラインモードを有効にすることをおすすめします。 +online_mode = オンラインモードを有効にしますか? +ram_warning = RAMはDevMineが使用し得るメモリの最大値を示しています。128-256MBの範囲内で指定することを推奨します。 server_ram = RAMの単位はMBです gamemode_info = クリエイティブモード(1)、またはサバイバルモード(0)を選択してください default_gamemode = デフォルトのゲームモード @@ -38,12 +40,12 @@ query_disable = クエリを無効にしますか? rcon_info = RCONはパスワードを用いてサーバコンソールからリモート接続するためのプロトコルです。 rcon_enable = RCONを有効にしますか? rcon_password = RCONパスワード(後から変更できます) -usage_info = 世界中で使われているdevmine-MPやそのプラグインの統計を算出するために匿名の使用データが送信されます。統計はこちらから確認できます。stats.devmine.net +usage_info = 世界中で使われているDevMine-MPやそのプラグインの統計を算出するために匿名の使用データが送信されます。統計はこちらから確認できます。stats.pocketmine.net usage_disable = 匿名の使用データの送信を拒否しますか? ip_get = グローバルIPとプライベートIPの取得 ip_warning = あなたのグローバルIPは{{EXTERNAL_IP}}です。プライベートIP{{INTERNAL_IP}}をポート解放してください。 ip_confirm = 必ずポート解放ができているか確認してください。ポートが解放できていなかった場合、他のプレイヤーがサーバに入れなくなる恐れがあります。[Enterキーを押してください] you_have_finished = セットアップは正しく終了しました -devmine_will_start = devmineを起動します。/helpと入力すれば使用可能なコマンド一覧を表示できます。 -devmine_plugins = 拡張機能や管理システム、ミニゲームなどを追加できるプラグインリポジトリも確認してみてください +DevMine_will_start = DevMineを起動します。/helpと入力すれば使用可能なコマンド一覧を表示できます。 +DevMine_plugins = 拡張機能や管理システム、ミニゲームなどを追加できるプラグインリポジトリも確認してみてください diff --git a/src/devmine/utilities/languages/Installer/kor.ini b/src/devmine/utilities/languages/Installer/kor.ini new file mode 100644 index 0000000..bbaa0dd --- /dev/null +++ b/src/devmine/utilities/languages/Installer/kor.ini @@ -0,0 +1,51 @@ +language_has_been_selected = 한국어가 언어로 선택되었습니다. +skip_installer = 설치 마법사를 건너뛰겠습니까? + +welcome_to_DevMine = DevMine에 오신 것을 환영합니다!\n서버 설치를 시작하기 전, 약관에 동의해야 합니다. \nDevMine는 GNU 약소 일반 공중 사용 허가서(LGPL) 하에 배포되고 있습니다. \n이 폴더에서 약관을 읽을 수 있습니다. +accept_license = 약관에 동의하십니까? +you_have_to_accept_the_license = GNU 약소 일반 공중 사용 허가서(LGPL)에 동의하셔야 DevMine를 사용할 수 있습니다. + +setting_up_server_now = 서버 설정을 시작합니다. +default_values_info = 기본값을 수정하고 싶지 않으면, 엔터를 누르시기 바랍니다. +server_properties = 이 설정들은 server.properties 파일에서 세부적으로 변경이 가능합니다. + +name_your_server = 당신의 서버 이름을 입력하시기 바랍니다. +port_warning = 만약 당신이 서버를 처음 설정한다면 포트 값을 변경하지 마세요. +server_port = 서버 포트 +invalid_port = 서버 포트가 잘못 입력되었습니다. +online_mode_info = 온라인 모드에서는 서버가 사용자를 XBOX를 사용해서만 로그인하도록 합니다.\n외부 서버를 여는 경우 온라인 모드를 활성화 하는 것이 좋습니다. +online_mode = 온라인 모드를 활성화 하시겠습니까? +ram_warning = RAM 값은 DevMine에 할당할 메모리의 크기입니다. 128~256MB를 권장합니다. +server_ram = 서버의 램(RAM) (MB) +gamemode_info = 크리에이티브 (1) 또는 서바이벌 (0) 게임모드 중 하나를 고르세요. +default_gamemode = 기본 게임 모드 +max_players = 최대 동시접속 인원 수 +spawn_protection_info = 스폰 보호는 OP를 제외한 유저들이 스폰 지역 근처에서 블럭을 놓거나 부수는 것을 방지합니다. +spawn_protection = 스폰 지역 보호를 사용하겠습니까? +level_name = 레벨의 이름을 설정하시기 바랍니다. +level_type = 레벨의 유형을 설정하시기 바랍니다. +invalid_level_type = 레벨 유형이 잘못 입력되었습니다. +announce_player_achievements = 플레이어가 도전 과제를 달성했을때 알리시겠습니까? + +op_info = OP는 서버 관리자를 뜻합니다. OP는 일반 플레이어보다 훨씬 많은 명령어들을 사용할 수 있습니다 +op_who = OP 권한을 줄 플레이어 이름(예: 당신의 닉네임) +op_warning = 또는 이후에 /op <플레이어 이름> 을 입력해 그 유저에게 OP 권한을 줄 수도 있습니다 +whitelist_info = 화이트리스트를 사용하면 허용된 플레이어들만 서버에 접속할 수 있습니다. +whitelist_enable = 화이트리스트를 사용하겠습니까? +whitelist_warning = 당신은 접속을 허용할 플레이어들의 이름을 적어야 합니다 + +query_warning1 = 쿼리 (Query)는 당신의 서버와 현재 접속한 플레이어들의 정보를 알 수 있게 해주는 여러가지 기능이 담긴 프로토콜입니다. +query_warning2 = 쿼리를 사용하지 않으면, 당신은 서버 리스트를 사용할 수 없게 됩니다. +query_disable = 쿼리를 사용하지 않겠습니까? +rcon_info = RCON은 비밀 번호를 사용하여 서버 명령창에 원격으로 접속할 수 있는 프로토콜입니다. +rcon_enable = RCON을 사용하시겠습니까? +rcon_password = RCON 비밀번호 설정 (나중에 server.properties 에서 변경이 가능합니다.) +usage_info = 익명 사용 통계 전송을 허용하면 DevMine-MP가 세계의 서버 상황과 플러그인들을 통계화하는 데 사용할 수 있습니다. 당신은 stats.pocketmine.net에서 이를 확인할 수 있습니다 +usage_disable = 익명 사용 통계 전송을 사용하지 않으시겠습니까? +ip_get = 내/외부 IP 주소 얻기 +ip_warning = 당신의 외부 IP는 {{EXTERNAL_IP}}입니다. 당신의 내부 IP {{INTERNAL_IP}}로 포트포워딩이 필요할 수 있습니다 +ip_confirm = 신중하게 확인하세요. 만약 포트포워딩이 필요하지만 하지 않을 경우 외부에서 플레이어들이 접속할 수 없게 됩니다. [계속 하시려면 엔터를 누르세요] + +you_have_finished = DevMine의 설치가 모두 완료되었습니다. +DevMine_will_start = DevMine 서버를 구동합니다. /help로 사용 가능한 모든 명령어의 목록을 보시기 바랍니다. +DevMine_plugins = 플러그인 저장소에서 새로운 기능을 추가하세요. 새로운 기능, 미니게임을 추가하거나 고급 기능으로 당신의 서버를 보호할 수 있습니다 diff --git a/src/devmine/utilities/languages/Installer/rus.ini b/src/devmine/utilities/languages/Installer/rus.ini index afbe35d..ef02bdf 100644 --- a/src/devmine/utilities/languages/Installer/rus.ini +++ b/src/devmine/utilities/languages/Installer/rus.ini @@ -1,9 +1,9 @@ language_has_been_selected = Был выбран русский язык. skip_installer = Вы хотите пропустить мастер настройки? -welcome_to_devmine = Добро пожаловать в devmine!\nПеред началом установки нового сервера, вы должны согласиться с лицензией. \ndevmine лицензировано на условиях LGPL лицензии, \nс которой вы можете ознакомиться, открыв файл LICENSE в этой папке. +welcome_to_DevMine = Добро пожаловать в DevMine!\nПеред началом установки нового сервера, вы должны согласиться с лицензией. \nDevMine лицензировано на условиях LGPL лицензии, \nс которой вы можете ознакомиться, открыв файл LICENSE в этой папке. accept_license = Принимаете ли вы лицензию? -you_have_to_accept_the_license = Вы должны принять LGPL лицензию, чтобы продолжить использование devmine +you_have_to_accept_the_license = Вы должны принять LGPL лицензию, чтобы продолжить использование DevMine setting_up_server_now = Теперь вы можете настроить сервер. default_values_info = Если вы не хотите изменять стандартное значение, просто нажмите Enter. @@ -13,7 +13,9 @@ name_your_server = Дайте имя вашему серверу port_warning = Не изменяйте значение порта по умолчанию, если это ваш первый сервер. server_port = Порт сервера invalid_port = Неверный порт сервера -ram_warning = RAM - максимальный объем памяти, котооый будет использовать devmine, рекомендуемое значение 128-256 МБ +online_mode_info=online-mode позволяет проверять игрока на аутентификацию в XBOX Live +online_mode=Включить online-mode? +ram_warning = RAM - максимальный объем памяти, котооый будет использовать DevMine, рекомендуемое значение 128-256 МБ server_ram = Оперативная память сервера в МБ gamemode_info = Выберите между Креативом-(1), или Выживанием (0) default_gamemode = Режим игры по умолчанию @@ -38,12 +40,12 @@ query_disable = Вы хотите отключить Query? rcon_info = RCON - это протокол для удаленного управления сервером через консоль, с использованием пароля. rcon_enable = Вы хотите включить RCON? rcon_password = RCON пароль (вы сможете изменить его позже) -usage_info = Сбор анонимных данных о использовании поможет нам проанализировать глобальную статистику для devmine-MP и плагинов. Статистика доступна по адресу stats.devmine.net +usage_info = Сбор анонимных данных о использовании поможет нам проанализировать глобальную статистику для DevMine-MP и плагинов. Статистика доступна по адресу stats.pocketmine.net usage_disable = Вы хотите отключить сбор анонимных данных о использовании? ip_get = Получение вашего внешнего и внутреннего IP адреса ip_warning = Ваш внешний IP адрес: {{EXTERNAL_IP}}. Возможно вам необходимо открыть порты к вашему внутреннему IP адресу: {{INTERNAL_IP}} ip_confirm = Убедитесь в том, что вы открыли порты, в противном случае игроки вне вашей локальной сети не смогут подключится. [Нажмите Enter] you_have_finished = Вы закончили работу с мастером установки -devmine_will_start = devmine сейчас запустится. Введите /help для просмотра доступных вам команд. -devmine_plugins = Посетите репозиторий плагинов для получения новых функций, мини-игр, или повышения защиты вашего сервера +DevMine_will_start = DevMine сейчас запустится. Введите /help для просмотра доступных вам команд. +DevMine_plugins = Посетите репозиторий плагинов для получения новых функций, мини-игр, или повышения защиты вашего сервера diff --git a/src/devmine/utilities/languages/Installer/ukr.ini b/src/devmine/utilities/languages/Installer/ukr.ini new file mode 100644 index 0000000..67b6f23 --- /dev/null +++ b/src/devmine/utilities/languages/Installer/ukr.ini @@ -0,0 +1,51 @@ +language_has_been_selected = Було вибрано українську мову. +skip_installer = Бажаєте пропустити майстер налаштування? + +welcome_to_DevMine = Вітаємо в DevMine!\nПеред початком встановлення нового серверу, ви маєте погодитися з умовами ліцензії. \nDevMine ліцензовано на умовах LGPL. \nДетально ви можете ознайомитися з нею у файлі LICENSE в цій теці. +accept_license = Ви приймаєте умови ліцензії? +you_have_to_accept_the_license = Ви маєте погодитися з умовами LGPL ліцензії для подальшого користування DevMine + +setting_up_server_now = Тепер ви можете налаштувати сервер. +default_values_info = Для вибору значень за замовчуванням просто натискайте Enter. +server_properties = Пізніше ви зможете їх відредагувати у файлі server.properties. + +name_your_server = Вкажіть назву вашого серверу +port_warning = Не змінюйте номер порту за замовчуванням, якщо ви налаштовуєте сервер вперше. +server_port = Порт серверу +invalid_port = Неправильний порт серверу +online_mode_info=online-mode дозволяє перевіряти у гравця наявність аутентифікації в XBOX Live +online_mode=Ввімкнути online-mode? +ram_warning = RAM - максимальний об’єм пам’яті, який буде використовувати DevMine, рекомендоване значення - 128-256 МБ +server_ram = Оперативна пам’ять серверу в МБ +gamemode_info = Вкажіть 1 для Творчого режиму на сервері або 0 для Виживання +default_gamemode = Режим гри за замовчуванням +max_players = Максимальна кількість гравців +spawn_protection_info = Захист місця появи гравців забороняє розміщення або руйнування блоків на місті появи гравця, за виключенням операторів +spawn_protection = Ввімкнути захист спавну? +level_name = Вкажіть назву світу +level_type = Вкажіть тип світу +invalid_level_type = Неправильний тип світу +announce_player_achievements = Демонструвати досягнення гравців? + +op_info = Оператор - це адміністратор серверу, що може використовувати більше команд, ніж звичайний гравець +op_who = Нік оператора (Наприклад, ваш нік в грі) +op_warning = Ви зможете додати оператора пізніше за допомогою команди /op <гравець> +whitelist_info = Білий список дозволяє заходити тільки тим гравцям, що знаходяться в ньому. +whitelist_enable = Бажаєте ввімкнути білий список? +whitelist_warning = Необхідно додати гравців до білого списку + +query_warning1 = QUERY - це протокол, що використовується різними інструментами для отримання інформації про сервер та про гравців серверу. +query_warning2 = Якщо ви його вимкнете, то не зможете користуватися моніторингами серверів. +query_disable = Ви хочете вимкнути QUERY? +rcon_info = RCON - це протокол, який реалізує віддалене керування сервером. Захищене паролем. +rcon_enable = Бажаєте ввімкнути RCON? +rcon_password = RCON пароль (ви зможете змінити його пізніше) +usage_info = Збір анонімних даних про користування допоможе нам проаналізувати глобальну статистику для DevMine-MP и плагінів. Статистика доступна за адресою stats.pocketmine.net +usage_disable = Бажаєте вимкнути збір анонімних даних про користування? +ip_get = Отримання вашого внутрішньої і зовнішньої IP адрес +ip_warning = Ваша зовнішня IP адреса: {{EXTERNAL_IP}}. Можливо, вам необхідно відкрити порти до вашої внутрішньої адреси: {{INTERNAL_IP}} +ip_confirm = Переконайтеся в тому, що ви відкрили порти, інакше гравці поза локальною мережею не зможуть приєднатися. [Натисніть Enter] + +you_have_finished = Ви завершили роботу з майстром встановлення +DevMine_will_start = DevMine зараз запуститься. Введіть /help для перегляду доступних команд. +DevMine_plugins = Відвідайте сховище плагінів для отримання нових функцій, міні ігр або для підвищення захисту вашого серверу diff --git a/src/devmine/utilities/languages/Installer/zho.ini b/src/devmine/utilities/languages/Installer/zho.ini index 1c5eb24..923db9e 100644 --- a/src/devmine/utilities/languages/Installer/zho.ini +++ b/src/devmine/utilities/languages/Installer/zho.ini @@ -1,9 +1,9 @@ language_has_been_selected=您選擇了繁體中文 skip_installer=您想跳過安裝精靈嗎? -welcome_to_devmine=歡迎來到devmine!\n在開始使用您的新伺服器前您需要接受以下協議\ndevmine使用了LGPL協議\n你可以在這個資料夾中找到LICENCE文件 +welcome_to_DevMine=歡迎來到DevMine!\n在開始使用您的新伺服器前您需要接受以下協議\nDevMine使用了LGPL協議\n你可以在這個資料夾中找到LICENCE文件 accept_license=您接受協議內容嗎? -you_have_to_accept_the_license=您必須接受LGPL協議來繼續使用devmine +you_have_to_accept_the_license=您必須接受LGPL協議來繼續使用DevMine setting_up_server_now=您現在要開始設定您的伺服器了 default_values_info=如果您希望使用預設值請直接按下Enter鍵 @@ -13,7 +13,9 @@ name_your_server=命名您的伺服器: port_warning=如果這是您第一次設定服伺服器,請儘量不要更改接口 server_port=伺服器接口: invalid_port=不正確的伺服器接口 -ram_warning=RAM是devmine可用的最大記憶體。推薦範圍:128~256 MB +online_mode_info = 多人連線模式下, 伺服器將強制玩家需要 Xbox 登入\n當多人模式時, 建議讓伺服器開啟此功能 +online_mode = 您想啟用多人模式? +ram_warning=RAM是DevMine可用的最大記憶體。推薦範圍:128~256 MB server_ram=分配給服務器的記憶體(MB): gamemode_info=選擇模式:(0) 生存模式 或 (1) 創造模式 default_gamemode=預設遊戲模式 @@ -38,12 +40,12 @@ query_disable=您希望停用Query請求嗎? rcon_info=RCON是一個用來遠程連接到伺服器控制台的協議(需要密碼) rcon_enable=您希望啟用RCON嗎? rcon_password=RCON密碼 (您以後能更改它): -usage_info=匿名數據讓我們可以獲得全球的devmine-MP和它的插件的統計訊息,您可以在 stats.devmine.net 查看統計訊息 +usage_info=匿名數據讓我們可以獲得全球的DevMine-MP和它的插件的統計訊息,您可以在 stats.pocketmine.net 查看統計訊息 usage_disable=您希望停用匿名數據嗎? ip_get=取得你的外網IP和內網IP ip_warning=您的外網IP是 {{EXTERNAL_IP}},您可能需要接口轉發到您的內網IP {{INTERNAL_IP}} ip_confirm=請確認您檢查了它,如果您直接進入下一步並跳過這一步,沒有外部的玩家可以加入 [按\"Enter\"鍵] you_have_finished=您已經成功完成了伺服器安裝精靈 -devmine_will_start=devmine現在開始運行,輸入 \"/help\" 來看所有可用的指令 -devmine_plugins=請查看插件源來新增新的功能,迷你遊戲或者對伺服器的高級保護 +DevMine_will_start=DevMine現在開始運行,輸入 \"/help\" 來看所有可用的指令 +DevMine_plugins=請查看插件源來新增新的功能,迷你遊戲或者對伺服器的高級保護 diff --git a/src/devmine/utilities/languages/locale/ces.ini b/src/devmine/utilities/languages/locale/ces.ini new file mode 100644 index 0000000..563c7bc --- /dev/null +++ b/src/devmine/utilities/languages/locale/ces.ini @@ -0,0 +1,318 @@ + +language.name=Čeština +language.selected=Vybráno {%0} ({%1}) jako základní jazyk + +multiplayer.player.joined={%0} se připojil do hry +multiplayer.player.left={%0} se odpojil ze hry + +chat.type.text={%0} : {%1} +chat.type.achievement={%0} právě získal ocenění {%1} + +disconnectionScreen.outdatedClient=Zastaralá verze! +disconnectionScreen.outdatedServer=Zastaralý server! +disconnectionScreen.serverFull=Server je plný! +disconnectionScreen.noReason=Odpojen ze serveru +disconnectionScreen.invalidSkin=Neplatný skin! +disconnectionScreen.invalidName=Nevhodný herní nick! + +death.fell.accident.generic={%0} spadl z vysokého místa +death.attack.inFire={%0} shořel v ohni +death.attack.onFire={%0} uhořel k smrti +death.attack.lava={%0} se pokusil plavat v lávě +death.attack.inWall={%0} se udusil ve zdi +death.attack.drown={%0} se utopil +death.attack.cactus={%0} byl upíchán k smrti +death.attack.generic={%0} zemřel +death.attack.explosion={%0} vybouchnul +death.attack.explosion.player={%0} byl odbouchnut hráčem {%1} +death.attack.magic={%0} byl zabit magickým efektem +death.attack.wither={%0} zemřel na útok Withera +death.attack.mob= {%0} byl zabit {%1} +death.attack.player= {%0} byl zabit {%1} +death.attack.player.item={%0} byl zabit hráčem {%1} používajícím {%2} +death.attack.arrow={%0} byl zastřelen {%1} +death.attack.arrow.item={%0} byl zastřelen hráčem {%1} používajícím {%2} +death.attack.fall={%0} spadl z moc velké výšky +death.attack.outOfWorld={%0} vypadl ze světa + +gameMode.survival=§l§f"Mód Survival" +gameMode.creative=§l§f"Mód Creative" +gameMode.adventure=§l§f"Mód Adventure" +gameMode.spectator=§l§f"Mód Spetractor" +gameMode.changed=Tvůj herní mód byl úspěšně změněn + +potion.moveSpeed=Rychlost +potion.moveSlowdown=zpomalení +potion.digSpeed=Rychle kopání +potion.digSlowDown=Pomalé kopání +potion.damageBoost=Síla +potion.heal=Rychlé uzdravení +potion.harm=Rychlé zranění +potion.jump=vysoké skoky +potion.confusion=nevolnost +potion.regeneration=Regenerace +potion.resistance=Odpor +potion.fireResistance=Ohnivzdornost +potion.waterBreathing=Dýchání pod vodou +potion.invisibility=Neviditelnost +potion.blindness=Hloupost +potion.nightVision=Noční vidění +potion.hunger=Hlad +potion.weakness=Slabost +potion.poison=Jed +potion.wither=Wither +potion.healthBoost=Zvýšení života +potion.absorption=Absorbace +potion.saturation=Saturace + +commands.generic.exception=Při pokusu o provedení tohoto příkazu došlo k neznámé chybě +commands.generic.permission=§l§cNemas opravneni pouzit tento prikaz +commands.generic.notFound=§l§cNeznamy příkaz. Pouzijte /help pro ziskani seznamu prikazu +commands.generic.player.notFound=Tento hráč nemůže být nalezen +commands.generic.usage=Vyuziti:{%0} + +commands.time.added=Pridáno {%0} do časů +commands.time.set=Čas nastaven na {%0} +commands.time.query=Čas je {%0} + +commands.me.usage=/me + +commands.give.item.notFound=Neexistuje žádný item s tímto ménem {%0} +commands.give.success=Given {%0} * {%1} to {%2} +commands.give.tagError=Rozbor data tagu neůspesný: {%0} + +commands.effect.usage=/effect [seconds] [amplifier] [hideParticles] NEBO /effect clear +commands.effect.notFound=Efekt s ID {%0} neexistuje +commands.effect.success=Daný {%0} (ID {%1}) * {%2} na {%3} pro {%4} sekund +commands.effect.success.removed=Vzal {%0} z {%1} +commands.effect.success.removed.all=Vzal všechny efekty od {%0} +commands.effect.failure.notActive=Nemůžu vzít {%0} od {%1} protože efekt nemá +commands.effect.failure.notActive.all=Nemůžu získat efekt od {%0} protože žádný nemá + +commands.enchant.noItem=Terc nedrzi item +commands.enchant.notFound=Tady není zadný enchant s ID {%0} +commands.enchant.success=Enchant byl uspesný +commands.enchant.usage=/enchant [level] + +commands.particle.success=Zapínám efekt {%0} {%1} +commands.particle.notFound=Neznámé méno efektu {%0} + +commands.players.usage=/seznam +commands.players.list={%0}/{%1} Hráčů online: + +commands.kill.successful=Zabit {%0} + +commands.banlist.ips=Celkem zabanovaných IP adres: %d +commands.banlist.players=Je zabanováno {%0} Hráčů: +commands.banlist.usage=/banlist [ips|players] + +commands.defaultgamemode.usage=/defaultgamemode +commands.defaultgamemode.success=Základní herní mód je teď {%0} + +commands.op.success=Povýšen {%0} +commands.op.usage=/op + +commands.deop.success=§l§cDe-opnut {%0} +commands.deop.usage=/deop + +commands.say.usage=/say + +commands.seed.usage=/seed +commands.seed.success=Seed:{%0} + +commands.ban.success=Zabanován hráč {%0} +commands.ban.usage=/ban [Důvod ...] + +commands.unban.success=Odbanován hráč {%0} +commands.unban.usage=/pardon + +commands.banip.invalid=Zadal jsi špatnou IP adresu nebo tento hráč není online +commands.banip.success=Zabanována IP adresa {%0} +commands.banip.success.players=Zabanovaná IP adresa {%0} byla přepsána na{%1} +commands.banip.usage=/ban-ip [Důvod...] + +commands.unbanip.invalid=Zadal jsi špatnou ip adresu +commands.unbanip.success=Odbanovali jste adresu ip {%0} +commands.unbanip.usage=/pardon-ip
+ +commands.save.usage=-ulozit-vse +commands.save-on.usage=/zapnout-ukladani +commands.save-off.usage=/vypnout-ulozeni +commands.save.enabled=Automatické ukládání světa zapnuto +commands.save.disabled=Automatické ukládání světa vypnuto +commands.save.start=Ukládám... +commands.save.success=Svět uložen + +commands.stop.usage=/stop +commands.stop.start=Zastavuji server + +commands.kick.success={%0} byl odpojen ze hry +commands.kick.success.reason={%0} byl kicknut ze serveru z duvodu: {%1} +commands.kick.usage=/odpojit [důvod...] + +commands.tp.success={%0} se portnul k {%1} +commands.tp.success.coordinates={%0} Se portnul na souřadnice {%1}, {%2}, {%3} +commands.tp.usage=/tp [cílový hráč] OR /tp [cílový hráč] [ ] + +commands.whitelist.list=Nacházejí se zde {%0} (z {%1} viděných) whitelist hráčů: +commands.whitelist.enabled=Zapnut whitelist +commands.whitelist.disabled=Vypnut whitelist +commands.whitelist.reloaded=Whitelist znova načten +commands.whitelist.add.success={%0} byl přidán na whitelist +commands.whitelist.add.usage=/whitelist přidat +commands.whitelist.remove.success={%0} byl odebrán z whitelistu +commands.whitelist.remove.usage=/whitelist odebrat +commands.whitelist.usage=/whitelist + +commands.gamemode.success.self=Změnit svůj herní mód na {%2} +commands.gamemode.success.other=Změněn herní mód hráče {%1} na {%2} +commands.gamemode.usage=/gamemode [player] + +commands.help.header=--- Ukazuji pomoc - strana {%0} z {%1} (/help ) --- +commands.help.usage=§l/help [strana|jméno příkazu] + +commands.message.usage=/tell +commands.message.sameTarget=Nemůžeš poslat soukromou zprávu sám sobě! + +commands.difficulty.usage=/difficulty +commands.difficulty.success=Herní obtížnost nastavena na {%0} + +commands.spawnpoint.usage=/spawnpoint [player] [ ] +commands.spawnpoint.success={%0}ův spawnpoint byl nastaven na ({%1}, {%2}, {%3}) + +commands.setworldspawn.usage=/setworldspawn [] +commands.setworldspawn.success=Spawn světa byl nastaven na souřadnice ({%0}, {%1}, {%2}) + + + +DevMine.data.playerNotFound=Data hráče {%0} nenalezena, vytvářím nový profil +DevMine.data.playerCorrupted=Špatná data hráče {%0}, vytvářím nový profil +DevMine.data.playerOld=Pro hráče {%0} nalezena stará data, vylepšuji profil +DevMine.data.saveError=Nemůžu nastavit hráče {%0}; {%1} + +DevMine.level.notFound=Svět {%0} nebyl nalezen +DevMine.level.loadError=Nemůžu načíst svět {%0}; {%1} +DevMine.level.generationError=Nemůžu vytvořit svět {%0}; {%1} +DevMine.level.tickError=Nemůžu najít svět {%0}; {%1} +DevMine.level.chunkUnloadError=Chyba při načítáni chunku {%0} +DevMine.level.backgroundGeneration=Spawn pro svět {%0} bude vytvořen v pozadí +DevMine.level.defaultError=Žádný základní level nebyl načten +DevMine.level.preparing=Připravuji svět {%0} +DevMine.level.unloading=Odnacitavam svět {%0} + +DevMine.server.start=Startuji Minecraft: PE server na verzi {%0} +DevMine.server.networkError=[Network] Zastavil interface {%0} protože {%1} +DevMine.server.networkStart=Startuji server na {%0}:{%1} +DevMine.server.info=Tento server běží na {%0} verzi {%1}"{%2}" (API {%3}) +DevMine.server.info.extended=Tento server používá {%0} {%1}「{%2}」implantována API {%3} pro Minecraft:PE {%4} +(protokol {%5}) +DevMine.server.license={%0} je distribuován pod LGPL Licencí +DevMine.server.tickOverload=Pozor! Server je pretižen! +DevMine.server.startFinished=Hotovo ({%0}s)! Pro pomoc napiš "help" nebo "?" +DevMine.server.defaultGameMode=Základní herní mód je:{%0} +DevMine.server.query.start=Zapínám GS4 status poslouchač +DevMine.server.query.info=Nastavuji query port na {%0} +DevMine.server.query.running=Query běží na {%0}:{%1} + +DevMine.command.alias.illegal=Nemůžu registrovat alias {%0} protože obsahuje nepoužitelné písmena +DevMine.command.alias.notFound=Nemůžu registrovat alias {%0} protože obsahuje příkaz který neexistuje:{%1} +DevMine.command.exception=Neošetřené použití příkazu '{%0}' in {%1}: {%2} + +DevMine.command.plugins.description=Dá list všech pluginů na serveru +DevMine.command.plugins.success=Pluginy ({%0}):{%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=Přenačte kofiguraci serveru a jeho pluginy +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=Znovu načítám data serveru.... +DevMine.command.reload.reloaded=Načtení serveru proběhlo úspěšně + +DevMine.command.status.description=Vrátí zpátky výkon serveru. +DevMine.command.status.usage=/status + +DevMine.command.gc.description=Fires garbage collection tasks +DevMine.command.gc.usage=/gc + +DevMine.command.timings.description=Nahrává načasování aby viděl stav serveru. +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=Zapnuto časování & reset +DevMine.command.timings.disable=Vypnuto časování +DevMine.command.timings.timingsDisabled=Prosím zapněte nahrávání zadáním: /timings on +DevMine.command.timings.reset=Nastaven restart +DevMine.command.timings.pasteError=Při vkládání zprávy nastala chyba +DevMine.command.timings.timingsUpload=Nahrávání nahrána na {%0} +DevMine.command.timings.timingsRead=Můžete si přečíst výsledky na {%0} +DevMine.command.timings.timingsWrite=Nahrávání napsána do {%0} + +DevMine.command.version.description=Dá vám informace o všech používaných pluginech +DevMine.command.version.usage=/version [plugin name] +DevMine.command.version.noSuchPlugin=Tento server nepoužívá žádný plugin s tímto jménem. Použij /plugins. + +DevMine.command.give.description=Daruje specifikovanému hráči určený počet vybraných itemů +DevMine.command.give.usage=/give [amount] [tags...] + +DevMine.command.kill.description=Zabití +DevMine.command.kill.usage=/kill [player] + +DevMine.command.particle.description=Přidá prvek do světa +DevMine.command.particle.usage=/particle [count] [data] + +DevMine.command.time.description=Nastaví čas sveta +DevMine.command.time.usage=/time NEBO /time + +DevMine.command.ban.player.description=Zakáže hráči přístup na server +DevMine.command.ban.ip.description=Zakáže specifické IP adrese používat tento server +DevMine.command.banlist.description=Zobrazí všechny zabanované hráče +DevMine.command.defaultgamemode.description=Nastaví základní herní mód +DevMine.command.deop.description=Nastaví hráči op +DevMine.command.difficulty.description=Nastaví obtížnost hry +DevMine.command.enchant.description=Pridá enchant na itemy +DevMine.command.effect.description=Přidá/Odebere hráči op +DevMine.command.gamemode.description=Změní hráči herní mód +DevMine.command.help.description=Ukáže nápovědu +DevMine.command.kick.description=Odebere ban hráči +DevMine.command.list.description=Seznam všech připojených hráčů +DevMine.command.me.description=Udělá popsanou akci v chatu +DevMine.command.op.description=Dá danému hráči status operátora +DevMine.command.unban.player.description=Zruší ban danému hráči +DevMine.command.unban.ip.description=Zruší ban dané IP adrese +DevMine.command.save.description=Uloží data serveru na disk +DevMine.command.saveoff.description=Vypne automatické ukládání serveru +DevMine.command.saveon.description=Zapnuto automatické ukládání serveru +DevMine.command.say.description=Napíše zprávu jako odesílatel +DevMine.command.seed.description=Zobrazí seed světa +DevMine.command.setworldspawn.description=Nastaví spawn světa. Pokud nejsou použity žádné souřadnice, budou použity souřadnice hráče. +DevMine.command.spawnpoint.description=Nastaví spawn hráči +DevMine.command.stop.description=zastaví server +DevMine.command.tp.description=Teleportuje daného hráče (nebo vás) k jinému hráči nebo na jiné souřadnice +DevMine.command.tell.description=Pošle soukromou zprávu vybranému hráči +DevMine.command.whitelist.description=Spravuje list hráčů s povolením navštívit tento server + +DevMine.crash.create=Neopravitelná chyba shodila server. Vytvářím report o chybe +DevMine.crash.error=Nemůžu vytvořit správu o chybě: {%0} +DevMine.crash.submit=Prosím nahrajte "{%0}" do archivu chyb a pošli link na stránku ohlašování chyb. Dej co nejvíc informací co můžeš. +DevMine.crash.archive=Zpráva o chybě byla nahrána do archivu chyb. Můžete se na ni podívat na {%0} nebo použít ID#{%1}. + +DevMine.debug.enable=LevelDB podpora zapnuta + +DevMine.player.invalidMove={%0} se hýbe špatně! +DevMine.player.logIn={%0}[/{%1}:{%2}] se připojil do hry s entitou id {%3} v ({%4},{%5},{%6},{%7}) +DevMine.player.logOut={%0}[/{%1}:{%2}] se odpojil kůli {%3} +DevMine.player.invalidEntity={%0} umřel na útok neznámého moba + +DevMine.plugin.load=Načítání {%0} +DevMine.plugin.enable=Povolení {%0} +DevMine.plugin.disable=Zakázání {%0} +DevMine.plugin.restrictedName=Omezené méno +DevMine.plugin.incompatibleAPI=Nekompatibilní API +DevMine.plugin.unknownDependency=Neznámá závislost +DevMine.plugin.circularDependency=oběžná závislost detekována +DevMine.plugin.genericLoadError=Nemůžu načíst plugin '{%0}' +DevMine.plugin.spacesDiscouraged=Plugin '{%0}' používá mezery ve svém jménu, to nejde +DevMine.plugin.loadError=Nemůžu načíst plugin '{%0}':{%1} +DevMine.plugin.duplicateError=Nemůžu načíst plugin '{%0}':plugin existuje +DevMine.plugin.fileError=Nemůžu načíst '{%0}' ve složce '{%1}':{%2} +DevMine.plugin.commandError=Nemůžu načíst příkaz {%0} pro plugin {%1} +DevMine.plugin.aliasError=Nemůžu načíst alias {%0} pro plugin {%1} +DevMine.plugin.deprecatedEvent=Plugin '{%0}' registroval poslouchač pro '{%1}' na metodě '{%2}', ale event. není praktikován. +DevMine.plugin.eventError="Nemůžu předělat event '{%0}' na'{%1}':{%2}na {%3}" diff --git a/src/devmine/utilities/languages/locale/chs.ini b/src/devmine/utilities/languages/locale/chs.ini index 55bcded..98de81f 100644 --- a/src/devmine/utilities/languages/locale/chs.ini +++ b/src/devmine/utilities/languages/locale/chs.ini @@ -1,20 +1,21 @@ # Language file compatible with Minecraft: Pocket Edition identifiers= #= # A message doesn't need to be there to be shown correctly on the client.= -# Only messages shown in devmine itself need to be here= +# Only messages shown in DevMine itself need to be here= -language.name=中文(简体) by PeratX QQ:1215714524 +language.name=中文(简体) language.selected=设定 {%0} ({%1}) 为基本语言 multiplayer.player.joined={%0} 加入了游戏 multiplayer.player.left={%0} 离开了游戏 -chat.type.text=<{%0}> {%1} +chat.type.text={%0} : {%1} chat.type.emote=* {%0} {%1} chat.type.announcement=[{%0}] {%1} chat.type.admin=[{%0}: {%1}] chat.type.achievement={%0} 刚刚获得了成就 {%1} +disconnectionScreen.notAuthenticated=需要 Xbox 登录 disconnectionScreen.outdatedClient=客户端版本过旧! disconnectionScreen.outdatedServer=服务器版本过旧! disconnectionScreen.serverFull=服务器人数已满! @@ -114,6 +115,7 @@ commands.players.list=There are {%0}/{%1} players online: commands.kill.successful=已删除 {%0} commands.banlist.ips=共有 {%0} 个被封锁的 IP 地址: commands.banlist.players=共有 {%0} 个被封锁的玩家: +commands.banlist.cids=共有 {%0} 禁止的 CIDs: commands.banlist.usage=/banlist [ips|players|cids] commands.defaultgamemode.usage=/defaultgamemode <模式> commands.defaultgamemode.success=服务器的默认游戏模式为 {%0} @@ -187,11 +189,8 @@ commands.whitelist.remove.success=从白名单删除 {%0} commands.whitelist.remove.usage=/whitelist remove <玩家名称> commands.whitelist.usage=/whitelist -devmine.command.fill.usage=/fill <方块> [方块损害值] -devmine.command.fill.invalidBlock=无效的方块名称或ID - -commands.gamemode.success.self=设定自己的游戏模式为 {%0} -commands.gamemode.success.other=设定 {%0} 的游戏模式为 {%1} +commands.gamemode.success.self=设定自己的游戏模式为 {%3} +commands.gamemode.success.other=设定 {%1} 的游戏模式为 {%2} commands.gamemode.usage=/gamemode <模式> [玩家名称] commands.help.header=--- 查看帮助列表第 {%0} 页共 {%1} 页 (/help ) --- commands.help.usage=/help [页数|指令名称] @@ -209,189 +208,198 @@ commands.setworldspawn.success=设定世界重生点为 ({%0},{%1},{%2}) commands.summon.usage=/summon [实体名] [ ] [数据标签] -commands.cave.usage=/cave <旋转角度> <洞穴长度> <分叉数> <洞穴强度> | /cave getmypos -commands.cave.info=旋转角度:{%0} 洞穴长度:{%1} 分叉数:{%2} 洞穴强度:{%3} -commands.cave.start=开始生成矿洞,可能需要较多时间 -commands.cave.success=矿洞生成完毕啦 -# -------------------- devmine language files, only for console -------------------- -devmine.data.playerNotFound=无法找到玩家数据 "{%0}",创建新的配置文件 -devmine.data.playerCorrupted=发现损坏的数据 "{%0}",创建新的配置文件 -devmine.data.playerOld=发现旧的玩家数据 "{%0}",更新配置文件 -devmine.data.saveError=无法储存 "{%0}" 的玩家数据:{%1} -devmine.level.notFound=无法找到 "{%0}" 地图 -devmine.level.loadError=无法读取地图 "{%0}":{%1} -devmine.level.generationError=无法产生地图 "{%0}":{%1} -devmine.level.tickError=计算地图“{%0}”时出现错误∶{%1} -devmine.level.chunkUnloadError=移除一个区块时发生错误:{%0} -devmine.level.backgroundGeneration=正在于背景生成世界 “{%0}“ 的地形 -devmine.level.defaultError=没有读取预设的地图 -devmine.level.preparing=准备地图中... "{%0}" -devmine.level.unloading=正在移除地图 "{%0}" -devmine.server.start=正在启动支持 Minecraft:PE {%0} 版本的服务器 -devmine.server.networkError=[网络] 停止接口 {%0} 由于 {%1} -devmine.server.networkStart=正在启动服务器在 {%0}:{%1} -devmine.server.info=此服务器正在运作 {%0} {%1} 版本 "{%2}" (API {%3}) -devmine.server.info.extended=此服务器正在运作 {%0} {%1} “{%2}” 执行 API 版本 {%3} 支持 Minecraft:PE {%4} (协议版本 {%5}) -devmine.server.license={%0} 根据 LGPL 许可发布 -devmine.server.tickOverload=注意!服务器有超载的可能 -devmine.server.startFinished=Done ({%0}s)!如需帮助,请输入 "help" 或 "?" -devmine.server.defaultGameMode=预设的游戏类型:{%0} -devmine.server.query.start=启动 GS4 状态监听器 -devmine.server.query.info=设定 query 接口到 {%0} -devmine.server.query.running=Query 运作在 {%0}:{%1} - -devmine.command.alias.illegal=不能注册别名 {%0},因为它包含非法字符 -devmine.command.alias.notFound=未能登记别称 {%0} ,因为它包含不存在的指令: {%1} -devmine.command.exception=于 {%1} 执行指令 “{%0}“ 时,出现了未被处理的错误: {%2} - -devmine.command.plugins.description=获取在服务器上运行的插件列表 -devmine.command.plugins.success=插件 ({%0}):{%1} -devmine.command.plugins.usage=/plugins - -devmine.command.reload.description=重新读取服务器设定和插件 -devmine.command.reload.usage=/reload -devmine.command.reload.reloading=重新读取服务器... -devmine.command.reload.reloaded=重新读取完成 - -devmine.command.lvdat.description=修改地图属性 -devmine.command.lvdat.changed=对地图{%0}的{%1}属性修改已保存,部分属性可能需要重启服务器后生效。 -devmine.command.lvdat.fixname=已修复地图{%0}的名字,建议重启服务器。 -devmine.command.lvdat.nofound=地图{%0}没有创建或者加载失败。 -devmine.command.lvdat.preset=生成器选项(预设) - -devmine.command.status.description=重新读取服务器的性能。 -devmine.command.status.usage=/status - -devmine.command.status.title=服务器状态 -devmine.command.status.player=服务器人数: -devmine.command.status.days=天 -devmine.command.status.hours=小时 -devmine.command.status.minutes=分 -devmine.command.status.seconds=秒 -devmine.command.status.uptime=运行时间: -devmine.command.status.AverageTPS=平均TPS: -devmine.command.status.CurrentTPS=瞬时TPS: -devmine.command.status.Networkupload=网络上传: -devmine.command.status.Networkdownload=网络下载: -devmine.command.status.Threadcount=线程总数: -devmine.command.status.Mainmemory=线程总数: -devmine.command.status.Totalmemory=总内存: -devmine.command.status.Totalvirtualmemory=总虚拟内存: -devmine.command.status.Heapmemory=堆栈内存: -devmine.command.status.Maxmemorysystem=系统最大内存: -devmine.command.status.Maxmemorymanager=核心全局最大内存: -devmine.command.status.World=世界 -devmine.command.status.chunks=区块, -devmine.command.status.entities=实体, -devmine.command.status.solidentities=solidentities. -devmine.command.status.Time=时间 -devmine.command.status.ms=毫秒 - -devmine.command.gc.description=回收垃圾 -devmine.command.gc.usage=/gc -devmine.command.gc.title=垃圾回收结果 -devmine.command.gc.chunks=区块: -devmine.command.gc.entities=实体: -devmine.command.gc.solidentities=方块: -devmine.command.gc.cycles=循环: -devmine.command.gc.memory=内存释放: - -devmine.command.biome.description=设置指定地图生物群系 -devmine.command.biome.posset=已设置第{%3}个坐标为:({%1},{%2})[{%0}] -devmine.command.biome.get=您所在的生物群系id为:{%0} 颜色值为:{%1},{%2},{%3} -devmine.command.biome.wrongLev=不能跨地图设置取点。 -devmine.command.biome.wrongBio=错误的生物群系ID,请输入数字ID(1=草原,2=沙漠,13=雪山,6=沼泽) -devmine.command.biome.wrongCol=错误的生物群系颜色,例如 146,188,89 可以使用 /biome get 获取 -devmine.command.biome.noPos=请先通过 /biome pos1|pos2 设定范围 -devmine.command.biome.set=已成功设置生物群系为:{%0} -devmine.command.biome.color=已成功设置生态颜色为:{%0},{%1},{%2} - -devmine.command.timings.description=纪录计时数据,以检视服务器的性能。 -devmine.command.timings.usage=/timings -devmine.command.timings.enable=启用定时和重启 -devmine.command.timings.disable=停用定时 -devmine.command.timings.timingsDisabled=启用定时工具透过 /timings on -devmine.command.timings.reset=定时重启 -devmine.command.timings.pasteError=已记录在事件记录文件中 -devmine.command.timings.timingsUpload=计时数据已被上载至 {%0} -devmine.command.timings.timingsRead=你可以在 {%0} 阅读计时结果 -devmine.command.timings.timingsWrite=计时数据已被储存至 {%0} -devmine.command.version.description=检视此服务器 (及其使用的插件) 的版本 -devmine.command.version.usage=/version [插件名称] -devmine.command.version.noSuchPlugin=该服务器没有运行任何叫这个名称的插件。使用 /plugins 来获得插件列表。 -devmine.command.give.description=给指定玩家一定数量的物品 -devmine.command.give.usage=/give <玩家名称> <项目[:损毁程度]> [数量] -devmine.command.kill.description=自杀或杀死其他玩家 -devmine.command.kill.usage=/kill [玩家名称] -devmine.command.particle.description=加入粒子效果至世界 -devmine.command.particle.usage=/particle <玩家名称> [数量] [数据值] -devmine.command.time.description=更改每个世界的时间 -devmine.command.time.usage=/time <数值> 或 /time -devmine.command.bancidbyname.description=禁止指定玩家的设备 ID -devmine.command.bancid.description=禁止指定的设备 ID -devmine.command.banipbyname.description=禁止指定玩家的 IP -devmine.command.ban.player.description=禁止指定的玩家使用此服务器 -devmine.command.ban.ip.description=禁止指定的 IP 地址使用此服务器 -devmine.command.banlist.description=查看来自该服务器禁止的所有玩家 -devmine.command.defaultgamemode.description=设定默认的游戏模式 -devmine.command.deop.description=移除指定玩家的管理员权限 -devmine.command.difficulty.description=设定游戏的难易度 -devmine.command.enchant.description=把物件附魔 -devmine.command.effect.description=增加/减少玩家身上的效果 -devmine.command.gamemode.description=改变玩家到一个特定的游戏模式 -devmine.command.help.description=显示帮助列表 -devmine.command.kick.description=从服务器中删除指定玩家 -devmine.command.list.description=显示在线玩家列表 -devmine.command.me.description=于聊天中作出指定的动作 -devmine.command.op.description=赋予指定玩家管理员权限 -devmine.command.unban.cid.description=允许指定 CID 使用此服务器 -devmine.command.unban.player.description=允许指定玩家使用此服务器 -devmine.command.unban.ip.description=允许指定 IP 地址使用此服务器 -devmine.command.save.description=储存服务器到磁盘上 -devmine.command.saveoff.description=停用自动储存服务器 -devmine.command.saveon.description=启用自动储存服务器 -devmine.command.say.description=以发送指令者身份广播指定的讯息 -devmine.command.seed.description=显示世界种子码 -devmine.command.setworldspawn.description=设定一个世界重生点。未指定坐标,将使用玩家的坐标。 -devmine.command.spawnpoint.description=设定玩家重生点 -devmine.command.stop.description=关闭服务器 -devmine.command.tp.description=传送指定玩家(或是自己)到另一位玩家或坐标 -devmine.command.tell.description=传送私讯给指定玩家 -devmine.command.xp.description=给指定玩家增加经验值或等级 -devmine.command.summon.description=召唤指定的实体于玩家位置或指定位置 -devmine.command.setblock.description=将一个方块更改为另一个方块 -devmine.command.weather.description=设置指定地图的天气 -devmine.command.weather.usage=/weather <世界名 天气值|天气值> -devmine.command.weather.changed=成功设置世界{%0}的天气! -devmine.command.weather.noregistered=世界{%0}没有注册到天气管理器! -devmine.command.weather.invalid=无效的天气!请输入天气类型 0,1,2,3 -devmine.command.weather.wrong=缺少参数! -devmine.command.weather.invalid.level=错误的地图名 - -devmine.command.whitelist.description=管理员允许使用此服务器的玩家列表 -devmine.crash.create=一个未知的错误发生了,使服务器崩溃。正在储存错误报告。 -devmine.crash.error=未能储存错误报告∶{%0} -devmine.crash.submit=请上载档案“{%0}”至在线崩溃储存库。请尽量提供更多数据。 -devmine.crash.archive=错误报告已经上传到在线崩溃储存库。你可以在{%0} 查看到它或使用ID #{%1}。 -devmine.debug.enable=启用 LevelDB 支援 -devmine.player.invalidMove={%0} 行动可疑! -devmine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] logged in with entity id {%4} at ({%5}, {%6}, {%7}, {%8}) -devmine.player.logOut={%0}[/{%1}:{%2}] logged out due to {%3} -devmine.player.transferred={%0}[/{%1}:{%2}] 被传送到了 {%3} -devmine.player.invalidEntity={%0} 尝试攻击一个无效的实体 -devmine.plugin.load=读取中... {%0} -devmine.plugin.enable=开启中... {%0} -devmine.plugin.disable=关闭中... {%0} -devmine.plugin.restrictedName=受限的名称 -devmine.plugin.incompatibleAPI=不兼容的API版本 -devmine.plugin.unknownDependency=本插件无法单独使用 -devmine.plugin.circularDependency=检测出循环依赖 -devmine.plugin.genericLoadError=无法读取插件 '{%0}' -devmine.plugin.spacesDiscouraged=插件 '{%0}' 在名称中使用了空格,不建议这样做 -devmine.plugin.loadError=无法读取插件 '{%0}':{%1} -devmine.plugin.duplicateError=无法读取插件 '{%0}':已有相同插件 -devmine.plugin.fileError=无法读取在 '{%1}' 文件夹中的 '{%0}':{%2} -devmine.plugin.commandError=无法读取 {%1} 插件的 {%0} 指令 -devmine.plugin.aliasError=无法读取 {%1} 插件的 {%0} 别名 -devmine.plugin.deprecatedEvent=插件 '{%0}' 已经使用 '{%2}' 方法注册了一个在 '{%1}' 的监听器,但是该事件已过时。 -devmine.plugin.eventError="无法处理事件 '{%0}' 至 '{%1}':{%2} 在 {%3} 上" +# -------------------- DevMine language files, only for console -------------------- +DevMine.data.playerNotFound=无法找到玩家数据 "{%0}",创建新的配置文件 +DevMine.data.playerCorrupted=发现损坏的数据 "{%0}",创建新的配置文件 +DevMine.data.playerOld=发现旧的玩家数据 "{%0}",更新配置文件 +DevMine.data.saveError=无法储存 "{%0}" 的玩家数据:{%1} +DevMine.level.notFound=无法找到 "{%0}" 地图 +DevMine.level.loadError=无法读取地图 "{%0}":{%1} +DevMine.level.generationError=无法产生地图 "{%0}":{%1} +DevMine.level.tickError=计算地图“{%0}”时出现错误∶{%1} +DevMine.level.chunkUnloadError=移除一个区块时发生错误:{%0} +DevMine.level.backgroundGeneration=正在于背景生成世界 “{%0}“ 的地形 +DevMine.level.defaultError=没有读取预设的地图 +DevMine.level.preparing=准备地图中... "{%0}" +DevMine.level.unloading=正在移除地图 "{%0}" +DevMine.server.start=正在启动支持 Minecraft:PE {%0} 版本的服务器 +DevMine.server.networkError=[网络] 停止接口 {%0} 由于 {%1} +DevMine.server.networkStart=正在启动服务器在 {%0}:{%1} +DevMine.server.info=此服务器正在运作 {%0} {%1} 版本 "{%2}" (API {%3}) + +DevMine.server.info.extended=此服务器正在运作 {%0} {%1} “{%2}” 执行 API 版本 {%3} 支持 Minecraft:PE {%4} (协议版本 {%5}) +DevMine.server.info.extended1=本服务器正运行 {%0}{%1} (代号 "{%2}") +DevMine.server.info.extended2=PHP 版本: {%0} +DevMine.server.info.extended3=API: {%0} (iTX API 版本 {%1}) +DevMine.server.info.extended4=客户端: Minecraft PE {%0} (protocol 版本 + +DevMine.server.license={%0} 根据 LGPL 许可发布 +DevMine.server.tickOverload=注意!服务器有超载的可能 +DevMine.server.startFinished=Done ({%0}s)!如需帮助,请输入 "help" 或 "?" +DevMine.server.defaultGameMode=预设的游戏类型:{%0} +DevMine.server.query.start=启动 GS4 状态监听器 +DevMine.server.query.info=设定 query 接口到 {%0} +DevMine.server.query.running=Query 运作在 {%0}:{%1} + +DevMine.command.alias.illegal=不能注册别名 {%0},因为它包含非法字符 +DevMine.command.alias.notFound=未能登记别称 {%0} ,因为它包含不存在的指令: {%1} +DevMine.command.exception=于 {%1} 执行指令 “{%0}“ 时,出现了未被处理的错误: {%2} + +DevMine.commands.cave.usage=/cave <旋转角度> <洞穴长度> <分叉数> <洞穴强度> | /cave getmypos +DevMine.commands.cave.info=旋转角度:{%0} 洞穴长度:{%1} 分叉数:{%2} 洞穴强度:{%3} +DevMine.commands.cave.start=开始生成矿洞,可能需要较多时间 +DevMine.commands.cave.success=矿洞生成完毕啦 + +DevMine.command.plugins.description=获取在服务器上运行的插件列表 +DevMine.command.plugins.success=插件 ({%0}):{%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=重新读取服务器设定和插件 +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=重新读取服务器... +DevMine.command.reload.reloaded=重新读取完成 + +DevMine.command.lvdat.description=修改地图属性 +DevMine.command.lvdat.changed=对地图{%0}的{%1}属性修改已保存,部分属性可能需要重启服务器后生效。 +DevMine.command.lvdat.fixname=已修复地图{%0}的名字,建议重启服务器。 +DevMine.command.lvdat.nofound=地图{%0}没有创建或者加载失败。 +DevMine.command.lvdat.preset=生成器选项(预设) + +DevMine.command.status.description=重新读取服务器的性能。 +DevMine.command.status.usage=/status + +DevMine.command.status.title=服务器状态 +DevMine.command.status.player=服务器人数: +DevMine.command.status.days=天 +DevMine.command.status.hours=小时 +DevMine.command.status.minutes=分 +DevMine.command.status.seconds=秒 +DevMine.command.status.uptime=运行时间: +DevMine.command.status.AverageTPS=平均TPS: +DevMine.command.status.CurrentTPS=瞬时TPS: +DevMine.command.status.Networkupload=网络上传: +DevMine.command.status.Networkdownload=网络下载: +DevMine.command.status.Threadcount=线程总数: +DevMine.command.status.Mainmemory=线程总数: +DevMine.command.status.Totalmemory=总内存: +DevMine.command.status.Totalvirtualmemory=总虚拟内存: +DevMine.command.status.Heapmemory=堆栈内存: +DevMine.command.status.Maxmemorysystem=系统最大内存: +DevMine.command.status.Maxmemorymanager=核心全局最大内存: +DevMine.command.status.World=世界 +DevMine.command.status.chunks=区块, +DevMine.command.status.entities=实体, +DevMine.command.status.tiles=tiles. +DevMine.command.status.Time=时间 +DevMine.command.status.ms=毫秒 + +DevMine.command.gc.description=回收垃圾 +DevMine.command.gc.usage=/gc +DevMine.command.gc.title=垃圾回收结果 +DevMine.command.gc.chunks=区块: +DevMine.command.gc.entities=实体: +DevMine.command.gc.tiles=方块: +DevMine.command.gc.cycles=循环: +DevMine.command.gc.memory=内存释放: + +DevMine.command.biome.description=设置指定地图生物群系 +DevMine.command.biome.posset=已设置第{%3}个坐标为:({%1},{%2})[{%0}] +DevMine.command.biome.get=您所在的生物群系id为:{%0} 颜色值为:{%1},{%2},{%3} +DevMine.command.biome.wrongLev=不能跨地图设置取点。 +DevMine.command.biome.wrongBio=错误的生物群系ID,请输入数字ID(1=草原,2=沙漠,13=雪山,6=沼泽) +DevMine.command.biome.wrongCol=错误的生物群系颜色,例如 146,188,89 可以使用 /biome get 获取 +DevMine.command.biome.noPos=请先通过 /biome pos1|pos2 设定范围 +DevMine.command.biome.set=已成功设置生物群系为:{%0} +DevMine.command.biome.color=已成功设置生态颜色为:{%0},{%1},{%2} + +DevMine.command.timings.description=纪录计时数据,以检视服务器的性能。 +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=启用定时和重启 +DevMine.command.timings.disable=停用定时 +DevMine.command.timings.timingsDisabled=启用定时工具透过 /timings on +DevMine.command.timings.reset=定时重启 +DevMine.command.timings.pasteError=已记录在事件记录文件中 +DevMine.command.timings.timingsUpload=计时数据已被上载至 {%0} +DevMine.command.timings.timingsRead=你可以在 {%0} 阅读计时结果 +DevMine.command.timings.timingsWrite=计时数据已被储存至 {%0} +DevMine.command.version.description=检视此服务器 (及其使用的插件) 的版本 +DevMine.command.version.usage=/version [插件名称] +DevMine.command.version.noSuchPlugin=该服务器没有运行任何叫这个名称的插件。使用 /plugins 来获得插件列表。 +DevMine.command.give.description=给指定玩家一定数量的物品 +DevMine.command.give.usage=/give <玩家名称> <项目[:损毁程度]> [数量] +DevMine.command.kill.description=自杀或杀死其他玩家 +DevMine.command.kill.usage=/kill [玩家名称] +DevMine.command.particle.description=加入粒子效果至世界 +DevMine.command.particle.usage=/particle <玩家名称> [数量] [数据值] +DevMine.command.time.description=更改每个世界的时间 +DevMine.command.time.usage=/time <数值> 或 /time +DevMine.command.bancidbyname.description=禁止指定玩家的设备 ID +DevMine.command.bancid.description=禁止指定的设备 ID +DevMine.command.banipbyname.description=禁止指定玩家的 IP +DevMine.command.ban.player.description=禁止指定的玩家使用此服务器 +DevMine.command.ban.ip.description=禁止指定的 IP 地址使用此服务器 +DevMine.command.banlist.description=查看来自该服务器禁止的所有玩家 +DevMine.command.defaultgamemode.description=设定默认的游戏模式 +DevMine.command.deop.description=移除指定玩家的管理员权限 +DevMine.command.difficulty.description=设定游戏的难易度 +DevMine.command.enchant.description=把物件附魔 +DevMine.command.effect.description=增加/减少玩家身上的效果 +DevMine.command.gamemode.description=改变玩家到一个特定的游戏模式 +DevMine.command.help.description=显示帮助列表 +DevMine.command.kick.description=从服务器中删除指定玩家 +DevMine.command.list.description=显示在线玩家列表 +DevMine.command.me.description=于聊天中作出指定的动作 +DevMine.command.op.description=赋予指定玩家管理员权限 +DevMine.command.unban.cid.description=允许指定 CID 使用此服务器 +DevMine.command.unban.player.description=允许指定玩家使用此服务器 +DevMine.command.unban.ip.description=允许指定 IP 地址使用此服务器 +DevMine.command.save.description=储存服务器到磁盘上 +DevMine.command.saveoff.description=停用自动储存服务器 +DevMine.command.saveon.description=启用自动储存服务器 +DevMine.command.say.description=以发送指令者身份广播指定的讯息 +DevMine.command.seed.description=显示世界种子码 +DevMine.command.setworldspawn.description=设定一个世界重生点。未指定坐标,将使用玩家的坐标。 +DevMine.command.spawnpoint.description=设定玩家重生点 +DevMine.command.stop.description=关闭服务器 +DevMine.command.tp.description=传送指定玩家(或是自己)到另一位玩家或坐标 +DevMine.command.tell.description=传送私讯给指定玩家 +DevMine.command.xp.description=给指定玩家增加经验值或等级 +DevMine.command.summon.description=召唤指定的实体于玩家位置或指定位置 +ocketmine.command.fill.description=填充了指定方块 +DevMine.command.setblock.description=将一个方块更改为另一个方块 + +DevMine.command.weather.description=设置指定地图的天气 +DevMine.command.weather.usage=/weather <世界名 天气值|天气值> +DevMine.command.weather.changed=成功设置世界{%0}的天气! +DevMine.command.weather.noregistered=世界{%0}没有注册到天气管理器! +DevMine.command.weather.invalid=无效的天气!请输入天气类型 0,1,2,3 +DevMine.command.weather.wrong=缺少参数! +DevMine.command.weather.invalid.level=错误的地图名 + +DevMine.command.whitelist.description=管理员允许使用此服务器的玩家列表 +DevMine.crash.create=一个未知的错误发生了,使服务器崩溃。正在储存错误报告。 +DevMine.crash.error=未能储存错误报告∶{%0} +DevMine.crash.submit=请上载档案“{%0}”至在线崩溃储存库。请尽量提供更多数据。 +DevMine.crash.archive=错误报告已经上传到在线崩溃储存库。你可以在{%0} 查看到它或使用ID #{%1}。 +DevMine.debug.enable=启用 LevelDB 支援 +DevMine.player.invalidMove={%0} 行动可疑! +DevMine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] logged in with entity id {%4} at ({%5}, {%6}, {%7}, {%8}) +DevMine.player.logOut={%0}[/{%1}:{%2}] logged out due to {%3} +DevMine.player.transferred={%0}[/{%1}:{%2}] 被传送到了 {%3} +DevMine.player.invalidEntity={%0} 尝试攻击一个无效的实体 +DevMine.plugin.load=读取中... {%0} +DevMine.plugin.enable=开启中... {%0} +DevMine.plugin.disable=关闭中... {%0} +DevMine.plugin.restrictedName=受限的名称 +DevMine.plugin.incompatibleAPI=不兼容的API版本 +DevMine.plugin.unknownDependency=本插件无法单独使用 +DevMine.plugin.circularDependency=检测出循环依赖 +DevMine.plugin.genericLoadError=无法读取插件 '{%0}' +DevMine.plugin.spacesDiscouraged=插件 '{%0}' 在名称中使用了空格,不建议这样做 +DevMine.plugin.loadError=无法读取插件 '{%0}':{%1} +DevMine.plugin.duplicateError=无法读取插件 '{%0}':已有相同插件 +DevMine.plugin.fileError=无法读取在 '{%1}' 文件夹中的 '{%0}':{%2} +DevMine.plugin.commandError=无法读取 {%1} 插件的 {%0} 指令 +DevMine.plugin.aliasError=无法读取 {%1} 插件的 {%0} 别名 +DevMine.plugin.deprecatedEvent=插件 '{%0}' 已经使用 '{%2}' 方法注册了一个在 '{%1}' 的监听器,但是该事件已过时。 +DevMine.plugin.eventError="无法处理事件 '{%0}' 至 '{%1}':{%2} 在 {%3} 上" diff --git a/src/devmine/utilities/languages/locale/deu.ini b/src/devmine/utilities/languages/locale/deu.ini new file mode 100644 index 0000000..b4c0204 --- /dev/null +++ b/src/devmine/utilities/languages/locale/deu.ini @@ -0,0 +1,411 @@ +# Language file compatible with Minecraft: Pocket Edition identifiers +# +# A message doesn't need to be there to be shown correctly on the client. +# Only messages shown in DevMine itself need to be here + +language.name=Deutsch +language.selected={%0} ({%1}) als Basissprache ausgewählt + +multiplayer.player.joined={%0} hat das Spiel betreten +multiplayer.player.left={%0} hat das Spiel verlassen + +chat.type.text={%0} : {%1} +chat.type.emote=* {%0} {%1} +chat.type.announcement=[{%0}] {%1} +chat.type.admin=[{%0}: {%1}] +chat.type.achievement={%0} hat gerade den Erfolg {%1} erzielt + +disconnectionScreen.notAuthenticated=Xbox Anmeldung notwendig +disconnectionScreen.outdatedClient=Veralteter Client! +disconnectionScreen.outdatedServer=Veralteter Server! +disconnectionScreen.serverFull=Server ist voll! +disconnectionScreen.noReason=Verbindung zum Server getrennt +disconnectionScreen.invalidSkin=Ungültiger Skin! +disconnectionScreen.invalidName=Ungültiger Name! + +death.fell.accident.generic={%0} fiel aus zu großer Höhe +death.attack.inFire={%0} ging in Flammen auf +death.attack.onFire={%0} verbrannte +death.attack.lava={%0} versuchte in Lava zu schwimmen +death.attack.inWall={%0} wurde lebendig begraben +death.attack.drown={%0} ertrank +death.attack.cactus={%0} wurde zu Tode gestochen +death.attack.generic={%0} starb +death.attack.explosion={%0} wurde in die Luft gesprengt +death.attack.explosion.player={%0} wurde durch {%1} in die Luft gesprengt +death.attack.magic={%0} wurde durch Magie getötet +death.attack.wither={%0} verdorrte +death.attack.mob={%0} wurde von {%1} erschlagen +death.attack.player={%0} wurde von {%1} erschlagen +death.attack.player.item={%0} wurde von {%1} mit {%2} erschlagen +death.attack.arrow={%0} wurde von {%1} erschossen +death.attack.arrow.item={%0} wurde von {%1} mit {%2} erschossen +death.attack.fall={%0} fiel der Schwerkraft zum Opfer +death.attack.outOfWorld={%0} fiel aus der Welt + +gameMode.survival=Überlebensmodus +gameMode.creative=Kreativmodus +gameMode.adventure=Abenteuermodus +gameMode.spectator=Zuschauermodus +gameMode.changed=Dein Spielmodus wurde aktualisiert + +potion.moveSpeed=Schnelligkeit +potion.moveSlowdown=Langsamkeit +potion.digSpeed=Eile +potion.digSlowDown=Langsames Abbauen +potion.damageBoost=Stärke +potion.heal=Direktheilung +potion.harm=Direktschaden +potion.jump=Sprungkraft +potion.confusion=Übelkeit +potion.regeneration=Regeneration +potion.resistance=Resistenz +potion.fireResistance=Feuerresistenz +potion.waterBreathing=Unterwasser-Atmung +potion.invisibility=Unsichtbarkeit +potion.blindness=Blindheit +potion.nightVision=Nachtsicht +potion.hunger=Hunger +potion.weakness=Schwäche +potion.poison=Gift +potion.wither=Dürre +potion.healthBoost=Lebenserweiterung +potion.absorption=Absorption +potion.saturation=Sättigung + +commands.generic.exception=Ein unbekannter Fehler trat auf, während versucht wurde, diesen Befehl auszufüren +commands.generic.permission=Du hast keine Berechtigung, diesen Befehl auszuführen +commands.generic.notFound=Unbekannter Befehl. Versuche /help für eine Liste von Befehlen +commands.generic.player.notFound=Dieser Spieler kann nicht gefunden werden +commands.generic.usage=Aufruf: {%0} +commands.generic.level=Weltname +commands.generic.seed=Startwert +commands.generic.name=Name +commands.generic.generator=Generator +commands.generic.opt.missing=Notwendige Eigenschaft fehlt, bitte überprüfen und neu eingeben. +commands.generic.runingame=Dieser Befehl kann nur im Spiel ausgeführt werden. + +commands.time.added={%0} zur Zeit hinzugefügt +commands.time.set=Setzte die Zeit auf {%0} +commands.time.query=Zeit: {%0} + +commands.me.usage=/me + +commands.give.item.notFound=Es gibt kein Item mit dem Namen {%0} +commands.give.success={%0} * {%1} an {%2} gegeben +commands.give.tagError=Parsen des Datatags fehlgeschlagen: {%0} + +commands.effect.usage=/effect [Sekunden] [Verstärker] [versteckePartikel] ODER /effect clear +commands.effect.notFound=Es gibt keinen Mob-Effekt mit der ID {%0} +commands.effect.success={%0} (ID {%1}) * {%2} für {%4} Sekunden an {%3} gegeben +commands.effect.success.removed={%0} von {%1} genommen +commands.effect.success.removed.all=Alle Effekte von {%0} genommen +commands.effect.failure.notActive=Konnte {%0} nicht von {%1} nehmen, da der Effekt nicht vorhanden war +commands.effect.failure.notActive.all=Konnte keinen Effekt von {%0} nehmen, da kein Effekt vorhanden war + +commands.enchant.noItem=Dieser Spieler hält keinen Gegenstand +commands.enchant.notFound=Es gibt keine Verzauberung mit der ID {%0} +commands.enchant.success=Verzauberung erfolgreich +commands.enchant.cantEnchant=Die gewählte Verzauberung kann diesem Gegenstand nicht hinzugefügt werden. +commands.enchant.usage=/enchant [Level] +commands.particle.success=Erzeuge {%1}-fach den Partikeleffekt {%0} +commands.particle.notFound=Unbekannter Partikeleffekt {%0} +commands.players.usage=/list +commands.players.list=Es sind {%0}/{%1} Spieler online: +commands.kill.successful={%0} wurde getötet +commands.banlist.ips=Es sind insgesamt {%0} IP-Adressen gebannt: +commands.banlist.players=Es sind insgesamt {%0} Spieler gebannt: +commands.banlist.cids=Es sind insgesamt {%0} CIDs gebannt: +commands.banlist.usage=/banlist [ips|players|cids] +commands.defaultgamemode.usage=/defaultgamemode +commands.defaultgamemode.success=Der Standart-Spielmodus der Welt ist jetzt {%0} + +commands.op.success={%0} wurde zum Operator ernannt +commands.op.usage=/op + +commands.deop.success={%0} ist jetzt kein Operator mehr +commands.deop.usage=/deop + +commands.say.usage=/say + +commands.seed.usage=/seed +commands.seed.success=Startwert: {%0} + +commands.bancidbyname.success=CID des Spielers {%0} wurde gebannt +commands.bancidbyname.usage=/bancidbyname + +commands.bancid.success=CID {%0} wurde gebannt +commands.bancid.usage=/bancid + +commands.unbancid.usage=/pardoncid +commands.unbancid.success=CID {%0} wurde entbannt + +commands.ban.success=Spieler {%0} wurde gebannt +commands.ban.usage=/ban [Grund ...] [Zeit(Tag)] + +commands.unban.success=Spieler {%0} wurde entbannt +commands.unban.usage=/pardon + +commands.banip.invalid=Du hast eine ungültige IP-Adresse angegeben oder einen Spieler, der nicht online ist +commands.banip.success=IP-Adresse {%0} wurde gebannt +commands.banip.success.players=IP-Adresse {%0}, die zu {%1} gehört, wurde gebannt +commands.banip.usage=/ban-ip [Grund ...] + +commands.unbanip.invalid=Du hast eine ungültige IP-Adresse angegeben +commands.unbanip.success=IP-Adresse {%0} wurde entbannt +commands.unbanip.usage=/pardon-ip + +commands.banipbyname.success=IP-Adresse des Spielers {%0} wurde gebannt +commands.banipbyname.usage=/banipbyname + +commands.save.usage=/save-all +commands.save-on.usage=/save-on +commands.save-off.usage=/save-off +commands.save.enabled=Automatische Welt-Speicherung aktiviert +commands.save.disabled=Automatische Welt-Speicherung deaktiviert +commands.save.start=Speichern... +commands.save.success=Welt wurde gespeichert + +commands.setblock.usage=/setblock [Schaden] +command.setblock.invalidBlock=Blockname/ID ist ungültig + +commands.stop.usage=/stop +commands.stop.start=Server wird beendet + +commands.kick.success={%0} wurde aus dem Spiel geworfen +commands.kick.success.reason={%0} wurde aus dem Spielgeworfen: '{%1}' +commands.kick.usage=/kick [Grund ...] + +commands.tp.success={%0} wurde zu {%1} teleportiert +commands.tp.success.coordinates={%0} wurde zu {%1}, {%2}, {%3} teleportiert +commands.tp.usage=/tp [Spieler] ODER /tp [Spieler] [ ] + +commands.whitelist.list=Es sind insgesamt {%0} (von {%1} hier gewesenen) Spieler in der Whitelist: +commands.whitelist.enabled=Whitelist aktiviert +commands.whitelist.disabled=Whitelist deaktiviert +commands.whitelist.reloaded=Whitelist neu eingelesen +commands.whitelist.add.success={%0} zur Whitelist hinzugefügt +commands.whitelist.add.usage=/whitelist add +commands.whitelist.remove.success={%0} von der Whitelist entfernt +commands.whitelist.remove.usage=/whitelist remove +commands.whitelist.usage=/whitelist + +commands.gamemode.success.self=Eigenen Spielmodus auf {%2} gesetzt +commands.gamemode.success.other={%1}'s Spielmodus auf {%2} gesetzt +commands.gamemode.usage=/gamemode [Spieler] +commands.help.header=--- Zeige Hilfe-Seite {%0} von {%1} (/help ) --- +commands.help.usage=/help [Seite|Befehl] +commands.message.usage=/tell +commands.message.sameTarget=Du kannst keine private Nachricht an dich selbst schicken! + +commands.difficulty.usage=/difficulty +commands.difficulty.success=Schwierigkeitsgrad auf {%0} gesetzt + +commands.spawnpoint.usage=/spawnpoint [Spieler] [ ] +commands.spawnpoint.success={%0}'s Spawnpunkt wurde auf ({%1}, {%2}, {%3}) gesetzt +commands.setworldspawn.usage=/setworldspawn [ ] +commands.setworldspawn.success=Der Welt-Spawn wurde auf ({%0}, {%1}, {%2}) gesetzt + +commands.summon.usage=/summon [Entity] [ ] [NBTTag] + +commands.xp.failure.withdrawXp=Einem Spieler können keine negativen Erfahrungspunkte gegeben werden +commands.xp.success={%0} Erfahrungspunkte an Spieler {%1} gegeben +commands.xp.success.levels={%0} Level Erfahrung an {%1} gegeben +commands.xp.success.negative.levels={%0} Level Erfahrung von {%1} genommen +commands.xp.usage=/xp [Spieler] ODER /xp L [Spieler] + +# -------------------- DevMine language files, only for console -------------------- +DevMine.data.playerNotFound=Keine Spielerdaten für "{%0}" gefunden, erstelle neues Profil +DevMine.data.playerCorrupted=Defekte Daten für Spieler "{%0}" gefunden, erstelle neues Profil +DevMine.data.playerOld=Alte Spielerdaten für "{%0}" gefunden, aktualisiere Profil +DevMine.data.saveError=Konnte Spieler "{%0}" nicht speichern: {%1} +DevMine.level.notFound=Welt "{%0}" nicht gefunden +DevMine.level.loadError=Welt "{%0}" konnte nicht geladen werden: {%1} +DevMine.level.generationError=Welt "{%0}" konnte nicht generiert werden: {%1} +DevMine.level.tickError=Welt "{%0}" konnte nicht getickt werden: {%1} +DevMine.level.chunkUnloadError=Fehler beim Entladen eines Chunks: {%0} +DevMine.level.backgroundGeneration=Spawn-Landschaft wird für die Welt "{%0}" im Hintergrund generiert +DevMine.level.defaultError=Es wurde keine Standard-Welt geladen +DevMine.level.preparing=Welt "{%0}" wird vorbereitet +DevMine.level.unloading=Welt "{%0}" wird entladen +DevMine.server.start=Starte Minecraft: PE server version {%0} +DevMine.server.networkError=[Netzwerk] Schnittstelle {%0} wurde wegen {%1} beendet +DevMine.server.networkStart=Öffne Server auf {%0}:{%1} +DevMine.server.info=Dieser Server läuft mit Version {%0}{%1} "{%2}" (API {%3}) + +DevMine.server.info.extended.title=-----Server Information----- +DevMine.server.info.extended1=Dieser Server läuft mit Version {%0}{%1} (Codename "{%2}") +DevMine.server.info.extended2=PHP Version: {%0} +DevMine.server.info.extended3=API: {%0} (iTX API Version {%1}) +DevMine.server.info.extended4=Zielclient: Minecraft PE {%0} (Protokollversion {%1}) + +DevMine.server.license={%0} wurde unter der GPL Lizenz Version 3 und neuer herausgegeben +DevMine.server.tickOverload=Server kann nicht mehr am Laufen gehalten werden! Ist der Server überladen? +DevMine.server.startFinished=Fertig ({%0}s)! Für Hilfe kannst du "help" oder "?" eingeben +DevMine.server.defaultGameMode=Standard-Spielmodus: {%0} +DevMine.server.query.start=Starte GS4 Status-Listener +DevMine.server.query.info=Setze Query-Port auf {%0} +DevMine.server.query.running=Query läuft auf {%0}:{%1} + +DevMine.command.alias.illegal=Alias {%0} konnte nicht registriert werden, da er unzulässige Zeichen enthält +DevMine.command.alias.notFound=Alias {%0} konnte nicht registriert werden, da er Befehle enthält, die nicht existieren: {%1} +DevMine.command.exception=Unbehandelte Ausnahme bei Ausführung des Befehls '{%0}' in {%1}: {%2} + +DevMine.commands.cave.usage=/cave | /cave getmypos +DevMine.commands.cave.info=Rotationswinkel:{%0} Länge:{%1} Abzweigungen:{%2} Stärke:{%3} +DevMine.commands.cave.start=Höhle wird generiert, bitte warten +DevMine.commands.cave.success=Höhle wurde generiert + +DevMine.command.plugins.description=Zeigt eine Liste aller auf dem Server laufenden Plugins +DevMine.command.plugins.success=Plugins ({%0}): {%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=Lädt die Serverkonfiguration und Plugins neu ein +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=Server wird neu geladen... +DevMine.command.reload.reloaded=Neuladen des Servers abgeschlossen + +DevMine.command.lvdat.description=Ändert die Eigenschaften einer Welt. +DevMine.command.lvdat.changed={%1} der Welt "{%0}" wurde geändert, manche Änderungen erfordern einen Neustart deines Servers. +DevMine.command.lvdat.fixname=Fixname erfolgreich für die Welt "{%0}" abgeschlossen, manche Änderungen erfordern einen Neustart deines Servers. +DevMine.command.lvdat.nofound=Die Welt "{%0}" wurde nicht gefunden oder konnte nicht geladen werden. +DevMine.command.lvdat.preset=Generator Einstellungen (Vorlagen) + +DevMine.command.status.description=Zeigt die aktuelle Serverauslastung an. +DevMine.command.status.usage=/status + +DevMine.command.status.title=Server-Status +DevMine.command.status.player=Spieleranzahl: +DevMine.command.status.days=Tage +DevMine.command.status.hours=Stunden +DevMine.command.status.minutes=Minuten +DevMine.command.status.seconds=Sekunden +DevMine.command.status.uptime=Laufzeit: +DevMine.command.status.AverageTPS=Durchschnittliche TPS: +DevMine.command.status.CurrentTPS=Aktuelle TPS: +DevMine.command.status.Networkupload=Netzwerk Upload: +DevMine.command.status.Networkdownload=Netzwerk Download: +DevMine.command.status.Threadcount=Anzahl der Threads: +DevMine.command.status.Mainmemory=Speicher des Main-Threads: +DevMine.command.status.Totalmemory=Speicher gesamt: +DevMine.command.status.Totalvirtualmemory=Virtueller Speicher gesamt: +DevMine.command.status.Heapmemory=Heap-Speicher: +DevMine.command.status.Maxmemorysystem=Maximaler Speicher (System): +DevMine.command.status.Maxmemorymanager=Maximaler Speicher (Manager): +DevMine.command.status.World=Welt +DevMine.command.status.chunks=Chunks, +DevMine.command.status.entities=Entities, +DevMine.command.status.tiles=Tiles. +DevMine.command.status.Time=Zeit +DevMine.command.status.ms=ms + +DevMine.command.gc.description=Startet die Tasks zur automatischen Speicherbereinigung (garbage collection) +DevMine.command.gc.usage=/gc +DevMine.command.gc.title=Sammelbericht +DevMine.command.gc.chunks=Chunks: +DevMine.command.gc.entities=Entities: +DevMine.command.gc.tiles=Tiles: +DevMine.command.gc.cycles=Zyklen: +DevMine.command.gc.memory=Freigegebener Speicher: + +DevMine.command.biome.description=Ändert die Biome der Region.(um zu Schnee oder Regen zu wechseln) +DevMine.command.biome.posset=Position {%3} bei ({%1},{%2}) der Welt {%0} festgelegt. +DevMine.command.biome.get=Die ID des Bioms, in dem du gerade bist ist {%0}. Farbe: {%1},{%2},{%3} +DevMine.command.biome.wrongLev=Die Position kann nicht in unterschiedlichen Welten festgelegt werden. +DevMine.command.biome.wrongBio=Falsche Biom-ID - Beispiele: 1 (Prärie), 2 (Wüste),13 (Eisberge),6 (Sumpfland) +DevMine.command.biome.wrongCol=Falsche Farbe - Beispiel: 146,188,89. Nutze "/biome get" um eine andere Farbe zu erhalten. +DevMine.command.biome.noPos=Bitte nutze "/biome Pos1|Pos2", um zuerst den Bereich festzulegen. +DevMine.command.biome.set=Das Biom des ausgewähltes Bereichs wurde auf {%0} gesetzt. +DevMine.command.biome.color=Die Grasfarbe wurde auf {%0},{%1},{%2} gesetzt. + +DevMine.command.timings.description=Nimmt Zeitmessungen auf, um die Severauslastung zu ermitteln. +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=Timings & Reset aktiviert +DevMine.command.timings.disable=Timings deaktiviert +DevMine.command.timings.timingsDisabled=Bitte aktiviere die Timings, indem du '/timings on' eingibst +DevMine.command.timings.reset=Timings zurückgesetzt +DevMine.command.timings.pasteError=Während der Übernahme des Berichts trat ein Fehler auf +DevMine.command.timings.timingsUpload=Timings wurden hochgeladen zu {%0} +DevMine.command.timings.timingsRead=Du kannst dir die Ergebnisse hier anschauen {%0} +DevMine.command.timings.timingsWrite=Timings wurden gespeichert in {%0} +DevMine.command.version.description=Ermittelt die Version des Servers inklusive jedem verwendeten Plugin. +DevMine.command.version.usage=/version [Plugin-Name] +DevMine.command.version.noSuchPlugin=Auf diesem Server läuft kein Plugin mit diesem Namen. Mit /plugins kannst du dir eine Liste aller Plugins anzeigen lassen. +DevMine.command.give.description=Gibt dem angegebenen Spieler eine bestimmte Anzahl an Gegenständen (Items) +DevMine.command.give.usage=/give [Anzahl] [NBT-Daten...] +DevMine.command.kill.description=Tötet dich selbst oder andere Spieler +DevMine.command.kill.usage=/kill [Spieler] +DevMine.command.particle.description=Fügt einer Welt Partikel hinzu +DevMine.command.particle.usage=/particle [Anzahl] [Wert] +DevMine.command.time.description=Ändert in allen Welten die Zeit +DevMine.command.time.usage=/time ODER /time +DevMine.command.bancidbyname.description=Verhindet, dass sich die durch den Spielernamen ermittelte CID mit dem Server verbinden kann +DevMine.command.bancid.description=Verhindert, dass sich die angegebene CID mit dem Server verbinden kann +DevMine.command.banipbyname.description=Verhindet, dass sich die durch den Spielernamen ermittelte IP-Adresse mit dem Server verbinden kann +DevMine.command.ban.player.description=Verhindert, dass sich der angegebene Spieler mit dem Server verbinden kann +DevMine.command.ban.ip.description=Verhindert, dass sich die angegebene IP-Adresse mit dem Server verbinden kann +DevMine.command.banlist.description=Zeigt alle Spieler an, die von diesem Server gebannt wurden +DevMine.command.defaultgamemode.description=Legt den Standard-Spielmodus fest +DevMine.command.deop.description=Nimmt dem angegebenen Spieler den Operator-Status +DevMine.command.difficulty.description=Legt den Schwierigkeitsgrad des Spiels fest +DevMine.command.enchant.description=Fügt Gegenständen Verzauberungen hinzu +DevMine.command.effect.description=Fügt Spielern Effekte hinzu oder entfernt sie +DevMine.command.gamemode.description=Ändert den Spiemodus eines Spielers wie angegeben +DevMine.command.help.description=Zeigt das Hilfe-Menü an +DevMine.command.kick.description=Trennt den angegebenen Spieler vom Server +DevMine.command.list.description=Zeigt alle Spieler an, die gerade online sind +DevMine.command.me.description=Stellt die angegebene Aktion im Chat dar +DevMine.command.op.description=Gibt dem angegebenen Spieler den Operator-Status +DevMine.command.unban.cid.description=Erlaubt der angegebenen CID, sich wieder mit dem Server zu verbinden +DevMine.command.unban.player.description=Erlaubt dem angegebenen Spieler, sich wieder mit dem Server zu verbinden +DevMine.command.unban.ip.description=Erlaubt der angegebenen IP-Adresse, sich wieder mit dem Server zu verbinden +DevMine.command.save.description=Speichert den Server im Dateisystem +DevMine.command.saveoff.description=Deaktiviert das automatische Speichern des Servers +DevMine.command.saveon.description=Aktiviert das automatische Speichern des Servers +DevMine.command.say.description=Sendet die eingegebene Nachricht im Namen des Absenders an alle Spieler +DevMine.command.seed.description=Zeigt den Startwert (seed) der Welt +DevMine.command.setworldspawn.description=Legt den Spawnpunkt einer Welt fest. Werden keine Koordinaten angegeben, werden die des Spielers verwendet. +DevMine.command.spawnpoint.description=Legt den Spawnpunkt eines Spielers fest. +DevMine.command.stop.description=Beendet den Server +DevMine.command.tp.description=Teleportiert den angegebenen Spieler (oder dich selbst) zu einem anderen Spieler oder Koordinaten +DevMine.command.tell.description=Sendet dem angegebenen Spieler eine private Nachricht +DevMine.command.xp.description=Fügt dem angegebenen Spieler Erfahrungspunkte oder -level hinzu +DevMine.command.summon.description=Läßt ein Wesen am Ort des Spielers oder einem angegebenen Ort erscheinen +DevMine.command.fill.description=Füllt einen bestimmten Auswahlbereich mit Blöcken +DevMine.command.setblock.description=Ersetzt einen Block durch einen anderen Block + +DevMine.command.weather.description=Legt das Wetter für eine Welt fest +DevMine.command.weather.usage=/weather +DevMine.command.weather.changed=Das Wetter in der Welt {%0} wurde erfolgreich gewechselt! +DevMine.command.weather.noregistered=Die Welt {%0} wurde nicht beim WetterManager registriert. +DevMine.command.weather.invalid=Ungültiges Wetter.(0,1,2,3) +DevMine.command.weather.wrong=Falsche Parameter. +DevMine.command.weather.invalid.level=Ungültiger Weltname. + +DevMine.command.whitelist.description=Verwaltet die Liste der Spieler, denen es erlaubt ist, den Server zu benutzen +DevMine.crash.create=Es ist ein nicht behebbarer Fehler aufgetreten und der Server ist abgestürzt. Erstelle einen Crash-Dump... +DevMine.crash.error=Crash-Dump konnte nicht erstellt werden: {%0} +DevMine.crash.submit=Bitte lade die Datei "{%0}" in das Crash-Archiv hoch und übermittel den Link auf der Bug-Reporting Seite. Gib so viele Informationen an wie du kannst. +DevMine.crash.archive=Der Crash-Dump wurde automatisch in das Crash-Archiv übertragen. Du kannst in unter {%0} einsehen oder die ID #{%1} verwenden. +DevMine.debug.enable=LevelDB Unterstützung aktiviert +DevMine.player.invalidMove={%0} bewegte sich falsch! +DevMine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] loggte sich mit der Entity-ID {%4} bei ({%5}, {%6}, {%7}, {%8}) ein +DevMine.player.logOut={%0}[/{%1}:{%2}] loggte sich wegen {%3} aus +DevMine.player.transferred={%0}[/{%1}:{%2}] wurde transferiert zu {%3} +DevMine.player.invalidEntity={%0} versuchte, eine ungültige Entity zu attackieren +DevMine.plugin.load=Lade {%0} +DevMine.plugin.enable=Aktiviere {%0} +DevMine.plugin.disable=Deaktiviere {%0} +DevMine.plugin.restrictedName=Verbotener Name +DevMine.plugin.incompatibleAPI=Inkompatible API-Version +DevMine.plugin.unknownDependency=Unbekannte Abhängigkeit +DevMine.plugin.circularDependency=Zirkuläre Abhängigkeit erkannt +DevMine.plugin.genericLoadError=Plugin '{%0}' konnte nicht geladen werden +DevMine.plugin.spacesDiscouraged=Plugin '{%0}' verwendet Leerzeichen im Namen, was nicht erlaubt ist +DevMine.plugin.loadError=Plugin '{%0}' konnte nicht geladen werden: {%1} +DevMine.plugin.duplicateError=Plugin '{%0}' konnte nicht geladen werden: Plugin existiert bereits +DevMine.plugin.fileError=Konnte '{%0}' im Ordner '{%1}' nicht laden: {%2} +DevMine.plugin.commandError=Der Befehl {%0} konnte für das Plugin {%1} nicht geladen werden +DevMine.plugin.aliasError=Alias {%0} konnte für Plugin {%1} nicht geladen werden +DevMine.plugin.deprecatedEvent=Das Plugin '{%0}' hat einen Listener für '{%1}' auf die Methode '{%2}' registriert, aber das Event ist veraltet. +DevMine.plugin.eventError="Das Event '{%0}' konnte nicht an '{%1}' weitergegeben werden: {%2} in {%3}" diff --git a/src/devmine/utilities/languages/locale/eng.ini b/src/devmine/utilities/languages/locale/eng.ini index 94665e6..7a74dd5 100644 --- a/src/devmine/utilities/languages/locale/eng.ini +++ b/src/devmine/utilities/languages/locale/eng.ini @@ -1,7 +1,7 @@ # Language file compatible with Minecraft: Pocket Edition identifiers # # A message doesn't need to be there to be shown correctly on the client. -# Only messages shown in devmine itself need to be here +# Only messages shown in DevMine itself need to be here language.name=English language.selected=Selected {%0} ({%1}) as the base language @@ -9,12 +9,13 @@ language.selected=Selected {%0} ({%1}) as the base language multiplayer.player.joined={%0} joined the game multiplayer.player.left={%0} left the game -chat.type.text=<{%0}> {%1} +chat.type.text={%0} : {%1} chat.type.emote=* {%0} {%1} chat.type.announcement=[{%0}] {%1} chat.type.admin=[{%0}: {%1}] chat.type.achievement={%0} has just earned the achievement {%1} +disconnectionScreen.notAuthenticated=Xbox login required disconnectionScreen.outdatedClient=Outdated client! disconnectionScreen.outdatedServer=Outdated server! disconnectionScreen.serverFull=Server is full! @@ -102,6 +103,7 @@ commands.effect.success.removed.all=Took all effects from {%0} commands.effect.failure.notActive=Couldn't take {%0} from {%1} as they do not have the effect commands.effect.failure.notActive.all=Couldn't take any effects from {%0} as they do not have any +commands.enchant.maxLevel=Level Range of that enchantment is 1 - {%0} commands.enchant.noItem=The target is not holding an item commands.enchant.notFound=There is no such enchantment with ID {%0} commands.enchant.success=Enchanting succeeded @@ -189,14 +191,13 @@ commands.whitelist.remove.success=Removed {%0} from the whitelist commands.whitelist.remove.usage=/whitelist remove commands.whitelist.usage=/whitelist -commands.gamemode.success.self=Set own game mode to {%0} -commands.gamemode.success.other=Set {%0}'s game mode to {%1} +commands.gamemode.success.self=Set own game mode to {%2} +commands.gamemode.success.other=Set {%1}'s game mode to {%2} commands.gamemode.usage=/gamemode [player] commands.help.header=--- Showing help page {%0} of {%1} (/help ) --- commands.help.usage=/help [page|command name] commands.message.usage=/tell commands.message.sameTarget=You can't send a private message to yourself! -commands.xp.usage=/xp commands.difficulty.usage=/difficulty commands.difficulty.success=Set game difficulty to {%0} @@ -208,191 +209,205 @@ commands.setworldspawn.success=Set the world spawn point to ({%0}, {%1}, {%2}) commands.summon.usage=/summon [entity] [ ] [NBTTag] -commands.cave.usage=/cave | /cave getmypos -commands.cave.info=Angle of rotation:{%0} Length:{%1} Branch Number:{%2} Strength:{%3} -commands.cave.start=Generating cave, please wait -commands.cave.success=Cave generated -# -------------------- devmine language files, only for console -------------------- -devmine.data.playerNotFound=Player data not found for "{%0}", creating new profile -devmine.data.playerCorrupted=Corrupted data found for "{%0}", creating new profile -devmine.data.playerOld=Old Player data found for "{%0}", upgrading profile -devmine.data.saveError=Could not save player "{%0}": {%1} -devmine.level.notFound=Level "{%0}" not found -devmine.level.loadError=Could not load level "{%0}": {%1} -devmine.level.generationError=Could not generate level "{%0}": {%1} -devmine.level.tickError=Could not tick level "{%0}": {%1} -devmine.level.chunkUnloadError=Error while unloading a chunk: {%0} -devmine.level.backgroundGeneration=Spawn terrain for level "{%0}" is being generated in the background -devmine.level.defaultError=No default level has been loaded -devmine.level.preparing=Preparing level "{%0}" -devmine.level.unloading=Unloading level "{%0}" -devmine.server.start=Starting Minecraft: PE server version {%0} -devmine.server.networkError=[Network] Stopped interface {%0} due to {%1} -devmine.server.networkStart=Opening server on {%0}:{%1} -devmine.server.info=This server is running {%0} version {%1} "{%2}" (API {%3}) -devmine.server.info.extended=This server is running {%0} {%1} "{%2}" implementing API {%3} for Minecraft: Pocket Edition {%4} (protocol version {%5}) -devmine.server.license={%0} is distributed under the GPL License version 3 and later -devmine.server.tickOverload=Can't keep up! Is the server overloaded? -devmine.server.startFinished=Done ({%0}s)! For help, type "help" or "?" -devmine.server.defaultGameMode=Default game type: {%0} -devmine.server.query.start=Starting GS4 status listener -devmine.server.query.info=Setting query port to {%0} -devmine.server.query.running=Query running on {%0}:{%1} - -devmine.command.alias.illegal=Could not register alias {%0} because it contains illegal characters -devmine.command.alias.notFound=Could not register alias {%0} because it contains commands that do not exist: {%1} -devmine.command.exception=Unhandled exception executing command '{%0}' in {%1}: {%2} - -devmine.command.plugins.description=Gets a list of plugins running on the server -devmine.command.plugins.success=Plugins ({%0}): {%1} -devmine.command.plugins.usage=/plugins - -devmine.command.reload.description=Reloads the server configuration and plugins -devmine.command.reload.usage=/reload -devmine.command.reload.reloading=Reloading server... -devmine.command.reload.reloaded=Reload complete. - -devmine.command.lvdat.description=Change properties of a map. -devmine.command.lvdat.changed=has changed {%1} of level "{%0}", some change need to reboot your server. -devmine.command.lvdat.fixname=fixname successfully for level "{%0}", some change need to reboot your server. -devmine.command.lvdat.nofound=level "{%0}" no found or load failed. -devmine.command.lvdat.preset=Generator setting (preset) - -devmine.command.status.description=Reads back the server's performance. -devmine.command.status.usage=/status - -devmine.command.status.title=Server status -devmine.command.status.player=Player count: -devmine.command.status.days=days -devmine.command.status.hours=hours -devmine.command.status.minutes=minutes -devmine.command.status.seconds=seconds -devmine.command.status.uptime=Uptime: -devmine.command.status.AverageTPS=Average TPS: -devmine.command.status.CurrentTPS=Current TPS: -devmine.command.status.Networkupload=Network upload: -devmine.command.status.Networkdownload=Network download: -devmine.command.status.Threadcount=Thread count: -devmine.command.status.Mainmemory=Main thread memory; -devmine.command.status.Totalmemory=Total memory: -devmine.command.status.Totalvirtualmemory=Total virtual memory: -devmine.command.status.Heapmemory=Heap memory: -devmine.command.status.Maxmemorysystem=Maximum memory (system): -devmine.command.status.Maxmemorymanager=Maximum memory (manager): -devmine.command.status.World=World -devmine.command.status.chunks=chunks, -devmine.command.status.entities=entities, -devmine.command.status.solidentities=solidentities. -devmine.command.status.Time=Time -devmine.command.status.ms=ms - -devmine.command.gc.description=Fires garbage collection tasks -devmine.command.gc.usage=/gc -devmine.command.gc.title=Collection Report -devmine.command.gc.chunks=Chunks: -devmine.command.gc.entities=Entities: -devmine.command.gc.solidentities=solidentities: -devmine.command.gc.cycles=Cycles: -devmine.command.gc.memory=Release memory: - -devmine.command.biome.description=Change the biome of the area.(To change snow or rain) -devmine.command.biome.posset=Set position {%3} at ({%1},{%2}) in level {%0} -devmine.command.biome.get=The ID of biome you are in is {%0}. Color: {%1},{%2},{%3} -devmine.command.biome.wrongLev=Cannot set position in different level. -devmine.command.biome.wrongBio=Wrong ID of biome. e.g. 1 (Plains), 2 (Desert),13 (Ice Mountains),6 (Swampland) -devmine.command.biome.wrongCol=Wrong Color. e.g. 146,188,89 .Use "/biome get" to get other color. -devmine.command.biome.noPos=Please use "/biome pos1|pos2" to select the area first. -devmine.command.biome.set=Set the selected area's biome to {%0} -devmine.command.biome.color=Set the grass colour to {%0},{%1},{%2} - -devmine.command.timings.description=Records timings to see performance of the server. -devmine.command.timings.usage=/timings -devmine.command.timings.enable=Enabled Timings & Reset -devmine.command.timings.disable=Disabled Timings -devmine.command.timings.timingsDisabled=Please enable timings by typing /timings on -devmine.command.timings.reset=Timings reset -devmine.command.timings.pasteError=An error happened while pasting the report -devmine.command.timings.timingsUpload=Timings uploaded to {%0} -devmine.command.timings.timingsRead=You can read the results at {%0} -devmine.command.timings.timingsWrite=Timings written to {%0} -devmine.command.version.description=Gets the version of this server including any plugins in use -devmine.command.version.usage=/version [plugin name] -devmine.command.version.noSuchPlugin=This server is not running any plugin by that name. Use /plugins to get a list of plugins. -devmine.command.give.description=Gives the specified player a certain amount of items -devmine.command.give.usage=/give [amount] [tags...] -devmine.command.kill.description=Commit suicide or kill other players -devmine.command.kill.usage=/kill [player] -devmine.command.particle.description=Adds particles to a world -devmine.command.particle.usage=/particle [count] [data] -devmine.command.time.description=Changes the time on each world -devmine.command.time.usage=/time OR /time -devmine.command.bancidbyname.description=Prevents the specified CID by name from using this server -devmine.command.bancid.description=Prevents the specified CID from using this server -devmine.command.banipbyname.description=Prevents the specified IP address by name from using this server -devmine.command.ban.player.description=Prevents the specified player from using this server -devmine.command.ban.ip.description=Prevents the specified IP address from using this server -devmine.command.banlist.description=View all players banned from this server -devmine.command.defaultgamemode.description=Set the default gamemode -devmine.command.deop.description=Takes the specified player's operator status -devmine.command.difficulty.description=Sets the game difficulty -devmine.command.enchant.description=Adds enchantments on items -devmine.command.effect.description=Adds/Removes effects on players -devmine.command.gamemode.description=Changes the player to a specific game mode -devmine.command.help.description=Shows the help menu -devmine.command.kick.description=Removes the specified player from the server -devmine.command.list.description=Lists all online players -devmine.command.me.description=Performs the specified action in chat -devmine.command.op.description=Gives the specified player operator status -devmine.command.unban.cid.description=Allows the specified CID to use this server -devmine.command.unban.player.description=Allows the specified player to use this server -devmine.command.unban.ip.description=Allows the specified IP address to use this server -devmine.command.save.description=Saves the server to disk -devmine.command.saveoff.description=Disables server autosaving -devmine.command.saveon.description=Enables server autosaving -devmine.command.say.description=Broadcasts the given message as the sender -devmine.command.seed.description=Shows the world seed -devmine.command.setworldspawn.description=Sets a worlds's spawn point. If no coordinates are specified, the player's coordinates will be used. -devmine.command.spawnpoint.description=Sets a player's spawn point -devmine.command.stop.description=Stops the server -devmine.command.tp.description=Teleports the given player (or yourself) to another player or coordinates -devmine.command.tell.description=Sends a private message to the given player -devmine.command.xp.description=Add experience or experience level to the given player -devmine.command.summon.description=Summons a entity at the player's location or a specific location -devmine.command.fill.description=fills a specific selection with blocks -devmine.command.setblock.description=Changes a block to another block - -devmine.command.weather.description=Set weather for level -devmine.command.weather.usage=/weather -devmine.command.weather.changed=Weather changed successfully in level {%0}! -devmine.command.weather.noregistered=level {%0} hasn't registered to WeatherManager. -devmine.command.weather.invalid=Invalid weather.(0,1,2,3) -devmine.command.weather.wrong=Wrong parameters. -devmine.command.weather.invalid.level=Invalid level name. - -devmine.command.whitelist.description=Manages the list of players allowed to use this server -devmine.crash.create=An unrecoverable error has occurred and the server has crashed. Creating a crash dump -devmine.crash.error=Could not create crash dump: {%0} -devmine.crash.submit=Please upload the "{%0}" file to the Crash Archive and submit the link to the Bug Reporting page. Give as much info as you can. -devmine.crash.archive=The crash dump has been automatically submitted to the Crash Archive. You can view it on {%0} or use the ID #{%1}. -devmine.debug.enable=LevelDB support enabled -devmine.player.invalidMove={%0} moved wrongly! -devmine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] logged in with entity id {%4} at ({%5}, {%6}, {%7}, {%8}) -devmine.player.logOut={%0}[/{%1}:{%2}] logged out due to {%3} -devmine.player.transferred={%0}[/{%1}:{%2}] was transferred to {%3} -devmine.player.invalidEntity={%0} tried to attack an invalid entity -devmine.plugin.load=Loading {%0} -devmine.plugin.enable=Enabling {%0} -devmine.plugin.disable=Disabling {%0} -devmine.plugin.restrictedName=Restricted name -devmine.plugin.incompatibleAPI=Incompatible API version -devmine.plugin.unknownDependency=Unknown dependency -devmine.plugin.circularDependency=Circular dependency detected -devmine.plugin.genericLoadError=Could not load plugin '{%0}' -devmine.plugin.spacesDiscouraged=Plugin '{%0}' uses spaces in its name, this is discouraged -devmine.plugin.loadError=Could not load plugin '{%0}': {%1} -devmine.plugin.duplicateError=Could not load plugin '{%0}': plugin exists -devmine.plugin.fileError=Could not load '{%0}' in folder '{%1}': {%2} -devmine.plugin.commandError=Could not load command {%0} for plugin {%1} -devmine.plugin.aliasError=Could not load alias {%0} for plugin {%1} -devmine.plugin.deprecatedEvent=Plugin '{%0}' has registered a listener for '{%1}' on method '{%2}', but the event is Deprecated. -devmine.plugin.eventError="Could not pass event '{%0}' to '{%1}': {%2} on {%3} +commands.xp.failure.withdrawXp=Cannot give player negative experience points +commands.xp.success=Given {%0} experience to {%1} +commands.xp.success.levels=Given {%0} levels to {%1} +commands.xp.success.negative.levels=Taken {%0} levels from {%1} +commands.xp.usage=/xp [player] OR /xp L [player] + +# -------------------- DevMine language files, only for console -------------------- +DevMine.data.playerNotFound=Player data not found for "{%0}", creating new profile +DevMine.data.playerCorrupted=Corrupted data found for "{%0}", creating new profile +DevMine.data.playerOld=Old Player data found for "{%0}", upgrading profile +DevMine.data.saveError=Could not save player "{%0}": {%1} +DevMine.level.notFound=Level "{%0}" not found +DevMine.level.loadError=Could not load level "{%0}": {%1} +DevMine.level.generationError=Could not generate level "{%0}": {%1} +DevMine.level.tickError=Could not tick level "{%0}": {%1} +DevMine.level.chunkUnloadError=Error while unloading a chunk: {%0} +DevMine.level.backgroundGeneration=Spawn terrain for level "{%0}" is being generated in the background +DevMine.level.defaultError=No default level has been loaded +DevMine.level.preparing=Preparing level "{%0}" +DevMine.level.unloading=Unloading level "{%0}" +DevMine.server.start=Starting Minecraft: PE server version {%0} +DevMine.server.networkError=[Network] Stopped interface {%0} due to {%1} +DevMine.server.networkStart=Opening server on {%0}:{%1} +DevMine.server.info=This server is running {%0}{%1} "{%2}" (API {%3}) + +DevMine.server.info.extended.title=-----Server information----- +DevMine.server.info.extended1=This server is running {%0}{%1} {%2} +DevMine.server.info.extended2=PHP version: {%0} +DevMine.server.info.extended3=API: {%0} +DevMine.server.info.extended4=Target client: Minecraft PE {%0} +DevMine.server.info.extended5=Protocol version: {%0} + +DevMine.server.license={%0} is distributed under the GPL License version 3 and later +DevMine.server.tickOverload=Can't keep up! Is the server overloaded? +DevMine.server.startFinished=Done ({%0}s)! For help, type "help" or "?" +DevMine.server.defaultGameMode=Default game type: {%0} +DevMine.server.query.start=Starting GS4 status listener +DevMine.server.query.info=Setting query port to {%0} +DevMine.server.query.running=Query running on {%0}:{%1} + +DevMine.command.alias.illegal=Could not register alias {%0} because it contains illegal characters +DevMine.command.alias.notFound=Could not register alias {%0} because it contains commands that do not exist: {%1} +DevMine.command.exception=Unhandled exception executing command '{%0}' in {%1}: {%2} + +DevMine.commands.cave.usage=/cave | /cave getmypos +DevMine.commands.cave.info=Angle of rotation:{%0} Length:{%1} Branch Number:{%2} Strength:{%3} +DevMine.commands.cave.start=Generating cave, please wait +DevMine.commands.cave.success=Cave generated + +DevMine.command.plugins.description=Gets a list of plugins running on the server +DevMine.command.plugins.success=Plugins ({%0}): {%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=Reloads the server configuration and plugins +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=Reloading server... +DevMine.command.reload.reloaded=Reload complete. + +DevMine.command.lvdat.description=Change properties of a map. +DevMine.command.lvdat.changed=has changed {%1} of level "{%0}", some change need to reboot your server. +DevMine.command.lvdat.fixname=fixname successfully for level "{%0}", some change need to reboot your server. +DevMine.command.lvdat.nofound=level "{%0}" no found or load failed. +DevMine.command.lvdat.preset=Generator setting (preset) + +DevMine.command.status.description=Reads back the server's performance. +DevMine.command.status.usage=/status + +DevMine.command.status.title=Server status +DevMine.command.status.player=Player count: +DevMine.command.status.days=days +DevMine.command.status.hours=hours +DevMine.command.status.minutes=minutes +DevMine.command.status.seconds=seconds +DevMine.command.status.uptime=Uptime: +DevMine.command.status.AverageTPS=Average TPS: +DevMine.command.status.CurrentTPS=Current TPS: +DevMine.command.status.Networkupload=Network upload: +DevMine.command.status.Networkdownload=Network download: +DevMine.command.status.Threadcount=Thread count: +DevMine.command.status.Mainmemory=Main thread memory: +DevMine.command.status.Totalmemory=Total memory: +DevMine.command.status.Totalvirtualmemory=Total virtual memory: +DevMine.command.status.Heapmemory=Heap memory: +DevMine.command.status.Maxmemorysystem=Maximum memory (system): +DevMine.command.status.Maxmemorymanager=Maximum memory (manager): +DevMine.command.status.World=World +DevMine.command.status.chunks=chunks, +DevMine.command.status.entities=entities, +DevMine.command.status.tiles=tiles. +DevMine.command.status.Time=Time +DevMine.command.status.ms=ms + +DevMine.command.gc.description=Fires garbage collection tasks +DevMine.command.gc.usage=/gc +DevMine.command.gc.title=Collection Report +DevMine.command.gc.chunks=Chunks: +DevMine.command.gc.entities=Entities: +DevMine.command.gc.tiles=Tiles: +DevMine.command.gc.cycles=Cycles: +DevMine.command.gc.memory=Release memory: + +DevMine.command.biome.description=Change the biome of the area.(To change snow or rain) +DevMine.command.biome.posset=Set position {%3} at ({%1},{%2}) in level {%0} +DevMine.command.biome.get=The ID of biome you are in is {%0}. Color: {%1},{%2},{%3} +DevMine.command.biome.wrongLev=Cannot set position in different level. +DevMine.command.biome.wrongBio=Wrong ID of biome. e.g. 1 (Plains), 2 (Desert),13 (Ice Mountains),6 (Swampland) +DevMine.command.biome.wrongCol=Wrong Color. e.g. 146,188,89 .Use "/biome get" to get other color. +DevMine.command.biome.noPos=Please use "/biome pos1|pos2" to select the area first. +DevMine.command.biome.set=Set the selected area's biome to {%0} +DevMine.command.biome.color=Set the grass colour to {%0},{%1},{%2} + +DevMine.command.timings.description=Records timings to see performance of the server. +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=Enabled Timings & Reset +DevMine.command.timings.disable=Disabled Timings +DevMine.command.timings.timingsDisabled=Please enable timings by typing /timings on +DevMine.command.timings.reset=Timings reset +DevMine.command.timings.pasteError=An error happened while pasting the report +DevMine.command.timings.timingsUpload=Timings uploaded to {%0} +DevMine.command.timings.timingsRead=You can read the results at {%0} +DevMine.command.timings.timingsWrite=Timings written to {%0} +DevMine.command.version.description=Gets the version of this server including any plugins in use +DevMine.command.version.usage=/version [plugin name] +DevMine.command.version.noSuchPlugin=This server is not running any plugin by that name. Use /plugins to get a list of plugins. +DevMine.command.give.description=Gives the specified player a certain amount of items +DevMine.command.give.usage=/give [amount] [tags...] +DevMine.command.kill.description=Commit suicide or kill other players +DevMine.command.kill.usage=/kill [player] +DevMine.command.particle.description=Adds particles to a world +DevMine.command.particle.usage=/particle [count] [data] +DevMine.command.time.description=Changes the time on each world +DevMine.command.time.usage=/time OR /time +DevMine.command.bancidbyname.description=Prevents the specified CID by name from using this server +DevMine.command.bancid.description=Prevents the specified CID from using this server +DevMine.command.banipbyname.description=Prevents the specified IP address by name from using this server +DevMine.command.ban.player.description=Prevents the specified player from using this server +DevMine.command.ban.ip.description=Prevents the specified IP address from using this server +DevMine.command.banlist.description=View all players banned from this server +DevMine.command.defaultgamemode.description=Set the default gamemode +DevMine.command.deop.description=Takes the specified player's operator status +DevMine.command.difficulty.description=Sets the game difficulty +DevMine.command.enchant.description=Adds enchantments on items +DevMine.command.effect.description=Adds/Removes effects on players +DevMine.command.gamemode.description=Changes the player to a specific game mode +DevMine.command.help.description=Shows the help menu +DevMine.command.kick.description=Removes the specified player from the server +DevMine.command.list.description=Lists all online players +DevMine.command.me.description=Performs the specified action in chat +DevMine.command.op.description=Gives the specified player operator status +DevMine.command.unban.cid.description=Allows the specified CID to use this server +DevMine.command.unban.player.description=Allows the specified player to use this server +DevMine.command.unban.ip.description=Allows the specified IP address to use this server +DevMine.command.save.description=Saves the server to disk +DevMine.command.saveoff.description=Disables server autosaving +DevMine.command.saveon.description=Enables server autosaving +DevMine.command.say.description=Broadcasts the given message as the sender +DevMine.command.seed.description=Shows the world seed +DevMine.command.setworldspawn.description=Sets a worlds's spawn point. If no coordinates are specified, the player's coordinates will be used. +DevMine.command.spawnpoint.description=Sets a player's spawn point +DevMine.command.stop.description=Stops the server +DevMine.command.tp.description=Teleports the given player (or yourself) to another player or coordinates +DevMine.command.tell.description=Sends a private message to the given player +DevMine.command.xp.description=Add experience or experience level to the given player +DevMine.command.summon.description=Summons a entity at the player's location or a specific location +DevMine.command.fill.description=fills a specific selection with blocks +DevMine.command.setblock.description=Changes a block to another block + +DevMine.command.weather.description=Set weather for level +DevMine.command.weather.usage=/weather +DevMine.command.weather.changed=Weather changed successfully in level {%0}! +DevMine.command.weather.noregistered=level {%0} hasn't registered to WeatherManager. +DevMine.command.weather.invalid=Invalid weather.(0,1,2,3) +DevMine.command.weather.wrong=Wrong parameters. +DevMine.command.weather.invalid.level=Invalid level name. + +DevMine.command.whitelist.description=Manages the list of players allowed to use this server +DevMine.crash.create=An unrecoverable error has occurred and the server has crashed. Creating a crash dump +DevMine.crash.error=Could not create crash dump: {%0} +DevMine.crash.submit=Please upload the "{%0}" file to the Crash Archive and submit the link to the Bug Reporting page. Give as much info as you can. +DevMine.crash.archive=The crash dump has been automatically submitted to the Crash Archive. You can view it on {%0} or use the ID #{%1}. +DevMine.debug.enable=LevelDB support enabled +DevMine.player.invalidMove={%0} moved wrongly! +DevMine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] logged in with entity id {%4} at ({%5}, {%6}, {%7}, {%8}) +DevMine.player.logOut={%0}[/{%1}:{%2}] logged out due to {%3} +DevMine.player.transferred={%0}[/{%1}:{%2}] was transferred to {%3} +DevMine.player.invalidEntity={%0} tried to attack an invalid entity +DevMine.plugin.load=Loading {%0} +DevMine.plugin.enable=Enabling {%0} +DevMine.plugin.disable=Disabling {%0} +DevMine.plugin.restrictedName=Restricted name +DevMine.plugin.incompatibleAPI=Incompatible API version +DevMine.plugin.unknownDependency=Unknown dependency +DevMine.plugin.circularDependency=Circular dependency detected +DevMine.plugin.genericLoadError=Could not load plugin '{%0}' +DevMine.plugin.spacesDiscouraged=Plugin '{%0}' uses spaces in its name, this is discouraged +DevMine.plugin.loadError=Could not load plugin '{%0}': {%1} +DevMine.plugin.duplicateError=Could not load plugin '{%0}': plugin exists +DevMine.plugin.fileError=Could not load '{%0}' in folder '{%1}': {%2} +DevMine.plugin.commandError=Could not load command {%0} for plugin {%1} +DevMine.plugin.aliasError=Could not load alias {%0} for plugin {%1} +DevMine.plugin.deprecatedEvent=Plugin '{%0}' has registered a listener for '{%1}' on method '{%2}', but the event is Deprecated. +DevMine.plugin.eventError="Could not pass event '{%0}' to '{%1}': {%2} on {%3} diff --git a/src/devmine/utilities/languages/locale/fra.ini b/src/devmine/utilities/languages/locale/fra.ini index 1cebb4c..1966632 100644 --- a/src/devmine/utilities/languages/locale/fra.ini +++ b/src/devmine/utilities/languages/locale/fra.ini @@ -1,8 +1,8 @@ -# Fichier de langue compatible avec Minecraft: identifiants Pocket Edition +# Fichier de langue compatible avec Minecraft: Pocket Edition -# Aidez moi a traduire (ou à vérifier) les lignes: 212, 257, 274, 275, 276, 277, 286, 290, 295. +# Aidez moi a traduire (ou à vérifier) les lignes: 186, 212, 276, 277, 286, 290, 295. # Un message n'a pas besoin d'être là pour être montré correctement sur le client. -# Seuls les messages affichés dans devmine se doivent d'être ici +# Seuls les messages affichés dans DevMine se doivent d'être ici language.name=Français language.selected=Sélection de {%0} ({%1}) comme langue de base @@ -10,38 +10,38 @@ language.selected=Sélection de {%0} ({%1}) comme langue de base multiplayer.player.joined={%0} a rejoint la partie multiplayer.player.left={%0} a quitté la partie -chat.type.text=<{%0}> {%1} +chat.type.text={%0} : {%1} chat.type.emote=* {%0} {%1} chat.type.announcement=[{%0}] {%1} chat.type.admin=[{%0}: {%1}] -chat.type.achievement={%0} vient d'obtenir le succés {%1} +chat.type.achievement={%0} vient d'obtenir le succès {%1} -disconnectionScreen.outdatedClient=Client périmé! -disconnectionScreen.outdatedServer=Serveur périmé! -disconnectionScreen.serverFull=Le serveur est complet! +disconnectionScreen.outdatedClient=Client expiré ! +disconnectionScreen.outdatedServer=Serveur expiré ! +disconnectionScreen.serverFull=Le serveur est complet ! disconnectionScreen.noReason=Déconnecté du serveur -disconnectionScreen.invalidSkin=Skin invalide! -disconnectionScreen.invalidName=Nom invalide! +disconnectionScreen.invalidSkin=Skin invalide ! +disconnectionScreen.invalidName=Nom invalide ! -death.fell.accident.generic={%0} est tombé d'un endroit élevé -death.attack.inFire={%0} a péri dans les flames +death.fell.accident.generic={%0} a fait une terrible chute +death.attack.inFire={%0} a péri dans les flammes death.attack.onFire={%0} s'est fait carboniser à mort death.attack.lava={%0} a essayé de nager dans la lave death.attack.inWall={%0} a suffoqué dans un mur death.attack.drown={%0} s'est noyé death.attack.cactus={%0} s'est fait piquer à mort death.attack.generic={%0} est mort -death.attack.explosion={%0} a explosé -death.attack.explosion.player={%0} a été soufflé par {%1} +death.attack.explosion={%0} est mort dans une explosion +death.attack.explosion.player={%0} est mort dans une explosion causé par {%1} death.attack.magic={%0} a été tué par la magie death.attack.wither={%0} sécha death.attack.mob={%0} a été tué par {%1} death.attack.player={%0} a été tué par {%1} death.attack.player.item={%0} a été tué par {%1} en utilisant {%2} -death.attack.arrow={%0} a été abattu par {%1} -death.attack.arrow.item={%0} a été abattu par {%1} en utilisant {%2} +death.attack.arrow={%0} s'est fait tiré dessus par {%1} +death.attack.arrow.item={%0} s'est fait tiré dessus par {%1} en utilisant {%2} death.attack.fall={%0} a frappé le sol trop rapidement -death.attack.outOfWorld={%0} a quitté notre monde +death.attack.outOfWorld={%0} a littéralement quitté notre monde gameMode.survival=Mode Survie gameMode.creative=Mode Créatif @@ -57,7 +57,7 @@ potion.damageBoost=Force potion.heal=Vie instantanée potion.harm=Dégats instantanés potion.jump=Saut -potion.confusion=Nausé +potion.confusion=Nausée potion.regeneration=Régénération potion.resistance=Résistance potion.fireResistance=Résistance au feu @@ -77,13 +77,13 @@ commands.generic.exception=Une erreur inconnue est survenue lors de la tentative commands.generic.permission=Vous n'avez pas la permission d'utiliser cette commande commands.generic.notFound=Cette commande n'est pas reconnue : faites /help pour obtenir la liste des commandes commands.generic.player.notFound=Le joueur n'a pas été trouvé -commands.generic.usage=Usage: {%0} -commands.generic.level=nom-niveau -commands.generic.seed=nom-seed -commands.generic.name=nom -commands.generic.generator=nom-générateur +commands.generic.usage=Utilisation : {%0} +commands.generic.level=Monde +commands.generic.seed=Semence +commands.generic.name=Nom +commands.generic.generator=Générateur commands.generic.opt.missing=Propriétés manquantes, merci de confirmer et d'appuyer sur entrée. -commands.generic.runingame=S'il vous plaît exécuter cette commande en jeu. +commands.generic.runingame=Cette commande ne fonctionne qu'en jeu. commands.time.added=Heure avancée de {%0} commands.time.set=Heure fixée à {%0} @@ -91,17 +91,17 @@ commands.time.query=Temps : {%0} commands.me.usage=/me -commands.give.item.notFound=Il n'y a pas d'objet nommé {%0} +commands.give.item.notFound=Il n'y a pas d'objet connu ayant pour nom {%0} commands.give.success=Don de {%0} * {%1} à {%2} commands.give.tagError=L'analyse syntaxique du data tag a échoué : {%0} commands.effect.usage=/effect [temps] [amplificateur] [masquer les particules] OU /effect clear -commands.effect.notFound=Il n'y a pas d'effet ayant pour ID {%0} +commands.effect.notFound=Il n'y a pas d'effet connu ayant pour ID {%0} commands.effect.success=Don de l'effet {%0} (ID {%1}) * {%2} à {%3} pour une durée de {%4} secondes commands.effect.success.removed=Retrait de l'effet {%0} de {%1} commands.effect.success.removed.all=Retrait de tous les effets de {%0} -commands.effect.failure.notActive=Impossible de supprimer l'effet {%0} de {%1} car il possède pas cet effet -commands.effect.failure.notActive.all=Impossible de supprimer les effets du joueur {%0} car il n'en a pas +commands.effect.failure.notActive=Impossible de supprimer l'effet {%0} de {%1} car ce joueur ne possède pas cet effet +commands.effect.failure.notActive.all=Impossible de supprimer les effets du joueur {%0} car ce joueur ne possède aucun effets commands.enchant.noItem=Le joueur n'a pas d'objet en main commands.enchant.notFound=Il n'y a pas d'enchantement avec l'ID {%0} @@ -115,7 +115,7 @@ commands.players.list=Il y'a {%0}/{%1} joueurs en ligne: commands.kill.successful={%0} a été anéanti(e) commands.banlist.ips=Il y'a un total de {%0} IP banni(s) : commands.banlist.players=Il y'a un total de {%0} joueur(s) banni(s) : -commands.banlist.cids=Il y'a un total de {%0} CID banni(s): +commands.banlist.cids=Il y'a un total de {%0} CID banni(s) : commands.banlist.usage=/banlist [ip|players|cids] commands.defaultgamemode.usage=/defaultgamemode commands.defaultgamemode.success=Le mode de jeu par défaut est maintenant {%0} @@ -129,7 +129,7 @@ commands.deop.usage=/deop commands.say.usage=/say commands.seed.usage=/seed -commands.seed.success=Seed: {%0} +commands.seed.success=Semence : {%0} commands.bancidbyname.success=CID du joueur {%0} banni commands.bancidbyname.usage=/bancidbyname @@ -166,32 +166,32 @@ commands.save.disabled=Sauvegarde automatique du monde désactivée commands.save.start=Sauvegarde... commands.save.success=Monde sauvegardé -commands.setblock.usage=/setblock [dégâts] +commands.setblock.usage=/setblock [dégâts] command.setblock.invalidBlock=Vous avez entré un nom/ID de bloc invalide commands.stop.usage=/stop commands.stop.start=Arrêt du serveur commands.kick.success={%0} s'est fait éjecter du serveur -commands.kick.success.reason={%0} s'est fait éjecter du serveur pour la raison suivante: {%1}' +commands.kick.success.reason={%0} s'est fait éjecter du serveur pour la raison suivante : {%1}' commands.kick.usage=/kick [raison ...] commands.tp.success={%0} s'est fait téléporter vers {%1} commands.tp.success.coordinates={%0} s'est fait téléporter en {%1}, {%2}, {%3} commands.tp.usage=/tp [joueur cible] OU /tp [joueur cible] [ ] -commands.whitelist.list=Il y'a {%0} joueur(s) (sur {%1} détecté(s)) dans la liste blanche : +commands.whitelist.list=Il y a {%0} joueur(s) (sur {%1} détecté(s)) dans la liste blanche : commands.whitelist.enabled=Liste blanche activée commands.whitelist.disabled=Liste blanche désactivée -commands.whitelist.reloaded=Liste blanche rechargée +commands.whitelist.reloaded=Liste blanche réactualisée commands.whitelist.add.success={%0} a été ajouté(e) à la liste blanche commands.whitelist.add.usage=/whitelist add commands.whitelist.remove.success=Le joueur {%0} a été retiré(e) de la liste blanche commands.whitelist.remove.usage=/whitelist remove commands.whitelist.usage=/whitelist -commands.gamemode.success.self=Votre mode de jeu a été changé en Mode {%0} -commands.gamemode.success.other=Le mode de jeu de {%0} a été changé en Mode {%1} +commands.gamemode.success.self=Votre mode de jeu a été changé en Mode {%2} +commands.gamemode.success.other=Le mode de jeu de {%1} a été changé en Mode {%2} commands.gamemode.usage=/gamemode [joueur] commands.help.header=--- Affichage de la page d'aide {%0} sur {%1} (/help ) --- commands.help.usage=/help [page|nom de la commande] @@ -209,191 +209,193 @@ commands.setworldspawn.usage=/setworldspawn [ ] commands.setworldspawn.success=Le point d'appartition du monde a été défini en ({%0}, {%1}, {%2}) commands.summon.usage=/summon [nom de l'entité] [ ] [dataTag] -commands.cave.usage=/cave | /cave getmypos -commands.cave.info=Angle de rotation:{%0} Longueur:{%1} Branch Number:{%2} Force:{%3} -commands.cave.start=Génération de la caverne patientez... -commands.cave.success=Caverne généré -# -------------------- Fichiers de langue devmine, uniquement pour la console -------------------- -devmine.data.playerNotFound=Données du joueur "{%0}" invalides , création d'un nouveau profil -devmine.data.playerCorrupted=Données du joueur "{%0}" corrompus, création d'un nouveau profil -devmine.data.playerOld=Ancienne données du joueur "{%0}" trouvées, mise à jour du profil -devmine.data.saveError=Impossible de sauvegarder le joueur "{%0}": {%1} -devmine.level.notFound=Le monde "{%0}" ne fonctionne pas -devmine.level.loadError=Impossible de charger le monde "{%0}": {%1} -devmine.level.generationError=Impossible de générer le monde "{%0}": {%1} -devmine.level.tickError=Impossible de vérifier le monde "{%0}": {%1} -devmine.level.chunkUnloadError=Une erreur est survenue lors du déchargement d'un chunk: {%0} -devmine.level.backgroundGeneration=L'apparition du terrain pour le niveau "{%0}" est entrain de ce générer en arrière-plan -devmine.level.defaultError=Aucun niveau par défaut n'a été chargée -devmine.level.preparing=Préparation du terrain "{%0}" -devmine.level.unloading=Déchargement du terrain "{%0}" -devmine.server.start=Démarrage du serveur Minecraft PE version {%0} -devmine.server.networkError=[Réseau] Arrêt de l'interface {%0} à cause de {%1} -devmine.server.networkStart=Ouverture du serveur sur {%0}:{%1} -devmine.server.info=Ce serveur fonctionne sur {%0} version {%1} "{%2}" (API {%3}) -devmine.server.info.extended=Ce serveur fonctionne sur {%0} {%1} "{%2}" API implantée {%3} pour Minecraft: Pocket Edition {%4} (version du protocol {%5}) -devmine.server.license={%0} est distribué sous la licence GPL version 3 et plus -devmine.server.tickOverload=Désynchronisation ! Est-ce que le serveur surchargé ? -devmine.server.startFinished=Démarrer en ({%0}s)! Pour afficher l'aide tapez "/help" ou "/?" -devmine.server.defaultGameMode=Mode de jeu par défaut: {%0} -devmine.server.query.start=Démarrage de GS4 statut listener -devmine.server.query.info=Réglage du port Query sur {%0} -devmine.server.query.running=Le Query fonctionne sur {%0}:{%1} - -devmine.command.alias.illegal=Le pseudonyme {%0} ne peut pas être enregistré car il contient des caractères illégaux -devmine.command.alias.notFound=Le pseudonyme {%0} ne peut pas être enregistré car il contient des commandes qui n'existent pas: {%1} -devmine.command.exception=Commande d'exécution d'exception non gérée '{%0}' dans {%1}: {%2} - -devmine.command.plugins.description=Obtention de la liste des plugins en cours d'exécution sur le serveur -devmine.command.plugins.success=Plugins ({%0}): {%1} -devmine.command.plugins.usage=/plugins - -devmine.command.reload.description=Recharge la configuration du serveur et des plugins -devmine.command.reload.usage=/reload -devmine.command.reload.reloading=Rechargement du serveur... -devmine.command.reload.reloaded=Rechargement du serveur terminé. - -devmine.command.lvdat.description=Modification des propriétés de la carte. -devmine.command.lvdat.changed=Changement {%1} du monde "{%0}", les changements nécessites un redémarrage de serveur. -devmine.command.lvdat.fixname=Changement du nom terminé "{%0}", les changements nécessites un redémarrage de serveur. -devmine.command.lvdat.nofound=le monde "{%0}" ne fonctionne pas ou le chargement a échoué -devmine.command.lvdat.preset=Réglage du générateur (prédéfini) - -devmine.command.status.description=Relecture des performances du serveur. -devmine.command.status.usage=/status - -devmine.command.status.title=Statut du serveur -devmine.command.status.player=Nombre de joueur(s): -devmine.command.status.days=jour(s) -devmine.command.status.hours=heure(s) -devmine.command.status.minutes=minute(s) -devmine.command.status.seconds=seconde(s) -devmine.command.status.uptime=Durée de fonctionnement: -devmine.command.status.AverageTPS=Moyenne de TPS: -devmine.command.status.CurrentTPS=TPS actuel: -devmine.command.status.Networkupload=Téléchargement montant de réseau : -devmine.command.status.Networkdownload=Téléchargement de réseau : -devmine.command.status.Threadcount=Thread count: -devmine.command.status.Mainmemory=Main thread memory; -devmine.command.status.Totalmemory=Mémoire totale: -devmine.command.status.Totalvirtualmemory=Mémoire virtuelle totale: -devmine.command.status.Heapmemory=Mémoire utilisée: -devmine.command.status.Maxmemorysystem=Mémoire maximale (système): -devmine.command.status.Maxmemorymanager=Mémoire maximale (gestionnaire): -devmine.command.status.World=Monde -devmine.command.status.chunks=Chunks, -devmine.command.status.entities=Entités, -devmine.command.status.solidentities=solidentities. -devmine.command.status.Time=Temps -devmine.command.status.ms=ms - -devmine.command.gc.description=Ramassage des déchets -devmine.command.gc.usage=/gc -devmine.command.gc.title=Collection du Rapport -devmine.command.gc.chunks=Chunks: -devmine.command.gc.entities=Entités: -devmine.command.gc.solidentities=solidentities: -devmine.command.gc.cycles=Cycles: -devmine.command.gc.memory=Release memory: - -devmine.command.biome.description=Changez le biome de la zone.(Pour changer la neige ou la pluie) -devmine.command.biome.posset=Réglage de la position {%3} à ({%1},{%2}) dans le niveau {%0} -devmine.command.biome.get=L'ID de biome où vous êtes est {%0}. Couleurr: {%1},{%2},{%3} -devmine.command.biome.wrongLev=Impossible de définir cette position dans un niveau différent. -devmine.command.biome.wrongBio=Mauvais ID de biome. e.g. 1 (Plaine), 2 (Désert),13 (Montagnes de glace),6 (Marécage) -devmine.command.biome.wrongCol=Mauvaise couleur. e.g. 146,188,89 .Use "/biome get" pour obtenir une autre couleur. -devmine.command.biome.noPos=Veuillez utiliser "/biome pos1|pos2" pour sélectionner la première zone. -devmine.command.biome.set=Réglage du biome dans la zone sélectionnée à {%0} -devmine.command.biome.color=Réglage de la couleur de l'herbe à {%0},{%1},{%2} - -devmine.command.timings.description=Synchronisation des rapports pour voir les performances du serveur. -devmine.command.timings.usage=/timings -devmine.command.timings.enable=Activer le minutage et réinitialiser -devmine.command.timings.disable=Désactiver le minutage -devmine.command.timings.timingsDisabled=Merci d'activer les rapports de performance en tapant la commande /timings on -devmine.command.timings.reset=Minutage réinitialisé -devmine.command.timings.pasteError=Une erreur s'est produite lors de la génération du rapport -devmine.command.timings.timingsUpload=Rapports de performance mis à jours sur {%0} -devmine.command.timings.timingsRead=Vous pouvez lire les résultats dans {%0} -devmine.command.timings.timingsWrite=Rapports de performance écrits sur {%0} -devmine.command.version.description=Obtenez la version de ce serveur, y compris tous les plugins utilisés -devmine.command.version.usage=/version [nom du plugin] -devmine.command.version.noSuchPlugin=Ce serveur n'utilise pas ce plugin. Utilisez / plugins pour obtenir la liste des plugins. -devmine.command.give.description=Donne au joueur spécifié une certaine quantité d'items -devmine.command.give.usage=/give [montant] [tags...] -devmine.command.kill.description=Se suicider ou tuer d'autres joueurs -devmine.command.kill.usage=/kill [joueur] -devmine.command.particle.description=Ajoute des particules à un monde -devmine.command.particle.usage=/particle [nombre] [data] -devmine.command.time.description=Change le temps sur chaque monde -devmine.command.time.usage=/time OU /time -devmine.command.bancidbyname.description=Empêche le CID du joueur spécifié d'accéder à ce serveur -devmine.command.bancid.description=Empêche le CID spécifié d'accéder à ce serveur -devmine.command.banipbyname.description=Empêche l'adresse IP du joueur spécifiée d'accéder a ce serveur -devmine.command.ban.player.description=Empêche le joueur spécifié d'accéder a ce serveur -devmine.command.ban.ip.description=Empêche l'adresse IP spécifiée d'accéder a ce serveur -devmine.command.banlist.description=Voir la liste de tous les joueurs bannis sur ce serveur -devmine.command.defaultgamemode.description=Réglez le mode de jeu par défaut -devmine.command.deop.description=Enléve les droits d'administration à un joueur spécifié. -devmine.command.difficulty.description=Définit la difficulté du jeu -devmine.command.enchant.description=Ajoute un enchantement sur un item -devmine.command.effect.description=Ajoute/Supprime des effets sur un joueur spécifié -devmine.command.gamemode.description=Change le mode de jeu d'un joueur spécifique -devmine.command.help.description=Affiche le menu d'aide -devmine.command.kick.description=Exclu le joueur spécifié du serveur -devmine.command.list.description=Liste de tous les joueurs en ligne -devmine.command.me.description=Exécute l'action spécifiée dans le chat -devmine.command.op.description=Donne le statut d'opérateur au joueur spécifié -devmine.command.unban.cid.description=Autorise le CID spécifié à accéder au serveur -devmine.command.unban.player.description=Autorise le joueur spécifié à accéder au serveur -devmine.command.unban.ip.description=Autorise l'adresse IP spécifiée à accéder au serveur -devmine.command.save.description=Sauvegarde le serveur sur le disque -devmine.command.saveoff.description=Désactive la sauvegarde automatique -devmine.command.saveon.description=Active la sauvegarde automatique -devmine.command.say.description=Diffuse un message dans le chat -devmine.command.seed.description=Affiche le seed du serveur -devmine.command.setworldspawn.description=Définit le point d'apparition du monde.Si aucunes coordonnées ne sont spécifiées, les coordonnées du joueur sont utilisés. -devmine.command.spawnpoint.description=Définit le point d'apparition d'un joueur -devmine.command.stop.description=Arrête le serveur -devmine.command.tp.description=Téléporte le joueur donné (ou vous-même) à un autre joueur ou vers des coordonnées -devmine.command.tell.description=Envoie un message privé au joueur donné -devmine.command.xp.description=Ajouter de l'expérience a un joueur donné -devmine.command.summon.description=Invoque une entité à l'emplacement d'un joueur ou à un emplacement spécifique -devmine.command.fill.description=remplit une sélection spécifique avec des blocs -devmine.command.setblock.description=Remplace un bloc par un autre - -devmine.command.weather.description=Réglez la météo pour le niveau -devmine.command.weather.usage=/weather -devmine.command.weather.changed=Météo changé avec succès au niveau {%0}! -devmine.command.weather.noregistered=Le niveau {%0} n'est pas enregistré à WeatherManager. -devmine.command.weather.invalid=Météo Invalide.(0,1,2,3) -devmine.command.weather.wrong=Mauvais paramètres. -devmine.command.weather.invalid.level=Nom du niveau invalide. - -devmine.command.whitelist.description=Gère la liste des joueurs autorisés à accéder à serveur -devmine.crash.create=Une erreur irréversible s'est produite causant un crash du serveur. Création d'un rapport de crash -devmine.crash.error=Impossible de créer un fichier de crash : {%0} -devmine.crash.submit=Soumettez le fichier "{%0}" à l'archive des crashs et soumettez le lien vers la page des rapports de bugs. Donnez le plus d'informations possible. -devmine.crash.archive=Le rapport de crash a été automatiquement soumis à l'archive des crashs. Vous pouvez le voir sur {%0} ou utilisez l'ID #{%1}. -devmine.debug.enable=Support LevelDB activé -devmine.player.invalidMove={%0} se déplace incorrectement ! -devmine.player.logIn={%0}[/{%1}:{%2}] [IDClient: {%3}] s'est connecté avec l'ID d'entité {%4} à ({%5}, {%6}, {%7}, {%8}) -devmine.player.logOut={%0}[/{%1}:{%2}] déconnecté en raison de {%3} -devmine.player.transferred={%0}[/{%1}:{%2}] a été transféré à {%3} -devmine.player.invalidEntity={%0} essaye d'attaquer une entité invalide -devmine.plugin.load=Chargement {%0} -devmine.plugin.enable=Activation de {%0} -devmine.plugin.disable=Désactivation de {%0} -devmine.plugin.restrictedName=Nom restreint -devmine.plugin.incompatibleAPI=Version d'API Incompatible -devmine.plugin.unknownDependency=Dépendance inconnu -devmine.plugin.circularDependency=Dépendance circulaire détectée -devmine.plugin.genericLoadError=Impossible de charger le plugin '{%0}' -devmine.plugin.spacesDiscouraged=Le plugin '{%0} utilise des espaces dans son nom, ceci est déconseillé -devmine.plugin.loadError=Impossible de charger le plugin '{%0}': {%1} -devmine.plugin.duplicateError=Impossible de charger le plugin '{%0}': le plugin existe -devmine.plugin.fileError=Impossible de charger '{%0}' dans le dossier '{%1}': {%2} -devmine.plugin.commandError=Impossible de charger la commande {%0} pour le plugin {%1} -devmine.plugin.aliasError=L'alias {%0} ne peut pas être chargé pour le plugin {%1} -devmine.plugin.deprecatedEvent=Le plugin '{%0}' a enregistré un auditeur pour '{%1} "sur la méthode'{%2}', mais l'événement est obsolète. -devmine.plugin.eventError="Impossible de passer l’événement '{%0}' de '{%1}': {%2} sur {%3}" + +# -------------------- Fichiers de langue DevMine, uniquement pour la console -------------------- +DevMine.data.playerNotFound=Données du joueur "{%0}" invalides , création d'un nouveau profil +DevMine.data.playerCorrupted=Données du joueur "{%0}" corrompus, création d'un nouveau profil +DevMine.data.playerOld=Ancienne données du joueur "{%0}" trouvées, mise à jour du profil +DevMine.data.saveError=Impossible de sauvegarder le joueur "{%0}": {%1} +DevMine.level.notFound=Le monde "{%0}" est introuvable +DevMine.level.loadError=Impossible de charger le monde "{%0}": {%1} +DevMine.level.generationError=Impossible de générer le monde "{%0}": {%1} +DevMine.level.tickError=Impossible de vérifier le monde "{%0}": {%1} +DevMine.level.chunkUnloadError=Une erreur est survenue lors du déchargement d'un chunk: {%0} +DevMine.level.backgroundGeneration=L'apparition du terrain pour le niveau "{%0}" est entrain de ce générer en arrière-plan +DevMine.level.defaultError=Aucun niveau par défaut n'a été chargée +DevMine.level.preparing=Préparation du terrain "{%0}" +DevMine.level.unloading=Déchargement du terrain "{%0}" +DevMine.server.start=Démarrage du serveur Minecraft PE version {%0} +DevMine.server.networkError=[Réseau] Arrêt de l'interface {%0} à cause de {%1} +DevMine.server.networkStart=Ouverture du serveur sur {%0}:{%1} +DevMine.server.info=Ce serveur fonctionne sur {%0} version {%1} "{%2}" (API {%3}) +DevMine.server.info.extended=Ce serveur fonctionne sur {%0} {%1} "{%2}" API implantée {%3} pour Minecraft: Pocket Edition {%4} (version du protocol {%5}) +DevMine.server.license={%0} est distribué sous la licence GPL version 3 et plus +DevMine.server.tickOverload=Désynchronisation ! Est-ce que le serveur surchargé ? +DevMine.server.startFinished=Démarrer en ({%0}s)! Pour afficher l'aide tapez "/help" ou "/?" +DevMine.server.defaultGameMode=Mode de jeu par défaut : {%0} +DevMine.server.query.start=Démarrage de GS4 statut listener +DevMine.server.query.info=Réglage du port Query sur {%0} +DevMine.server.query.running=Le Query fonctionne sur {%0}:{%1} + +DevMine.command.alias.illegal=Le pseudonyme {%0} ne peut pas être enregistré car il contient des caractères illégaux +DevMine.command.alias.notFound=Le pseudonyme {%0} ne peut pas être enregistré car il contient des commandes qui n'existent pas: {%1} +DevMine.command.exception=Commande d'exécution d'exception non gérée '{%0}' dans {%1}: {%2} + +DevMine.commands.cave.usage=/cave | /cave getmypos +DevMine.commands.cave.info=Angle de rotation:{%0} Longueur:{%1} Branch Number:{%2} Force:{%3} +DevMine.commands.cave.start=Génération de la caverne, veuillez patientez... +DevMine.commands.cave.success=Caverne généré + +DevMine.command.plugins.description=Obtention de la liste des plugins en cours d'exécution sur le serveur +DevMine.command.plugins.success=Plugins ({%0}) : {%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=Recharge la configuration du serveur et des plugins +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=Rechargement du serveur... +DevMine.command.reload.reloaded=Rechargement du serveur terminé. + +DevMine.command.lvdat.description=Modification des propriétés de la carte. +DevMine.command.lvdat.changed=Changement {%1} du monde "{%0}", les changements nécessites un redémarrage de serveur. +DevMine.command.lvdat.fixname=Changement du nom terminé "{%0}", les changements nécessites un redémarrage de serveur. +DevMine.command.lvdat.nofound=le monde "{%0}" ne fonctionne pas ou le chargement a échoué +DevMine.command.lvdat.preset=Réglage du générateur (prédéfini) + +DevMine.command.status.description=Relecture des performances du serveur. +DevMine.command.status.usage=/status + +DevMine.command.status.title=Statut du serveur +DevMine.command.status.player=Nombre de joueur(s): +DevMine.command.status.days=jour(s) +DevMine.command.status.hours=heure(s) +DevMine.command.status.minutes=minute(s) +DevMine.command.status.seconds=seconde(s) +DevMine.command.status.uptime=Durée de fonctionnement: +DevMine.command.status.AverageTPS=Moyenne de TPS: +DevMine.command.status.CurrentTPS=TPS actuel: +DevMine.command.status.Networkupload=Débit montant de réseau : +DevMine.command.status.Networkdownload=Débit descendant de réseau : +DevMine.command.status.Threadcount=Thread count: +DevMine.command.status.Mainmemory=Main thread memory: +DevMine.command.status.Totalmemory=Mémoire totale: +DevMine.command.status.Totalvirtualmemory=Mémoire virtuelle totale: +DevMine.command.status.Heapmemory=Mémoire utilisée: +DevMine.command.status.Maxmemorysystem=Mémoire maximale (système): +DevMine.command.status.Maxmemorymanager=Mémoire maximale (gestionnaire): +DevMine.command.status.World=Monde +DevMine.command.status.chunks=Chunks, +DevMine.command.status.entities=Entités, +DevMine.command.status.tiles=Tiles. +DevMine.command.status.Time=Temps +DevMine.command.status.ms=ms + +DevMine.command.gc.description=Ramassage des déchets +DevMine.command.gc.usage=/gc +DevMine.command.gc.title=Collection du Rapport +DevMine.command.gc.chunks=Chunks: +DevMine.command.gc.entities=Entités: +DevMine.command.gc.tiles=Tiles: +DevMine.command.gc.cycles=Cycles: +DevMine.command.gc.memory=Release memory: + +DevMine.command.biome.description=Changez le biome de la zone.(Pour changer la neige ou la pluie) +DevMine.command.biome.posset=Réglage de la position {%3} à ({%1},{%2}) dans le niveau {%0} +DevMine.command.biome.get=L'ID de biome où vous êtes est {%0}. Couleurr: {%1},{%2},{%3} +DevMine.command.biome.wrongLev=Impossible de définir cette position dans un niveau différent. +DevMine.command.biome.wrongBio=Mauvais ID de biome. e.g. 1 (Plaine), 2 (Désert),13 (Montagnes de glace),6 (Marécage) +DevMine.command.biome.wrongCol=Mauvaise couleur. e.g. 146,188,89 .Use "/biome get" pour obtenir une autre couleur. +DevMine.command.biome.noPos=Veuillez utiliser "/biome pos1|pos2" pour sélectionner la première zone. +DevMine.command.biome.set=Réglage du biome dans la zone sélectionnée à {%0} +DevMine.command.biome.color=Réglage de la couleur de l'herbe à {%0},{%1},{%2} + +DevMine.command.timings.description=Synchronisation des rapports pour voir les performances du serveur. +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=Activer le minutage et réinitialiser +DevMine.command.timings.disable=Désactiver le minutage +DevMine.command.timings.timingsDisabled=Merci d'activer les rapports de performance en tapant la commande /timings on +DevMine.command.timings.reset=Minutage réinitialisé +DevMine.command.timings.pasteError=Une erreur s'est produite lors de la génération du rapport +DevMine.command.timings.timingsUpload=Rapports de performance mis à jours sur {%0} +DevMine.command.timings.timingsRead=Vous pouvez lire les résultats dans {%0} +DevMine.command.timings.timingsWrite=Rapports de performance écrits sur {%0} +DevMine.command.version.description=Obtenez la version de ce serveur, y compris tous les plugins utilisés +DevMine.command.version.usage=/version [nom du plugin] +DevMine.command.version.noSuchPlugin=Ce serveur n'utilise pas ce plugin. Utilisez / plugins pour obtenir la liste des plugins. +DevMine.command.give.description=Donne au joueur spécifié une certaine quantité d'items +DevMine.command.give.usage=/give [montant] [tags...] +DevMine.command.kill.description=Se suicider ou tuer d'autres joueurs +DevMine.command.kill.usage=/kill [joueur] +DevMine.command.particle.description=Ajoute des particules à un monde +DevMine.command.particle.usage=/particle [nombre] [data] +DevMine.command.time.description=Change le temps sur chaque monde +DevMine.command.time.usage=/time OU /time +DevMine.command.bancidbyname.description=Empêche le CID du joueur spécifié d'accéder à ce serveur +DevMine.command.bancid.description=Empêche le CID spécifié d'accéder à ce serveur +DevMine.command.banipbyname.description=Empêche l'adresse IP du joueur spécifiée d'accéder a ce serveur +DevMine.command.ban.player.description=Empêche le joueur spécifié d'accéder a ce serveur +DevMine.command.ban.ip.description=Empêche l'adresse IP spécifiée d'accéder a ce serveur +DevMine.command.banlist.description=Voir la liste de tous les joueurs bannis sur ce serveur +DevMine.command.defaultgamemode.description=Réglez le mode de jeu par défaut +DevMine.command.deop.description=Enléve les droits d'administration à un joueur spécifié. +DevMine.command.difficulty.description=Définit la difficulté du jeu +DevMine.command.enchant.description=Ajoute un enchantement sur un item +DevMine.command.effect.description=Ajoute/Supprime des effets sur un joueur spécifié +DevMine.command.gamemode.description=Change le mode de jeu d'un joueur spécifique +DevMine.command.help.description=Affiche le menu d'aide +DevMine.command.kick.description=Exclu le joueur spécifié du serveur +DevMine.command.list.description=Liste de tous les joueurs en ligne +DevMine.command.me.description=Exécute l'action spécifiée dans le chat +DevMine.command.op.description=Donne le statut d'opérateur au joueur spécifié +DevMine.command.unban.cid.description=Autorise le CID spécifié à accéder au serveur +DevMine.command.unban.player.description=Autorise le joueur spécifié à accéder au serveur +DevMine.command.unban.ip.description=Autorise l'adresse IP spécifiée à accéder au serveur +DevMine.command.save.description=Sauvegarde le serveur sur le disque +DevMine.command.saveoff.description=Désactive la sauvegarde automatique +DevMine.command.saveon.description=Active la sauvegarde automatique +DevMine.command.say.description=Diffuse un message dans le chat +DevMine.command.seed.description=Affiche le seed du serveur +DevMine.command.setworldspawn.description=Définit le point d'apparition du monde.Si aucunes coordonnées ne sont spécifiées, les coordonnées du joueur sont utilisés. +DevMine.command.spawnpoint.description=Définit le point d'apparition d'un joueur +DevMine.command.stop.description=Arrête le serveur +DevMine.command.tp.description=Téléporte le joueur donné (ou vous-même) à un autre joueur ou vers des coordonnées +DevMine.command.tell.description=Envoie un message privé au joueur donné +DevMine.command.xp.description=Ajouter de l'expérience a un joueur donné +DevMine.command.summon.description=Invoque une entité à l'emplacement d'un joueur ou à un emplacement spécifique +DevMine.command.fill.description=remplit une sélection spécifique avec des blocs +DevMine.command.setblock.description=Remplace un bloc par un autre + +DevMine.command.weather.description=Réglez la météo pour le niveau +DevMine.command.weather.usage=/weather +DevMine.command.weather.changed=Météo changé avec succès au niveau {%0}! +DevMine.command.weather.noregistered=Le niveau {%0} n'est pas enregistré à WeatherManager. +DevMine.command.weather.invalid=Météo Invalide.(0,1,2,3) +DevMine.command.weather.wrong=Mauvais paramètres. +DevMine.command.weather.invalid.level=Nom du niveau invalide. + +DevMine.command.whitelist.description=Gère la liste des joueurs autorisés à accéder à serveur +DevMine.crash.create=Une erreur irréversible s'est produite causant un crash du serveur. Création d'un rapport de crash +DevMine.crash.error=Impossible de créer un fichier de crash : {%0} +DevMine.crash.submit=Soumettez le fichier "{%0}" à l'archive des crashs et soumettez le lien vers la page des rapports de bugs. Donnez le plus d'informations possible. +DevMine.crash.archive=Le rapport de crash a été automatiquement soumis à l'archive des crashs. Vous pouvez le voir sur {%0} ou utilisez l'ID #{%1}. +DevMine.debug.enable=Support LevelDB activé +DevMine.player.invalidMove={%0} se déplace incorrectement ! +DevMine.player.logIn={%0}[/{%1}:{%2}] [IDClient: {%3}] s'est connecté avec l'ID d'entité {%4} à ({%5}, {%6}, {%7}, {%8}) +DevMine.player.logOut={%0}[/{%1}:{%2}] déconnecté en raison de {%3} +DevMine.player.transferred={%0}[/{%1}:{%2}] a été transféré à {%3} +DevMine.player.invalidEntity={%0} essaye d'attaquer une entité invalide +DevMine.plugin.load=Chargement {%0} +DevMine.plugin.enable=Activation de {%0} +DevMine.plugin.disable=Désactivation de {%0} +DevMine.plugin.restrictedName=Nom restreint +DevMine.plugin.incompatibleAPI=Version d'API Incompatible +DevMine.plugin.unknownDependency=Dépendance inconnu +DevMine.plugin.circularDependency=Dépendance circulaire détectée +DevMine.plugin.genericLoadError=Impossible de charger le plugin '{%0}' +DevMine.plugin.spacesDiscouraged=Le plugin '{%0} utilise des espaces dans son nom, ceci est déconseillé +DevMine.plugin.loadError=Impossible de charger le plugin '{%0}': {%1} +DevMine.plugin.duplicateError=Impossible de charger le plugin '{%0}': le plugin existe +DevMine.plugin.fileError=Impossible de charger '{%0}' dans le dossier '{%1}': {%2} +DevMine.plugin.commandError=Impossible de charger la commande {%0} pour le plugin {%1} +DevMine.plugin.aliasError=L'alias {%0} ne peut pas être chargé pour le plugin {%1} +DevMine.plugin.deprecatedEvent=Le plugin '{%0}' a enregistré un auditeur pour '{%1} "sur la méthode'{%2}', mais l'événement est obsolète. +DevMine.plugin.eventError="Impossible de passer l’événement '{%0}' de '{%1}': {%2} sur {%3}" diff --git a/src/devmine/utilities/languages/locale/jpn.ini b/src/devmine/utilities/languages/locale/jpn.ini index b0d5890..64c8e38 100644 --- a/src/devmine/utilities/languages/locale/jpn.ini +++ b/src/devmine/utilities/languages/locale/jpn.ini @@ -1,7 +1,7 @@ # Language file compatible with Minecraft: Pocket Edition identifiers # # A message doesn't need to be there to be shown correctly on the client. -# Only messages shown in devmine itself need to be here +# Only messages shown in DevMine itself need to be here language.name=日本語 language.selected={%0} ({%1}) を言語に選択しました @@ -9,12 +9,13 @@ language.selected={%0} ({%1}) を言語に選択しました multiplayer.player.joined={%0} がゲームに参加しました multiplayer.player.left={%0} が退出しました -chat.type.text=<{%0}> {%1} +chat.type.text={%0} : {%1} chat.type.emote=* {%0} {%1} chat.type.announcement=[{%0}] {%1} chat.type.admin=[{%0}: {%1}] chat.type.achievement={%0}は{%1}の実績を手に入れました +disconnectionScreen.notAuthenticated=Xboxでのログインが必要です disconnectionScreen.outdatedClient=古いクライアントです! disconnectionScreen.outdatedServer=古いサーバーです! disconnectionScreen.serverFull=サーバーは満員です! @@ -81,8 +82,8 @@ commands.generic.level=level-name commands.generic.seed=seed-name commands.generic.name=name commands.generic.generator=generator-name -commands.generic.opt.missing=Missing required properties,please confirm and re-enter. -commands.generic.runingame=Please run this commond in game. +commands.generic.opt.missing=必要なオプションが入力されていません。確認して再入力してください。 +commands.generic.runingame=コマンドはゲーム内で使用してください。 commands.time.added=時間を{%0}進めました commands.time.set=現在時刻を{%0}に設定しました @@ -105,7 +106,7 @@ commands.effect.failure.notActive.all={%0}はステータス効果を受けて commands.enchant.noItem=対象のプレイヤーはアイテムを持っていません commands.enchant.notFound=ID {%0} に該当するエンチャントはありません commands.enchant.success=エンチャントに成功しました -commands.enchant.cantEnchant=This item cannot be enchanted +commands.enchant.cantEnchant=このアイテムはエンチャントをすることができません commands.enchant.usage=/enchant <プレイヤー名> <エンチャントID> [レベル] commands.particle.success=効果{%0}を{%1}回発生させます commands.particle.notFound=存在しないエフェクト:{%0} @@ -114,7 +115,8 @@ commands.players.list=現在{%0}人(最大{%1}人)がオンライン: commands.kill.successful={%0}を殺しました commands.banlist.ips=%d 個のIPアドレスがBANされています: commands.banlist.players={%0} 人のプレイヤーがBANされています: -commands.banlist.usage=/banlist [IPアドレス|プレイヤー名] +commands.banlist.cids={%0} 個のCIDがBANされています: +commands.banlist.usage=/banlist [ips|players|cids] commands.defaultgamemode.usage=/defaultgamemode <モード> commands.defaultgamemode.success=ワールドのデフォルトのゲームモードを {%0} にしました。 @@ -136,9 +138,10 @@ commands.bancid.success=CID: {%0}はBANされました commands.bancid.usage=/bancid commands.unbancid.usage=/pardoncid +commands.unbancid.success=CID {%0} のBANが解除されました commands.ban.success={%0} をBANしました -commands.ban.usage=/ban <プレイヤー名> [理由 ...] [time(day)] +commands.ban.usage=/ban <プレイヤー名> [理由 ...] [時間(日)] commands.unban.success={%0} のbanを解除しました commands.unban.usage=/pardon <プレイヤー名> @@ -163,8 +166,8 @@ commands.save.disabled=ワールドの自動保存を無効にしました commands.save.start=保存中… commands.save.success=ワールドを保存しました -commands.setblock.usage=/setblock <ボックス名> [データ値] -command.fill.invalidBlock=無効なボックス名/ID +commands.setblock.usage=/setblock <ブロック名> [データ値] +command.fill.invalidBlock=無効なブロック名/ID commands.stop.usage=/stop commands.stop.start=サーバーを停止しています @@ -187,8 +190,8 @@ commands.whitelist.remove.success={%0} をホワイトリストから削除し commands.whitelist.remove.usage=/whitelist remove <プレイヤー名> commands.whitelist.usage=/whitelist -commands.gamemode.success.self=ゲームモードを{%0}に変更しました -commands.gamemode.success.other={%0}のゲームモードを{%1}に変更しました +commands.gamemode.success.self=ゲームモードを{%2}に変更しました +commands.gamemode.success.other={%2}のゲームモードを{%2}に変更しました commands.gamemode.usage=/gamemode <モード> [プレイヤー名] commands.help.header=--- ヘルプページの {%0} / {%1} ページを表示(/help <ページ番号>) --- commands.help.usage=/help [ページ|コマンド名] @@ -204,191 +207,201 @@ commands.spawnpoint.success={%0} のスポーン地点を ({%1}, {%2}, {%3}) に commands.setworldspawn.usage=/setworldspawn [ ] commands.setworldspawn.success=({%0},{%1},{%2}) にワールドのスポーンポイントを設定します -commands.summon.usage=/summon [実体名] [ ] [データタグ] - -commands.cave.usage=/cave | /cave getmypos -commands.cave.info=Angle of rotation:{%0} Length:{%1} Branch Number:{%2} Strength:{%3} -commands.cave.start=Start to generate cave,please wait -# -------------------- devmine language files, only for console -------------------- -devmine.data.playerNotFound={%0} のプレイヤーデータが見つからないため、新たに作成します -devmine.data.playerCorrupted={%0} のデータの破損が見つかったため、新たに作成します -devmine.data.playerOld={%0} の古いプレイヤーデータが見つかったため、更新します -devmine.data.saveError={%0}のデータを保存できませんでした: {%1} -devmine.level.notFound=ワールド "{%0}" が見つかりません -devmine.level.loadError=ワールド "{%0}" を読み込むことができませんでした: {%1} -devmine.level.generationError=ワールド"{%0}"を生成することができませんでした: {%1} -devmine.level.tickError=ワールド "{%0}" をチェックすることができませんでした: {%1} -devmine.level.chunkUnloadError=チャンクの書き込み中にエラーが発生しました: {%0} -devmine.level.backgroundGeneration=ワールド"{%0}"の地形をバックグラウンドで生成しています -devmine.level.defaultError=デフォルトのワールドが読み込まれていません -devmine.level.preparing=ワールド "{%0}" を読み込んでいます -devmine.level.unloading=ワールド"{%0}"の書き込みをしています -devmine.server.start=Minecraft: PEサーバー({%0}に対応)を起動しています -devmine.server.networkError=[Network] {%1}によって{%0}のインターフェイスが停止しました -devmine.server.networkStart={%0}:{%1}上でサーバーを開始しています -devmine.server.info=このサーバーは{%0}のバージョン{%1}「{%2}」(API {%3})で動作しています -devmine.server.info.extended=このサーバーが実行している{%0}のバージョンは{%1}「{%2}」Minecraft PE {%4}用実装APIバージョン{%3}(プロトコルバージョン{%5})です -devmine.server.license={%0}はLGPLライセンスに基づき配布されています -devmine.server.tickOverload=注意! サーバーが高負荷になっている可能性があります -devmine.server.startFinished=起動完了({%0}秒)! "help"または"?"でヘルプを表示 -devmine.server.defaultGameMode=デフォルトゲームタイプ: {%0} -devmine.server.query.start=GS4ステータス リスナーを開始 -devmine.server.query.info=クエリポートを設定: {%0} -devmine.server.query.running=クエリーは {%0}:{%1} で動作しています - -devmine.command.alias.illegal=無効な文字が含まれているため、{%0}を登録できませんでした -devmine.command.alias.notFound=存在しないコマンドが含まれているため、{%0}を登録できませんでした: {%1} -devmine.command.exception=コマンド'{%0}'を{%1}で実行中に、処理できない例外が発生:{%2} - -devmine.command.plugins.description=サーバー上で実行されているプラグインを一覧にして表示します -devmine.command.plugins.success=プラグイン ({%0}): {%1} -devmine.command.plugins.usage=/plugins - -devmine.command.reload.description=サーバーの設定やプラグインを再読み込みします -devmine.command.reload.usage=/reload -devmine.command.reload.reloading=サーバーを再読み込みしています... -devmine.command.reload.reloaded=再読み込みが完了しました - -devmine.command.lvdat.description=Change properties of a map. -devmine.command.lvdat.changed=has changed {%1} of level "{%0}", some change need to reboot your server. -devmine.command.lvdat.fixname=fixname successfully for level "{%0}", some change need to reboot your server. -devmine.command.lvdat.nofound=level "{%0}" no found or load failed. -devmine.command.lvdat.preset=Generator setting (preset) - -devmine.command.status.description=サーバーのパフォーマンスを読み出します -devmine.command.status.usage=/status - -devmine.command.status.title=サーバーステータス -devmine.command.status.player=プレイヤー人数: -devmine.command.status.days=日数 -devmine.command.status.hours=時間 -devmine.command.status.minutes=分 -devmine.command.status.seconds=秒 -devmine.command.status.uptime=起動時間: -devmine.command.status.AverageTPS=平均の TPS: -devmine.command.status.CurrentTPS=現在のTPS: -devmine.command.status.Networkupload=ネットワークアップロード: -devmine.command.status.Networkdownload=ネットワークダウンロード: -devmine.command.status.Threadcount=スレッド数: -devmine.command.status.Mainmemory=メインスレッド数; -devmine.command.status.Totalmemory=合計のメモリ使用量: -devmine.command.status.Totalvirtualmemory=合計の仮想メモリ使用量: -devmine.command.status.Heapmemory=ヒープ領域: -devmine.command.status.Maxmemorysystem=最大メモリ (システム): -devmine.command.status.Maxmemorymanager=最大メモリ (マネージャー): -devmine.command.status.World=ワールド -devmine.command.status.chunks=チャンク, -devmine.command.status.entities=エンティティ, -devmine.command.status.solidentities=タイル. -devmine.command.status.Time=時間 -devmine.command.status.ms=ms - -devmine.command.gc.description=ガベージコレクションのタスクを起動しました -devmine.command.gc.usage=/gc -devmine.command.gc.title=コレクションレポート -devmine.command.gc.chunks=チャンク: -devmine.command.gc.entities=エンティティ: -devmine.command.gc.solidentities=タイル: -devmine.command.gc.cycles=サイクル: -devmine.command.gc.memory=解放されたメモリ: - -devmine.command.biome.description=change the biome of the area.(To change snow or rain) -devmine.command.biome.posset=Has set pos{%3} at:({%1},{%2})[{%0}] -devmine.command.biome.get=The ID of biome you stay is {%0} Color:{%1},{%2},{%3} -devmine.command.biome.wrongLev=Cannot set point in different level. -devmine.command.biome.wrongBio=Wrong ID of biome. e.g. 1 (Plains), 2 (Desert),13 (Ice Mountains),6 (Swampland) -devmine.command.biome.wrongCol=Wrong Color. e.g. 146,188,89 .Use "/biome get" to get other color. -devmine.command.biome.noPos=Plz use "/biome pos1|pos2" to select the area first. -devmine.command.biome.set=Has set biome as:{%0} -devmine.command.biome.color=Has set color as:{%0},{%1},{%2} - -devmine.command.timings.description=サーバーのパフォーマンスを確認する記録のタイミングを設定します -devmine.command.timings.usage=/timings -devmine.command.timings.enable=タイミングをリセット及び有効にしました -devmine.command.timings.disable=タイミングを無効にしました -devmine.command.timings.timingsDisabled=/timings と入力してタイミングを有効にしてください -devmine.command.timings.reset=タイミングをリセットしました -devmine.command.timings.pasteError=レポートのペースト中にエラーが発生しました -devmine.command.timings.timingsUpload=タイミングを{%0}にアップロードします -devmine.command.timings.timingsRead=結果は {%0} で見ることができます -devmine.command.timings.timingsWrite=タイミングを {%0} に書き込んでいます -devmine.command.version.description=使用しているプラグインを含めたこのサーバーのバージョンを取得します -devmine.command.version.usage=/version [プラグイン名] -devmine.command.version.noSuchPlugin=このサーバーではその名前のどのプラグインも実行しまいません プラグインリストを取得するには /plugins を使用してください -devmine.command.give.description=指定したプレイヤーに一定量のアイテムを付与します -devmine.command.give.usage=/give <プレイヤー名> <アイテム[:ダメージ値]> [量] [タグ] -devmine.command.kill.description=自殺または他のプレイヤーを殺すことができます -devmine.command.kill.usage=/kill [プレイヤー名] -devmine.command.particle.description=ワールドにパーティクルを追加します -devmine.command.particle.usage=/particle <パーティクル名> [量] [データ値] -devmine.command.time.description=それぞれのワールドの時間を変更します -devmine.command.time.usage=/time <値> または /time -devmine.command.bancidbyname.description=指定したCIDをプレイヤー名によってサーバーの使用を拒否します -devmine.command.bancid.description=指定したCIDからのサーバーの使用を拒否します -devmine.command.banipbyname.description=指定したIPアドレスをプレイヤー名によってサーバーの使用を拒否します -devmine.command.ban.player.description=指定したプレーヤーのサーバーの使用を拒否します -devmine.command.ban.ip.description=指定したIPアドレスからのサーバーの使用を拒否します -devmine.command.banlist.description=このサーバーでBANされたすべてのプレイヤーを表示します -devmine.command.defaultgamemode.description=デフォルトのゲームモードを設定します -devmine.command.deop.description=指定プレイヤーのOP権限を剥奪します -devmine.command.difficulty.description=ゲーム難易度を設定します -devmine.command.enchant.description=アイテムにエンチャントを付加します -devmine.command.effect.description=プレイヤーに効果を付与/削除します -devmine.command.gamemode.description=プレイヤーのゲームモードを変更します -devmine.command.help.description=ヘルプメニューを表示します -devmine.command.kick.description=指定したプレイヤーをサーバーから追い出します -devmine.command.list.description=サーバーに接続しているプレイヤーを一覧表示します -devmine.command.me.description=チャットで指定したアクションを実行します -devmine.command.op.description=指定したプレイヤーにOP権限を付与します -devmine.command.unban.cid.description=指定したCIDのBANを解除します -devmine.command.unban.player.description=指定したプレイヤーのBANを解除します -devmine.command.unban.ip.description=指定したIPアドレスのBANを解除します -devmine.command.save.description=サーバーを保存します -devmine.command.saveoff.description=サーバーの自動保存を無効にします -devmine.command.saveon.description=サーバーの自動保存を有効にします -devmine.command.say.description=送信者として指定したメッセージを送信します -devmine.command.seed.description=ワールドのシード値を表示します -devmine.command.setworldspawn.description=ワールドのスポーン地点を設定します 座標が指定されていない場合はプレイヤーの現在地の座標が使用されます -devmine.command.spawnpoint.description=プレイヤーのスポーン地点を設定します -devmine.command.stop.description=サーバーを停止します -devmine.command.tp.description=他のプレイヤーまたは指定した座標にプレイヤー(または自分自身)をテレポートさせます -devmine.command.tell.description=指定したプレイヤーにプライベートメッセージを送信します -devmine.command.xp.description=指定プレイヤーに経験値またはレベルを増加する -devmine.command.summon.description=プレーヤーの場所または特定の場所での実体を召喚 -devmine.command.setblock.description=ひと塊に変更は別のブロック - -devmine.command.weather.description=Set weather for level -devmine.command.weather.usage=/weather -devmine.command.weather.changed=Weather changed successfully in level {%0}! -devmine.command.weather.noregistered=level {%0} hasn't registered to WeatherManager. -devmine.command.weather.invalid=Invalid weather.(0,1,2,3) -devmine.command.weather.wrong=Wrong parameters. -devmine.command.weather.invalid.level=Invalid level name. - -devmine.command.whitelist.description=このサーバーの利用を許可するプレイヤーリストを管理します -devmine.crash.create=リカバリー不可能なエラーが発生し、サーバーがクラッシュ(動作を停止)しました。クラッシュダンプを作成しました -devmine.crash.error=クラッシュダンプの作成に失敗: {%0} -devmine.crash.submit=「{%0}」のファイルをクラッシュアーカイブにアップロードし、そのリンクを送ってください 出来る限り多くの情報を記載してください -devmine.crash.archive=クラッシュダンプが自動的にクラッシュアーカイブに提出されました {%0}で閲覧またはID #{%1}を使用可能です -devmine.debug.enable=LevelDB形式の対応を有効にしました -devmine.player.invalidMove={%0} が正しく移動できませんでした! -devmine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] logged in with entity id {%4} at ({%5}, {%6}, {%7}, {%8}) -devmine.player.logOut={%0}[/{%1}:{%2}] logged out due to {%3} -devmine.player.transferred={%0}[/{%1}:{%2}] は {%3}に転送されました。 -devmine.player.invalidEntity={%0} は無効なエンティティに攻撃しました -devmine.plugin.load={%0} を読み込み中... -devmine.plugin.enable={%0}を有効にしています… -devmine.plugin.disable={%0}を無効にしています… -devmine.plugin.restrictedName=不審な名前 -devmine.plugin.incompatibleAPI=互換性がないAPIバージョン -devmine.plugin.unknownDependency=不明な依存関係 -devmine.plugin.circularDependency=循環依存が検出されました -devmine.plugin.genericLoadError=プラグイン'{%0}'の読み込みに失敗しました -devmine.plugin.spacesDiscouraged=プラグイン'{%0}'の名前に空白が使用されていますが、これはおすすめしません -devmine.plugin.loadError=プラグイン'{%0}'を読み込むことができませんでした: {%1} -devmine.plugin.duplicateError=プラグイン'{%0}'を読み込むことができませんでした: 同じプラグインが存在します -devmine.plugin.fileError=フォルダー'{%0}'内の'{%1}'を読み込むことができませんでした: {%2} -devmine.plugin.commandError=プラグイン{%1}のコマンド{%0}を読み込むことができませんでした -devmine.plugin.aliasError=プラグイン {%1} で、コマンド{%0} に対するエイリアスを登録できませんでした -devmine.plugin.deprecatedEvent=プラグイン'{%0}'がメソッド'{%2}'に'{%1}'のリスナーを登録しましたが、イベントが廃止されました -devmine.plugin.eventError="'{%1}'に'{%0}'Eventを渡すことができませんでした: {%3}での{%2}" +commands.summon.usage=/summon [エンティティ名] [ ] [データタグ] + + +# -------------------- DevMine language files, only for console -------------------- +DevMine.data.playerNotFound={%0} のプレイヤーデータが見つからないため、新たに作成します +DevMine.data.playerCorrupted={%0} のデータの破損が見つかったため、新たに作成します +DevMine.data.playerOld={%0} の古いプレイヤーデータが見つかったため、更新します +DevMine.data.saveError={%0}のデータを保存できませんでした: {%1} +DevMine.level.notFound=ワールド "{%0}" が見つかりません +DevMine.level.loadError=ワールド "{%0}" を読み込むことができませんでした: {%1} +DevMine.level.generationError=ワールド"{%0}"を生成することができませんでした: {%1} +DevMine.level.tickError=ワールド "{%0}" をチェックすることができませんでした: {%1} +DevMine.level.chunkUnloadError=チャンクの書き込み中にエラーが発生しました: {%0} +DevMine.level.backgroundGeneration=ワールド"{%0}"の地形をバックグラウンドで生成しています +DevMine.level.defaultError=デフォルトのワールドが読み込まれていません +DevMine.level.preparing=ワールド "{%0}" を読み込んでいます +DevMine.level.unloading=ワールド"{%0}"の書き込みをしています +DevMine.server.start=Minecraft: PEサーバー({%0}に対応)を起動しています +DevMine.server.networkError=[Network] {%1}によって{%0}のインターフェイスが停止しました +DevMine.server.networkStart={%0}:{%1}上でサーバーを開始しています +DevMine.server.info=このサーバーは{%0}のバージョン{%1}「{%2}」(API {%3})で動作しています + +DevMine.server.info.extended.title=-----サーバーの情報----- +DevMine.server.info.extended1=このサーバーは {%0}{%1} を実行しています (コードネーム "{%2}") +DevMine.server.info.extended2=PHPバージョン: {%0} +DevMine.server.info.extended3=API: {%0} (iTX APIバージョン {%1}) +DevMine.server.info.extended4=目的のクライアント: Minecraft PE {%0} (プロトコルバージョン {%1}) + +DevMine.server.license={%0}はLGPLライセンスに基づき配布されています +DevMine.server.tickOverload=注意! サーバーが高負荷になっている可能性があります +DevMine.server.startFinished=起動完了({%0}秒)! "help"または"?"でヘルプを表示 +DevMine.server.defaultGameMode=デフォルトゲームタイプ: {%0} +DevMine.server.query.start=GS4ステータス リスナーを開始 +DevMine.server.query.info=クエリポートを設定: {%0} +DevMine.server.query.running=クエリーは {%0}:{%1} で動作しています + +DevMine.command.alias.illegal=無効な文字が含まれているため、{%0}を登録できませんでした +DevMine.command.alias.notFound=存在しないコマンドが含まれているため、{%0}を登録できませんでした: {%1} +DevMine.command.exception=コマンド'{%0}'を{%1}で実行中に、処理できない例外が発生:{%2} + +DevMine.commands.cave.usage=/cave <回転角> <長さ> <分岐数> <強さ> <ワールド名> | /cave getmypos +DevMine.commands.cave.info=回転角:{%0} 長さ:{%1} 分岐数:{%2} 強さ:{%3} +DevMine.commands.cave.start=洞窟を生成しています。しばらくお待ちください +DevMine.commands.cave.success=洞窟が生成されました + +DevMine.command.plugins.description=サーバー上で実行されているプラグインを一覧にして表示します +DevMine.command.plugins.success=プラグイン ({%0}): {%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=サーバーの設定やプラグインを再読み込みします +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=サーバーを再読み込みしています... +DevMine.command.reload.reloaded=再読み込みが完了しました + +DevMine.command.lvdat.description=マップの設定を変更します。 +DevMine.command.lvdat.changed=ワールド "{%0}" の {%1} が変更されました。 幾つかの変更はサーバーを再起動する必要があります。 +DevMine.command.lvdat.fixname="{%0}" の fixname が成功しました。 幾つかの変更はサーバーを再起動する必要があります。 +DevMine.command.lvdat.nofound=level "{%0}" は存在しないかロードに失敗しています。 +DevMine.command.lvdat.preset=ジェネレーターの設定 (プリセット) + +DevMine.command.status.description=サーバーのパフォーマンスを読み出します +DevMine.command.status.usage=/status + +DevMine.command.status.title=サーバーステータス +DevMine.command.status.player=プレイヤー人数: +DevMine.command.status.days=日数 +DevMine.command.status.hours=時間 +DevMine.command.status.minutes=分 +DevMine.command.status.seconds=秒 +DevMine.command.status.uptime=起動時間: +DevMine.command.status.AverageTPS=平均のTPS: +DevMine.command.status.CurrentTPS=現在のTPS: +DevMine.command.status.Networkupload=ネットワークアップロード: +DevMine.command.status.Networkdownload=ネットワークダウンロード: +DevMine.command.status.Threadcount=スレッド数: +DevMine.command.status.Mainmemory=メインスレッド数: +DevMine.command.status.Totalmemory=合計のメモリ使用量: +DevMine.command.status.Totalvirtualmemory=合計の仮想メモリ使用量: +DevMine.command.status.Heapmemory=ヒープ領域: +DevMine.command.status.Maxmemorysystem=最大メモリ (システム): +DevMine.command.status.Maxmemorymanager=最大メモリ (マネージャー): +DevMine.command.status.World=ワールド +DevMine.command.status.chunks=チャンク, +DevMine.command.status.entities=エンティティ, +DevMine.command.status.tiles=タイル. +DevMine.command.status.Time=時間 +DevMine.command.status.ms=ms + +DevMine.command.gc.description=ガベージコレクションのタスクを起動 +DevMine.command.gc.usage=/gc +DevMine.command.gc.title=コレクションレポート +DevMine.command.gc.chunks=チャンク: +DevMine.command.gc.entities=エンティティ: +DevMine.command.gc.tiles=タイル: +DevMine.command.gc.cycles=サイクル: +DevMine.command.gc.memory=解放されたメモリ: + +DevMine.command.biome.description=エリアのバイオームを変更します。(雪や雨を変更できます) +DevMine.command.biome.posset=ポジション {%3} を ({%1},{%2}) ワールド {%0} にセットしました。 +DevMine.command.biome.get=あなたが立っている場所のバイオームIDは {%0} です。 色:{%1},{%2},{%3} +DevMine.command.biome.wrongLev=ワールドをまたいでポジションをセットすることはできません。 +DevMine.command.biome.wrongBio=バイオームIDが間違っています。 例: 1 (草原), 2 (砂漠),13 (雪山),6 (湿地) +DevMine.command.biome.wrongCol=色が間違っています。 例: 146,188,89 "/biome get" で他の色を取得できます。 +DevMine.command.biome.noPos=最初に "/biome pos1|pos2" を使ってエリアを指定してください。 +DevMine.command.biome.set=選択された場所のバイオームを {%0} に設定しました。 +DevMine.command.biome.color=選択された場所の草ブロックの色を {%0},{%1},{%2} に設定しました。 + +DevMine.command.timings.description=サーバーのパフォーマンスを確認する記録のタイミングを設定します +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=タイミングをリセット及び有効にしました +DevMine.command.timings.disable=タイミングを無効にしました +DevMine.command.timings.timingsDisabled=/timings と入力してタイミングを有効にしてください +DevMine.command.timings.reset=タイミングをリセットしました +DevMine.command.timings.pasteError=レポートのペースト中にエラーが発生しました +DevMine.command.timings.timingsUpload=タイミングを{%0}にアップロードします +DevMine.command.timings.timingsRead=結果は {%0} で見ることができます +DevMine.command.timings.timingsWrite=タイミングを {%0} に書き込んでいます +DevMine.command.version.description=使用しているプラグインを含めたこのサーバーのバージョンを取得します +DevMine.command.version.usage=/version [プラグイン名] +DevMine.command.version.noSuchPlugin=このサーバーではその名前のどのプラグインも実行しまいません プラグインリストを取得するには /plugins を使用してください +DevMine.command.give.description=指定したプレイヤーに一定量のアイテムを付与します +DevMine.command.give.usage=/give <プレイヤー名> <アイテム[:ダメージ値]> [量] [タグ] +DevMine.command.kill.description=自殺または他のプレイヤーを殺すことができます +DevMine.command.kill.usage=/kill [プレイヤー名] +DevMine.command.particle.description=ワールドにパーティクルを追加します +DevMine.command.particle.usage=/particle <パーティクル名> [量] [データ値] +DevMine.command.time.description=それぞれのワールドの時間を変更します +DevMine.command.time.usage=/time <値> または /time +DevMine.command.bancidbyname.description=指定したCIDをプレイヤー名によってサーバーの使用を拒否します +DevMine.command.bancid.description=指定したCIDからのサーバーの使用を拒否します +DevMine.command.banipbyname.description=指定したIPアドレスをプレイヤー名によってサーバーの使用を拒否します +DevMine.command.ban.player.description=指定したプレーヤーのサーバーの使用を拒否します +DevMine.command.ban.ip.description=指定したIPアドレスからのサーバーの使用を拒否します +DevMine.command.banlist.description=このサーバーでBANされたすべてのプレイヤーを表示します +DevMine.command.defaultgamemode.description=デフォルトのゲームモードを設定します +DevMine.command.deop.description=指定プレイヤーのOP権限を剥奪します +DevMine.command.difficulty.description=ゲーム難易度を設定します +DevMine.command.enchant.description=アイテムにエンチャントを付加します +DevMine.command.effect.description=プレイヤーに効果を付与/削除します +DevMine.command.gamemode.description=プレイヤーのゲームモードを変更します +DevMine.command.help.description=ヘルプメニューを表示します +DevMine.command.kick.description=指定したプレイヤーをサーバーから追い出します +DevMine.command.list.description=サーバーに接続しているプレイヤーを一覧表示します +DevMine.command.me.description=チャットで指定したアクションを実行します +DevMine.command.op.description=指定したプレイヤーにOP権限を付与します +DevMine.command.unban.cid.description=指定したCIDのBANを解除します +DevMine.command.unban.player.description=指定したプレイヤーのBANを解除します +DevMine.command.unban.ip.description=指定したIPアドレスのBANを解除します +DevMine.command.save.description=サーバーを保存します +DevMine.command.saveoff.description=サーバーの自動保存を無効にします +DevMine.command.saveon.description=サーバーの自動保存を有効にします +DevMine.command.say.description=送信者として指定したメッセージを送信します +DevMine.command.seed.description=ワールドのシード値を表示します +DevMine.command.setworldspawn.description=ワールドのスポーン地点を設定します 座標が指定されていない場合はプレイヤーの現在地の座標が使用されます +DevMine.command.spawnpoint.description=プレイヤーのスポーン地点を設定します +DevMine.command.stop.description=サーバーを停止します +DevMine.command.tp.description=他のプレイヤーまたは指定した座標にプレイヤー(または自分自身)をテレポートさせます +DevMine.command.tell.description=指定したプレイヤーにプライベートメッセージを送信します +DevMine.command.xp.description=指定プレイヤーに経験値またはレベルを増加する +DevMine.command.summon.description=プレーヤーの場所または特定の場所での実体を召喚 +DevMine.command.fill.description=指定した範囲を、指定するブロックIDで置換します。 +DevMine.command.setblock.description=指定した座標にブロックを配置します。 + +DevMine.command.weather.description=ワールドの天気をセットします +DevMine.command.weather.usage=/weather +DevMine.command.weather.changed=ワールド {%0} で天気の変更に成功しました! +DevMine.command.weather.noregistered=ワールド {%0} はWeatherManagerに登録されていません +DevMine.command.weather.invalid=不正な天気。(0,1,2,3) +DevMine.command.weather.wrong=間違ったパラメーター. +DevMine.command.weather.invalid.level=不正なワールド名。 + +DevMine.command.whitelist.description=このサーバーの利用を許可するプレイヤーリストを管理します +DevMine.crash.create=リカバリー不可能なエラーが発生し、サーバーがクラッシュ(動作を停止)しました。クラッシュダンプを作成しました +DevMine.crash.error=クラッシュダンプの作成に失敗: {%0} +DevMine.crash.submit=「{%0}」のファイルをクラッシュアーカイブにアップロードし、そのリンクを送ってください 出来る限り多くの情報を記載してください +DevMine.crash.archive=クラッシュダンプが自動的にクラッシュアーカイブに提出されました {%0}で閲覧またはID #{%1}を使用可能です +DevMine.debug.enable=LevelDB形式の対応を有効にしました +DevMine.player.invalidMove={%0} が正しく移動できませんでした! +DevMine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] logged in with entity id {%4} at ({%5}, {%6}, {%7}, {%8}) +DevMine.player.logOut={%0}[/{%1}:{%2}] logged out due to {%3} +DevMine.player.transferred={%0}[/{%1}:{%2}] は {%3}に転送されました。 +DevMine.player.invalidEntity={%0} は無効なエンティティに攻撃しました +DevMine.plugin.load={%0} を読み込み中... +DevMine.plugin.enable={%0}を有効にしています… +DevMine.plugin.disable={%0}を無効にしています… +DevMine.plugin.restrictedName=不審な名前 +DevMine.plugin.incompatibleAPI=互換性がないAPIバージョン +DevMine.plugin.unknownDependency=不明な依存関係 +DevMine.plugin.circularDependency=循環依存が検出されました +DevMine.plugin.genericLoadError=プラグイン'{%0}'の読み込みに失敗しました +DevMine.plugin.spacesDiscouraged=プラグイン'{%0}'の名前に空白が使用されていますが、これはおすすめしません +DevMine.plugin.loadError=プラグイン'{%0}'を読み込むことができませんでした: {%1} +DevMine.plugin.duplicateError=プラグイン'{%0}'を読み込むことができませんでした: 同じプラグインが存在します +DevMine.plugin.fileError=フォルダー'{%0}'内の'{%1}'を読み込むことができませんでした: {%2} +DevMine.plugin.commandError=プラグイン{%1}のコマンド{%0}を読み込むことができませんでした +DevMine.plugin.aliasError=プラグイン {%1} で、コマンド{%0} に対するエイリアスを登録できませんでした +DevMine.plugin.deprecatedEvent=プラグイン'{%0}'がメソッド'{%2}'に'{%1}'のリスナーを登録しましたが、イベントが廃止されました +DevMine.plugin.eventError="'{%1}'に'{%0}'Eventを渡すことができませんでした: {%3}での{%2}" diff --git a/src/devmine/utilities/languages/locale/kor.ini b/src/devmine/utilities/languages/locale/kor.ini new file mode 100644 index 0000000..338f8fd --- /dev/null +++ b/src/devmine/utilities/languages/locale/kor.ini @@ -0,0 +1,411 @@ +# Language file compatible with Minecraft: Pocket Edition identifiers +# +# A message doesn't need to be there to be shown correctly on the client. +# Only messages shown in DevMine itself need to be here + +language.name="한국어 | Johnmacrocraft가 번역, ParkChanSol이 도움" +language.selected={%0} ({%1})(이)가 기본 언어로 설정되었습니다. + +multiplayer.player.joined={%0} 님이 게임에 접속했습니다 +multiplayer.player.left={%0}님이 게임에서 나갔습니다 + +chat.type.text={%0} : {%1} +chat.type.emote=* {%0} {%1} +chat.type.announcement=[{%0}] {%1} +chat.type.admin=[{%0}: {%1}] +chat.type.achievement={%0}님이 업적 {%1}을(를) 달성했습니다 + +disconnectionScreen.notAuthenticated=Xbox 로그인이 필요합니다! +disconnectionScreen.outdatedClient=오래된 클라이언트입니다! +disconnectionScreen.outdatedServer=오래된 서버입니다! +disconnectionScreen.serverFull=서버 최대 인원 수를 초과하였습니다. +disconnectionScreen.noReason=서버와의 연결이 끊어졌습니다. +disconnectionScreen.invalidSkin=올바르지 않거나 지원되지 않는 스킨입니다. +disconnectionScreen.invalidName=올바르지 않거나 잘못된 형식의 이름입니다! + +death.fell.accident.generic={%0} 님이 높은 곳에서 떨어졌습니다 +death.attack.inFire={%0} 님이 불에 타 죽었습니다 +death.attack.onFire={%0} 님이 불에 타서 죽었습니다 +death.attack.lava={%0} 님이 용암에 빠져 죽었습니다 +death.attack.inWall={%0} 님이 벽에 끼어 질식사했습니다 +death.attack.drown={%0} 님이 익사했습니다 +death.attack.cactus={%0} 님이 가시에 찔려서 사망했습니다 +death.attack.generic={%0} 님이 사망했습니다 +death.attack.explosion={%0}님이 폭발로 인해 사망하셨습니다. +death.attack.explosion.player={%0} 님이 {%1} 님에 의해 폭사했습니다 +death.attack.magic={%0}님이 마법에 의해 죽었습니다 +death.attack.wither={%0} 님이 말라서 죽었습니다 +death.attack.mob={%0} 님이 {%1} 에게 살해당했습니다 +death.attack.player={%0} 님이 {%1} 에게 살해당했습니다 +death.attack.player.item={%0} 님이 {%1} 님에게 {%2} (으)로 살해당했습니다 +death.attack.arrow={%0} 님이 {%1} 님에게 저격당했습니다 +death.attack.arrow.item={%0}님이 {%1}님에게 {%2}(으)로 저격당했습니다. +death.attack.fall={%0} 님이 너무 높은 곳에서 떨어져 사망했습니다 +death.attack.outOfWorld={%0} 님이 세계 밖으로 떨어져서 사망했습니다 + +gameMode.survival=서바이벌 모드 +gameMode.creative=크리에이티브 모드 +gameMode.adventure=모험 모드 +gameMode.spectator=관전 모드 +gameMode.changed=게임 모드가 변경되었습니다 + +potion.moveSpeed=신속 +potion.moveSlowdown=구속 +potion.digSpeed=성급함 +potion.digSlowDown=피로 +potion.damageBoost=힘 +potion.heal=즉시 회복 +potion.harm=즉시 데미지 +potion.jump=점프 강화 +potion.confusion=멀미 +potion.regeneration=재생 +potion.resistance=저항 +potion.fireResistance=화염 저항 +potion.waterBreathing=수중 호흡 +potion.invisibility=투명화 +potion.blindness=실명 +potion.nightVision=야간 투시 +potion.hunger=허기 +potion.weakness=나약함 +potion.poison=독 +potion.wither=위더 +potion.healthBoost=체력 강화 +potion.absorption=흡수 +potion.saturation=포화 + +commands.generic.exception=이 명령을 수행하는 동안 알 수 없는 오류가 발생했습니다 +commands.generic.permission=이 명령을 사용할 수 있는 권한이 없습니다 +commands.generic.notFound=알 수 없는 명령입니다. /help 로 명령어 목록을 보세요 +commands.generic.player.notFound=플레이어를 찾을 수 없습니다 +commands.generic.usage=사용법: {%0} +commands.generic.level=레벨 이름 +commands.generic.seed=시드 이름 +commands.generic.name=이름 +commands.generic.generator=생성기 이름 +commands.generic.opt.missing=필요한 속성이 없습니다. 확인하고 다시 입력해 주세요. +commands.generic.runingame=게임 안에서 이 명령어를 사용해 주세요. + +commands.time.added=시간을 {%0}만큼 추가하였습니다 +commands.time.set={%0}으로 시간을 설정하였습니다 +commands.time.query=현재 시간은 {%0}입니다 + +commands.me.usage=/me <행동> + +commands.give.item.notFound={%0}의 이름을 가진 아이템이 없습니다 +commands.give.success={%2}님에게 {%0}을(를) {%1}개 주었습니다 +commands.give.tagError=데이터 태그 분석 실패: {%0} + +commands.effect.usage=/effect <유저명> <효과명> [초] [증폭] [입자 숨김] 또는 /effect <유저명> clear (효과 없애기) +commands.effect.notFound=효과 ID {%0}는 존재하지 않습니다 +commands.effect.success=효과 {%0} (ID {%1} * {%2})를 {%3}에게 {%4}초간 주었습니다 +commands.effect.success.removed= {%1}님에게서 효과 {%0}을(를) 제거하였습니다. +commands.effect.success.removed.all={%0} 님의 모든 효과를 제거하였습니다. +commands.effect.failure.notActive={%1}님에게 {%0}효과를 뺏을 수 없습니다, 어떤 효과도 걸려있지 않습니다. +commands.effect.failure.notActive.all={%0}님에게 어떠한 효과도 걸려있지 않기 때문에 효과를 뺏을 수 없습니다 + +commands.enchant.noItem=대상이 아이템을 들고 있지 않아 마법을 부여 할 수 없습니다 +commands.enchant.notFound=ID가 {%0} 인 마법 부여 효과는 없습니다 +commands.enchant.success=마법 부여를 완료하였습니다 +commands.enchant.cantEnchant=선택한 마법 부여는 대상 아이템에 추가될 수 없습니다 +commands.enchant.usage=/enchant <플레이어> <마법 부여 ID> [레벨] +commands.particle.success={%0}효과를 {%1} 초간 지속합니다 +commands.particle.notFound={%0}는 알 수 없는 효과명입니다 +commands.players.usage=/list +commands.players.list=현재 {%0}/{%1} 명이 접속 중입니다: +commands.kill.successful={%0}님을 죽였습니다 +commands.banlist.ips=총 %d개의 차단된 IP 주소들이 있습니다: +commands.banlist.players=총 {%0}명의 차단된 플레이어가 있습니다: +commands.banlist.cids=총 {%0}개의 차단된 CID들이 있습니다: +commands.banlist.usage=/banlist [아이피|플레이어 이름] +commands.defaultgamemode.usage=/defaultgamemode <게임 모드> +commands.defaultgamemode.success=기본 게임모드가 {%0}로 변경되었습니다. + +commands.op.success={%0}을 OP로 설정하였습니다 +commands.op.usage=/op <플레이어> + +commands.deop.success={%0}님의 OP 권한을 박탈하였습니다 +commands.deop.usage=/deop <플레이어> + +commands.say.usage=/say <메시지 ...> + +commands.seed.usage=/seed +commands.seed.success=시드: {%0} + +commands.bancidbyname.success=플레이어 {%0}님의 CID를 차단하였습니다 +commands.bancidbyname.usage=/bancidbyname <플레이어 이름> + +commands.bancid.success=CID 차단: {%0} +commands.bancid.usage=/bancid <클라이언트 ID> + +commands.unbancid.usage=/pardoncid <클라이언트 ID> +commands.unbancid.success=CID {%0}의 차단을 해제하였습니다 + +commands.ban.success=플레이어 {%0}를 차단하였습니다 +commands.ban.usage=/ban <이름> [사유 ...] + +commands.unban.success=플레이어 {%0}님을 차단 해제하였습니다 +commands.unban.usage=/pardon <차단 해제할 플레이어 이름> + +commands.banip.invalid=잘못된 IP 주소이거나 현재 접속해있지 않은 플레이어입니다 +commands.banip.success=IP 주소 {%0}을(를) 차단하였습니다 +commands.banip.success.players={%1}님의 IP 주소 {%0}을(를) 차단하였습니다 +commands.banip.usage=/ban-ip [사유 ...] + +commands.unbanip.invalid=잘못된 IP 주소를 입력하였습니다 +commands.unbanip.success=IP 주소 {%0}의 차단을 해제하였습니다 +commands.unbanip.usage=/pardon-ip + +commands.banipbyname.success=플레이어 {%0}님의 IP를 차단하였습니다 +commands.banipbyname.usage=/banipbyname <플레이어 이름> + +commands.save.usage=/save-all +commands.save-on.usage=/save-on +commands.save-off.usage=/save-off +commands.save.enabled=월드 자동 저장 기능을 활성화하였습니다 +commands.save.disabled=월드 자동 저장 기능을 비활성화하였습니다 +commands.save.start=월드를 저장 중... +commands.save.success=월드를 저장했습니다 + +commands.setblock.usage=/setblock <블럭 이름> [손상 정도] +command.setblock.invalidBlock=잘못된 블럭 이름/ID입니다 + +commands.stop.usage=/stop +commands.stop.start=서버를 끄는 중입니다 + +commands.kick.success={%0}을 게임에서 강제 추방시켰습니다 +commands.kick.success.reason={%0}님이 강제 추방되셨습니다. (사유: {%1}) +commands.kick.usage=/kick <플레이어> [사유 ...] + +commands.tp.success={%0}을(를) {%1}(으)로 이동시켰습니다 +commands.tp.success.coordinates={%0}님을 X:{%1}, Y:{%2}, Z:{%3}(으)로 이동시켰습니다 +commands.tp.usage=/tp [이동시킬 플레이어] <도착 지점 플레이어> 또는 /tp [이동시킬 플레이어] [ ] + +commands.whitelist.list=(보여진 {%1} 중) {%0}명의 화이트리스트 된 플레이어가 있습니다: +commands.whitelist.enabled=화이트리스트 기능을 활성화하였습니다 +commands.whitelist.disabled=화이트리스트 기능을 비활성화하였습니다 +commands.whitelist.reloaded=화이트리스트를 새로고침하였습니다. +commands.whitelist.add.success={%0}님을 화이트리스트에 추가하였습니다 +commands.whitelist.add.usage=/whitelist add <플레이어> +commands.whitelist.remove.success={%0}님을 화이트리스트에서 삭제하였습니다 +commands.whitelist.remove.usage=/whitelist remove <플레이어명> +commands.whitelist.usage=/whitelist + +commands.gamemode.success.self=자신의 게임 모드를 {%2}으로 설정하였습니다 +commands.gamemode.success.other={%1}님의 게임 모드를 {%2}로 설정했습니다 +commands.gamemode.usage=/gamemode <모드> [플레이어명] +commands.help.header=--- 전체 페이지 {%1} 중 {%0}번째 페이지 (/help <페이지>) --- +commands.help.usage=/help [페이지|명령어] +commands.message.usage=/tell <플레이어> <비밀 메시지 ...> +commands.message.sameTarget=자기 자신에게 비밀 메시지를 보낼 수 없습니다! + +commands.difficulty.usage=/difficulty <난이도> +commands.difficulty.success=게임 난이도를 {%0}(으)로 설정하였습니다 + +commands.spawnpoint.usage=/spawnpoint [플레이어] [ ] +commands.spawnpoint.success={%0}의 스폰 위치를 ({%1}, {%2}, {%3})로 설정하였습니다 +commands.setworldspawn.usage=/setworldspawn [ ] +commands.setworldspawn.success=월드의 스폰 지점을 ({%0}, {%1}, {%2})로 설정하였습니다 + +commands.summon.usage=/summon [엔티티] [ ] [NBTTag] + +commands.xp.failure.withdrawXp=0보다 작은 경험치는 줄 수 없습니다 +commands.xp.success=%s에게 경험치 %s을(를) 주었습니다 +commands.xp.success.levels=%s에게 %s 레벨이 지급되었습니다 +commands.xp.success.negative.levels=%s의 레벨을 %s 낮추었습니다 +commands.xp.usage=/xp <수량> [플레이어] 또는 /xp <수량>L [플레이어] + +# -------------------- DevMine language files, only for console -------------------- +DevMine.data.playerNotFound=플레이어 "{%0}"님의 데이터를 찾지 못했습니다. 새 프로필을 생성합니다. +DevMine.data.playerCorrupted=플레이어 "{%0}"님의 데이터가 손상되었습니다. 새로운 프로필을 생성합니다. +DevMine.data.playerOld=플레이어 "{%0}"님의 데이터가 오래되었습니다. 프로필을 업데이트합니다. +DevMine.data.saveError=플레이어 "{%0}"님의 데이터를 저장하지 못했습니다: {%1} +DevMine.level.notFound="{%0}" 월드를 찾지 못했습니다 +DevMine.level.loadError=월드 "{%0}"를(을) 불러오지 못했습니다: {%1} +DevMine.level.generationError=월드 "{%0}"를(을) 생성하지 못했습니다: {%1} +DevMine.level.tickError="{%0}" 월드의 틱을 처리하지 못했습니다: {%1} +DevMine.level.chunkUnloadError=청크 언로드 중 오류가 발생했습니다: {%0} +DevMine.level.backgroundGeneration=월드 "{%0}"의 스폰 지형이 백그라운드에서 생성됩니다... +DevMine.level.defaultError=기본 월드를 찾을 수 없습니다 +DevMine.level.preparing=월드 "{%0}"를(을) 준비 중입니다... +DevMine.level.unloading=월드 "{%0}"를(을) 언로드 중입니다... +DevMine.server.start=마인크래프트: 포켓 에디션 (버전 {%0}용) 서버를 시작 중입니다... +DevMine.server.networkError=[Network] 인터페이스 {%0}가 {%1}로 인해 작동 중단되었습니다. +DevMine.server.networkStart=서버를 {%0}:{%1}에서 여는 중입니다 +DevMine.server.info=이 서버는 {%0} (버전 {%1} "{%2}" (API {%3}))을 구동 중입니다 + +DevMine.server.info.extended.title=-----서버 정보----- +DevMine.server.info.extended1=이 서버는 {%0}{%1} (코드네임 "{%2}")을 구동 중입니다 +DevMine.server.info.extended2=PHP 버전: {%0} +DevMine.server.info.extended3=API: {%0} (iTX API 버전 {%1}) +DevMine.server.info.extended4=대상 클라이언트: Minecraft PE {%0} (프로토콜 버전 {%1}) + +DevMine.server.license={%0}는(은) LGPL 라이센스 하에서 배포됩니다 +DevMine.server.tickOverload=서버 처리 속도가 느려졌습니다. 서버가 과부하되었는지 확인해주시기 바랍니다. +DevMine.server.startFinished=서버 구동 준비 완료! :D ({%0}초) 명령어 목록을 확인하시려면 "help" 또는 "?"를 입력해 주세요. +DevMine.server.defaultGameMode=기본 게임 모드: {%0} +DevMine.server.query.start=GS4 쿼리 리스너를 시작 중입니다 +DevMine.server.query.info=쿼리 포트를 {%0}로 설정합니다 +DevMine.server.query.running=쿼리 서버가 {%0}:{%1}에서 실행 중입니다 + +DevMine.command.alias.illegal=명령어 별칭 {%0}을 등록하지 못했습니다. 잘못된 문자를 포함하고 있습니다. +DevMine.command.alias.notFound=명령어 별칭 {%0}을 등록하지 못했습니다. 존재하지 않는 명령어를 포함합니다: {%1} +DevMine.command.exception=플러그인 {%1}에서 명령어 '{%0}'을 실행하는 중 예외가 발생했습니다: {%2} + +DevMine.commands.cave.usage=/cave <회전 각도> <길이> <지점 번호> <강도> <레벨 이름> | /cave getmypos +DevMine.commands.cave.info=회전 각도:{%0} 길이:{%1} 지점 번호:{%2} 강도:{%3} +DevMine.commands.cave.start=동굴을 생성하는 중입니다. 잠시만 기다리세요 +DevMine.commands.cave.success=동굴이 생성되었습니다 + +DevMine.command.plugins.description=서버에서 실행 중인 플러그인 목록을 불러옵니다. +DevMine.command.plugins.success=플러그인 목록 (전체 {%0}개): {%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=서버 설정과 플러그인을 다시 불러옵니다. +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=서버를 다시 불러오는 중입니다... +DevMine.command.reload.reloaded=서버 설정을 다시 불러왔습니다. + +DevMine.command.lvdat.description=맵의 속성을 변경합니다. +DevMine.command.lvdat.changed=레벨 "{%0}"의 {%1}(을)를 변경하였습니다. 일부 변경은 서버 재부팅이 필요합니다. +DevMine.command.lvdat.fixname=성공적으로 레벨 "{%0}"의 이름을 변경하였습니다. 일부 변경은 서버 재부팅이 필요합니다. +DevMine.command.lvdat.nofound=레벨 "{%0}"이 없거나 로드하지 못했습니다. +DevMine.command.lvdat.preset=생성기 설정 (프리셋) + +DevMine.command.status.description=서버의 현재 상태를 확인합니다 (TPS 등) +DevMine.command.status.usage=/status + +DevMine.command.status.title=서버 상태 +DevMine.command.status.player=플레이어 수: +DevMine.command.status.days=일 +DevMine.command.status.hours=시간 +DevMine.command.status.minutes=분 +DevMine.command.status.seconds=초 +DevMine.command.status.uptime=작업 시간: +DevMine.command.status.AverageTPS=평균 TPS: +DevMine.command.status.CurrentTPS=현재 TPS: +DevMine.command.status.Networkupload=네트워크 업로드: +DevMine.command.status.Networkdownload=네트워크 다운로드: +DevMine.command.status.Threadcount=스레드 수: +DevMine.command.status.Mainmemory=메인 스레드 메모리: +DevMine.command.status.Totalmemory=총 메모리: +DevMine.command.status.Totalvirtualmemory=총 가상 메모리: +DevMine.command.status.Heapmemory=힙 메모리: +DevMine.command.status.Maxmemorysystem=최대 메모리 (시스템): +DevMine.command.status.Maxmemorymanager=최대 메모리 (관리자): +DevMine.command.status.World=월드 +DevMine.command.status.chunks=청크, +DevMine.command.status.entities=엔티티, +DevMine.command.status.tiles=타일. +DevMine.command.status.Time=시간 +DevMine.command.status.ms=ms + +DevMine.command.gc.description=가비지 컬렉션 작업을 시작합니다 +DevMine.command.gc.usage=/gc +DevMine.command.gc.title=모음 보고서 +DevMine.command.gc.chunks=청크: +DevMine.command.gc.entities=엔티티: +DevMine.command.gc.tiles=타일: +DevMine.command.gc.cycles=주기: +DevMine.command.gc.memory=릴리스 메모리: + +DevMine.command.biome.description=영역의 바이옴을 변경합니다.(눈 또는 비 변경) +DevMine.command.biome.posset=위치 {%3}(을)를 다음 위치로 설정하였습니다:({%1},{%2})[{%0}] +DevMine.command.biome.get=현재 당신이 계신 바이옵의 ID는 {%0}입니다. 색상:{%1},{%2},{%3} +DevMine.command.biome.wrongLev=포인트를 각자 다른 레벨에서 설정할 수 없습니다. +DevMine.command.biome.wrongBio=잘못된 바이옴의 ID입니다. e.g. 1 (평야), 2 (사막),13 (얼음 산),6 (습지대) +DevMine.command.biome.wrongCol=잘못된 색입니다. e.g. 146,188,89 ."/biome get"을 사용하여 다른 색을 가져오세요. +DevMine.command.biome.noPos=영역을 선택하려면 먼저 "/biome pos1|pos2"를 사용해주세요. +DevMine.command.biome.set=바이옴을 다음으로 설정하였습니다:{%0} +DevMine.command.biome.color=색을 다음으로 설정하였습니다:{%0},{%1},{%2} + +DevMine.command.timings.description=서버 성능 확인을 위해 타이밍을 기록합니다. +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=타이밍 & 초기화 기능을 활성화하였습니다 +DevMine.command.timings.disable=타이밍이 비활성화되었습니다. +DevMine.command.timings.timingsDisabled=/timings on를 사용하여 타이밍 기능을 활성화해주세요. +DevMine.command.timings.reset=타이밍을 초기화하였습니다 +DevMine.command.timings.pasteError=보고 목록에 붙이는 동안 에러가 발생 하였습니다. +DevMine.command.timings.timingsUpload=타이밍이 {%0}로 업로드가 되었습니다. +DevMine.command.timings.timingsRead=당신은 {%0} 에서 결과를 읽을수 있습니다. +DevMine.command.timings.timingsWrite=타이밍이 {%0}에 써졌습니다. +DevMine.command.version.description=현재 구동되고 있는 서버 버전과 플러그인 정보를 출력합니다. +DevMine.command.version.usage=/version [플러그인 이름] +DevMine.command.version.noSuchPlugin=입력하신 플러그인을 찾을 수 없습니다. /plugins를 입력해 플러그인 목록을 확인하세요. +DevMine.command.give.description=해당 플레이어에게 아이템을 지정한 양만큼 줍니다 +DevMine.command.give.usage=/give <플레이어> <아이템[:손상 정도]> [양] [태그...] +DevMine.command.kill.description=자신 또는 다른 플레이어를 죽입니다 +DevMine.command.kill.usage=/kill [죽일 플레이어] +DevMine.command.particle.description=월드에 파티클을 추가합니다. +DevMine.command.particle.usage=/particle <이름> [양] [데이터] +DevMine.command.time.description=월드 시간을 변경합니다. +DevMine.command.time.usage=/time <값> 또는 /time +DevMine.command.bancidbyname.description=지정된 플레이어의 CID가 서버에 접속할 수 없게 차단합니다 +DevMine.command.bancid.description=지정된 CID가 서버에 들어오지 못하게 차단합니다 +DevMine.command.banipbyname.description=지정된 플레이어의 IP 주소가 서버에 접속할 수 없게 차단합니다 +DevMine.command.ban.player.description=지정된 플레이어가 서버에 들어오지 못하게 차단합니다 +DevMine.command.ban.ip.description=지정된 IP 주소가 서버에 접속할 수 없게 차단합니다 +DevMine.command.banlist.description=이 서버에서 차단한 모든 플레이어 목록을 보여줍니다. +DevMine.command.defaultgamemode.description=기본 게임모드를 설정합니다 +DevMine.command.deop.description=지정된 플레이어의 OP 권한을 해제합니다 +DevMine.command.difficulty.description=게임의 난이도를 설정합니다. +DevMine.command.enchant.description=아이템에 마법을 부여합니다 +DevMine.command.effect.description=플레이어에게 효과를 부여하거나 제거합니다. +DevMine.command.gamemode.description=지정된 플레이어의 게임 모드를 변경합니다 +DevMine.command.help.description=모든 명령어 목록을 보여줍니다. +DevMine.command.kick.description=해당 플레이어를 서버에서 퇴장시킵니다 +DevMine.command.list.description=현재 접속 중인 플레이어의 목록을 보여줍니다 +DevMine.command.me.description=채팅에서 지정된 동작을 합니다 +DevMine.command.op.description=지정된 플레이어에게 OP 권한을 부여합니다 +DevMine.command.unban.cid.description=지정된 CID가 서버를 이용할 수 있도록 차단 해제합니다 +DevMine.command.unban.player.description=해당 플레이어의 차단을 해제합니다. +DevMine.command.unban.ip.description=지정된 IP 주소가 서버를 이용할 수 있도록 차단 해제합니다 +DevMine.command.save.description=서버를 디스크에 저장합니다 +DevMine.command.saveoff.description=서버 자동 저장을 비활성화합니다 +DevMine.command.saveon.description=서버 자동 저장을 활성화합니다 +DevMine.command.say.description=입력된 메시지를 서버 전체에 표시합니다 +DevMine.command.seed.description=월드의 시드를 보여줍니다. +DevMine.command.setworldspawn.description=월드의 부활 지점을 지정합니다. 좌표를 입력하지 않으면 현재 플레이어의 좌표로 지정됩니다. +DevMine.command.spawnpoint.description=플레이어의 부활 지점을 정합니다 +DevMine.command.stop.description=서버를 정지합니다 +DevMine.command.tp.description=해당 플레이어 (또는 자신을) 지정한 플레이어나 좌표로 이동시킵니다 +DevMine.command.tell.description=해당 플레이어에게 개인 메세지를 보냅니다 +DevMine.command.xp.description=지정한 플레이어에게 경험치 또는 경험치 레벨을 줍니다 +DevMine.command.summon.description=플레이어의 위치나 지정된 위치에 엔티티를 생성합니다 +DevMine.command.fill.description=지정한 영역을 블럭으로 채웁니다 +DevMine.command.setblock.description=블럭을 다른 블럭으로 변경합니다 + +DevMine.command.weather.description=레벨의 날씨를 설정합니다 +DevMine.command.weather.usage=/weather <레벨 이름 또는 날씨|날씨 (rain|sunny|clear)> +DevMine.command.weather.changed=성공적으로 레벨 {%0}의 날씨를 변경하였습니다! +DevMine.command.weather.noregistered=레벨 {%0}(은)는 날씨 관리자에 등록되지 않았습니다. +DevMine.command.weather.invalid=잘못된 날씨입니다.(0,1,2,3) +DevMine.command.weather.wrong=잘못된 매개 변수 입니다. +DevMine.command.weather.invalid.level=올바르지 않은 레벨 이름입니다. + +DevMine.command.whitelist.description=서버를 이용할 수 있는 플레이어 목록을 관리합니다 +DevMine.crash.create=복구가 불가능한 오류가 발생하여 서버가 강제로 종료되었습니다. 크래시 덤프를 생성합니다. +DevMine.crash.error=크래시 덤프를 생성하지 못했습니다: {%0} +DevMine.crash.submit="{%0}"파일을 Crash Archive에 업로드하고 버그 리포팅 페이지에 링크를 보내 주세요. 가능한 한 많은 정보를 주시면 감사하겠습니다. +DevMine.crash.archive=크래시 덤프가 자동으로 Crash Archive에 전송되었습니다. {%0}에서 확인하거나 ID #{%1}을 사용하세요. +DevMine.debug.enable=LevelDB 지원이 활성화되었습니다 +DevMine.player.invalidMove={%0}님이 잘못된 움직임을 보였습니다! +DevMine.player.logIn={%0}[/{%1}:{%2}] 이 엔티티 ID {%3} (으)로 ({%4}, {%5}, {%6}, {%7})에 접속했습니다 +DevMine.player.logOut={%0}[/{%1}:{%2}] 님의 연결이 끊어졌습니다. 이유: {%3} +DevMine.player.transferred={%0}[/{%1}:{%2}] 님이 {%3}로 옮겨졌습니다 +DevMine.player.invalidEntity={%0}이 유효하지 않은 엔티티를 공격하려 시도했습니다 +DevMine.plugin.load=플러그인 {%0}을(를) 로딩 중입니다. +DevMine.plugin.enable=플러그인 {%0}을(를) 활성화 중입니다 +DevMine.plugin.disable=플러그인 {%0}을(를) 비활성화 중입니다 +DevMine.plugin.restrictedName=제한된 이름입니다! +DevMine.plugin.incompatibleAPI=호환되지 않는 API 버전입니다! +DevMine.plugin.unknownDependency=알 수 없는 의존 플러그인입니다! +DevMine.plugin.circularDependency=의존성 플러그인입니다. +DevMine.plugin.genericLoadError=플러그인 '{%0}'을(를) 로드하지 못했습니다 +DevMine.plugin.spacesDiscouraged=플러그인 '{%0}'의 이름에 공백 문자가 섞여 있습니다. 이는 권장되지 않습니다. +DevMine.plugin.loadError=플러그인 '{%0}'을(를) 로드하지 못했습니다: {%1} +DevMine.plugin.duplicateError=플러그인 '{%0}'을(를) 로드하지 못했습니다: 이미 존재하는 플러그인입니다 +DevMine.plugin.fileError=폴더 '{%1}'에서 플러그인 '{%0}'을(를) 로드하지 못했습니다: {%2} +DevMine.plugin.commandError=명령어 {%0}을(를) 플러그인 {%1}에서 로드하지 못했습니다 +DevMine.plugin.aliasError=플러그인 {%1}의 명령어 별칭 {%0}을(를) 로드하지 못했습니다 +DevMine.plugin.deprecatedEvent=플러그인 '{%0}'이(가) 이벤트 '{%1}'을(를) 위한 리스너를 메서드 '{%2}'에 대해 추가했지만, 이 이벤트의 사용은 권장되지 않습니다. +DevMine.plugin.eventError="이벤트 '{%0}'을(를) 플러그인 '{%1}'에 전달하지 못했습니다: {%2} ({%3})" diff --git a/src/devmine/utilities/languages/locale/rus.ini b/src/devmine/utilities/languages/locale/rus.ini index 76ef515..c36582d 100644 --- a/src/devmine/utilities/languages/locale/rus.ini +++ b/src/devmine/utilities/languages/locale/rus.ini @@ -1,7 +1,7 @@ # Language file compatible with Minecraft: Pocket Edition identifiers # # A message doesn't need to be there to be shown correctly on the client. -# Only messages shown in devmine itself need to be here +# Only messages shown in DevMine itself need to be here language.name=Russian language.selected=Выбран {%0} ({%1}) в качестве главного языка @@ -9,12 +9,13 @@ language.selected=Выбран {%0} ({%1}) в качестве главного multiplayer.player.joined={%0} присоединился к игре multiplayer.player.left={%0} вышел из игры -chat.type.text=<{%0}> {%1} +chat.type.text={%0} : {%1} chat.type.emote=* {%0} {%1} chat.type.announcement=[{%0}] {%1} chat.type.admin=[{%0}: {%1}] chat.type.achievement=Игрок {%0} получил достижение {%1}! +disconnectionScreen.notAuthenticated=Требуется авторизация в Xbox! disconnectionScreen.outdatedClient=Устаревший клиент! disconnectionScreen.outdatedServer=Устаревший сервер! disconnectionScreen.serverFull=Сервер переполнен! @@ -180,8 +181,8 @@ commands.whitelist.remove.success={%0} убран из вайтлиста commands.whitelist.remove.usage=/whitelist remove <игрок> commands.whitelist.usage=/whitelist -commands.gamemode.success.self=Установлен режим игры {%0} для себя -commands.gamemode.success.other=Игровой режим игрока {%0} изменён на {%1} +commands.gamemode.success.self=Установлен режим игры {%2} для себя +commands.gamemode.success.other=Игровой режим игрока {%1} изменён на {%2} commands.gamemode.usage=/gamemode <игровой режим> [игрок] commands.help.header=--- Отображается страница {%0} из {%1} (/help <страница>) --- commands.help.usage=/help [страница|имя команды] @@ -198,188 +199,190 @@ commands.setworldspawn.usage=/setworldspawn [ ] commands.setworldspawn.success=Установлен респаун мира на ({%0}, {%1}, {%2}) commands.summon.usage=/summon [сущность] [ ] [Имя] -commands.cave.usage=/cave <угол_поворота> <длина> <Номер ветви> <прочность> <название_мира> | /cave getmypos -commands.cave.info=Угол поворота:{%0} Длина:{%1} Номер ветви:{%2} Прочность:{%3} -commands.cave.start=Начало создания пещеры, пожалуйста, подождите! -# -------------------- devmine language files, only for console -------------------- -devmine.data.playerNotFound=Информация об игроке "{%0}" не найдена, создаётся новый профиль -devmine.data.playerCorrupted=Повреждённые данные у игрока "{%0}", создание нового профиля -devmine.data.playerOld=Обнаружен старый профиль игрока "{%0}", обновляем на новый -devmine.data.saveError=Невозможно сохранить игрока "{%0}": {%1} -devmine.level.notFound=Мир "{%0}" не найден -devmine.level.loadError=Невозможно загрузить мир"{%0}": {%1} -devmine.level.generationError=Невозможно сгенерировать уровень "{%0}": {%1} -devmine.level.tickError=Ошибка прорисовки мира "{%0}": {%1} -devmine.level.chunkUnloadError=Ошибка при выгрузке чанка: {%0} -devmine.level.backgroundGeneration=Генерируется территория спауна для мира "{%0}" -devmine.level.defaultError=Мир по умолчанию не загружен -devmine.level.preparing=Подготовка мира "{%0}" -devmine.level.unloading=Выгрузка мира "{%0}" -devmine.server.start=Запускается сервер Minecraft: PE версии {%0} -devmine.server.networkError=[Сеть] Остановлен интерфейс {%0} из-за {%1} -devmine.server.networkStart=Открытие сервера на {%0}:{%1} -devmine.server.info.extended=Сервер использует {%0} {%1}「 {%2}」 , версия API {%3} для Minecraft: PE {%4} (версия протокола {%5}) -devmine.server.info=Этот сервер использует {%0}, версию {%1} "{%2}" (API {%3}) -devmine.server.license={%0} распространяется под лицензией LGPL -devmine.server.tickOverload=Сервер перегружен! -devmine.server.startFinished=Загружено ({%0} секунд)! Для справки введите "help" или "?" -devmine.server.defaultGameMode=Игровой режим по умолчанию: {%0} -devmine.server.query.start=Запуск прослушивателя статуса GS4 -devmine.server.query.info=Установлен порт query на {%0} -devmine.server.query.running=Query запущен на {%0}:{%1} - -devmine.command.alias.illegal=Невозможно зарегистрировать альтернативу команды {%0}, поскольку он содержит недопустимые знаки -devmine.command.alias.notFound=Невозможно зарегистрировать альтернативу команды {%0}, поскольку он содержит недопустимые команды: {%1} -devmine.command.exception=Необработанное исключение при выполнении команды '{%0}' в {%1}: {%2} - -devmine.command.plugins.description=Получить список установленых плагинов на этом сервере -devmine.command.plugins.success=Плагины ({%0}): {%1} -devmine.command.plugins.usage=/plugins - -devmine.command.reload.description=Перезагрузить настройки сервера и плагины -devmine.command.reload.usage=/reload -devmine.command.reload.reloading=Перезагрузка сервера... -devmine.command.reload.reloaded=Перезагрузка завершена. - -devmine.command.lvdat.description=Изменить настройки карты. -devmine.command.lvdat.changed=Был сменена настройка {%1} для мира "{%0}", для применения некоторых изменений нужна перезагрузка. -devmine.command.lvdat.fixname=Имя для мира "{%0}" было успешно исправлено, для применения некоторых изменений нужна перезагрузка. -devmine.command.lvdat.nofound=Мир "{%0}" не найден или не загружен. -devmine.command.lvdat.preset=Настройки генератора (пресеты) - -devmine.command.status.description=Отображает производительность сервера. -devmine.command.status.usage=/status -devmine.command.status.title=Статус сервера -devmine.command.status.player=Число игроков: -devmine.command.status.days=дн. -devmine.command.status.hours=ч -devmine.command.status.minutes=мин -devmine.command.status.seconds=сек -devmine.command.status.uptime=Аптайм: -devmine.command.status.AverageTPS=Средний TPS: -devmine.command.status.CurrentTPS=Текущий TPS: -devmine.command.status.Networkupload=Данных отправлено: -devmine.command.status.Networkdownload=Данных получено: -devmine.command.status.Threadcount=Количество потоков: -devmine.command.status.Mainmemory=Основная память потока; -devmine.command.status.Totalmemory=Общая память: -devmine.command.status.Totalvirtualmemory=Общая виртуальная память: -devmine.command.status.Heapmemory=Heap memory: -devmine.command.status.Maxmemorysystem=Максимальная память (системы): -devmine.command.status.Maxmemorymanager=Максимальная память (менеджер): -devmine.command.status.World=Мир -devmine.command.status.chunks=чанков, -devmine.command.status.entities=сущностей, -devmine.command.status.solidentities=тайлов. -devmine.command.status.Time=Время -devmine.command.status.ms=мс -devmine.command.gc.description=Запускает процессы сборщика мусора -devmine.command.gc.usage=/gc -devmine.command.gc.title=Отчёт очистки -devmine.command.gc.chunks=Чанков: -devmine.command.gc.entities=Сущностей: -devmine.command.gc.solidentities=Тайлов: -devmine.command.gc.cycles=Циклов: -devmine.command.gc.memory=Освобождённая память: - -devmine.command.biome.description=Изменяет биом выделенной области. (Для смены снега на дождь) -devmine.command.biome.posset=Установлена точка {%3} на позиции: ({%1},{%2})[{%0}] -devmine.command.biome.get=ID биома, где ты стоишь: {%0}. Цвет:{%1},{%2},{%3} -devmine.command.biome.wrongLev=Нельзя устанавливать точки в разнымх мирах. -devmine.command.biome.wrongBio=Неверный ID биома. Пример: 1 (Равнины), 2 (Пустыня),13 (Ледяные горы),6 (Болото) -devmine.command.biome.wrongCol=Неверный цвет! Пример: 146,188,89. Используй: "/biome get" чтобы получить остальные цвета. -devmine.command.biome.noPos=Используйте "/biome pos1|pos2" чтобы отметить точки. -devmine.command.biome.set=Был установлен цвет:{%0} -devmine.command.biome.color=Выбран цвет: {%0},{%1},{%2} - -devmine.command.timings.description=Записывает тайминги, чтобы показать производительность сервера. -devmine.command.timings.usage=/timings -devmine.command.timings.enable=Тайминги включены и сброшены. -devmine.command.timings.disable=Тайминги выключены -devmine.command.timings.timingsDisabled=Пожалуйста, включите тайминги, набрав в чате /timings on -devmine.command.timings.reset=Тайминги сброшены -devmine.command.timings.pasteError=Произошла ошибка при сохранении таймингов -devmine.command.timings.timingsUpload=Тайминги загружены в {%0} -devmine.command.timings.timingsRead=Вы можете прочесть результаты таймингов в {%0} -devmine.command.timings.timingsWrite=Тайминги записаны в {%0} - -devmine.command.version.description=Получает версию сервера, включая все используемые плагины -devmine.command.version.usage=/version [имя плагина] -devmine.command.version.noSuchPlugin=Этот сервер не использует плагин с таким именем. Используйте /plugins, чтобы получить список используемых плагинов. -devmine.command.give.description=Даёт определённому игроку определённое количество предметов -devmine.command.give.usage=/give <игрок> <предмет[:урон]> [количество] [тэги...] -devmine.command.kill.description=Совершает суицид или убивает других игроков -devmine.command.kill.usage=/kill [игрок] -devmine.command.particle.description=Добавляет частицы в мир -devmine.command.particle.usage=/particle <имя> [значение] [данные] -devmine.command.time.description=Изменяет время в каждом мире -devmine.command.time.usage=/time ИЛИ /time -devmine.command.bancidbyname.description=Бан игрока по уникальному номеру устройства -devmine.command.bancid.description=Бан уникального номера устройства -devmine.command.banipbyname.description=Бан игрока по IP -devmine.command.ban.player.description=Бан игрока -devmine.command.ban.ip.description=Бан IP-адреса -devmine.command.banlist.description=Список забаненных игроков -devmine.command.defaultgamemode.description=Устанавливает режим игры по умолчанию -devmine.command.deop.description=Убирает статус оператора с определённого игрока -devmine.command.difficulty.description=Устанавливает сложность игры -devmine.command.enchant.description=Добавляет зачарование предметам -devmine.command.effect.description=Добавляет/Убирает эффекты у игроков -devmine.command.gamemode.description=Изменяет режим игры у игрока -devmine.command.help.description=Показывает меню помощи -devmine.command.kick.description=Заставить выйти определённого игрока с сервера -devmine.command.list.description=Показывает всех игроков на сервере -devmine.command.me.description=Выполняет указанное действие в чате -devmine.command.op.description=Даёт определённому игроку статус оператора -devmine.command.unban.cid.description=Разбан уникального номера устройства игрока -devmine.command.unban.player.description=Разбан игрока по нику -devmine.command.unban.ip.description=Разбан IP-адреса игрока -devmine.command.save.description=Сохраняет все файлы сервера -devmine.command.saveoff.description=Отключает автосохранение сервера -devmine.command.saveon.description=Включает автосохранение сервера -devmine.command.say.description=Транслирует сообщение в чат -devmine.command.seed.description=Показывает сид мира -devmine.command.setworldspawn.description=Устанавливает точку респауна мира. Если координаты не введены, будут использованы координаты игрока. -devmine.command.spawnpoint.description=Устанавливает точку возрождения игрока -devmine.command.stop.description=Выключает сервер -devmine.command.tp.description=Телепортирует определённого игрока (или Вас) к другому игроку или на другие координаты -devmine.command.tell.description=Отправляет приватное сообщение указанному игроку -devmine.command.xp.description=Добавляет опыт или уровень опыта игроку -devmine.command.summon.description=Создаёт сущность по установленным координатам или координатом игрока -devmine.command.fill.description=Заполняет выделенную область блоками -devmine.command.setblock.description=Заменяет блок по координатам - -devmine.command.weather.description=Установка погоды в мире -devmine.command.weather.usage=/weather <мир> (0,1,2,3) -devmine.command.weather.changed=Погода успешно изменена в мире {%0}! -devmine.command.weather.noregistered=Мир {%0} не был зарегистрирован в менеджере погоды. -devmine.command.weather.invalid=Некорректная погода.(0,1,2,3) -devmine.command.weather.wrong=Некорректные параметры. -devmine.command.weather.invalid.level=Некорректное имя мира. -devmine.command.whitelist.description=Управление вайтлистом сервера -devmine.crash.create=Произошла фатальная ошибка и сервер вышел из строя. Создание аварийного дампа -devmine.crash.error=Не удалось создать дамп: {%0} -devmine.crash.submit=Пожалуйста, загрузите файл"{%0}" в краш-архив и отправьте ссылку на страницу исправления ошибок. Дайте как можно больше информации. -devmine.crash.archive=Дамп выхода из строя сервера был автоматически отправлен в краш-архив. Вы можете его просмотреть тут: {%0}, или использовать ID #{%1}. -devmine.debug.enable=Поддержка LevelDB включена -devmine.player.invalidMove={%0} некорректно передвинулся! -devmine.player.logIn={%0}[/{%1}:{%2}] вошел с id сущности {%3} на ({%4}, {%5}, {%6}, {%7}) -devmine.player.logOut={%0}[/{%1}:{%2}] отключился: {%3} -devmine.player.transferred={%0}[/{%1}:{%2}] был перемещен в {%3} -devmine.player.invalidEntity={%0} попытался атаковать неправильную сущность -devmine.plugin.load=Загрузка {%0} -devmine.plugin.enable=Включение {%0} -devmine.plugin.disable=Выключение {%0} -devmine.plugin.restrictedName=Ограниченное имя -devmine.plugin.incompatibleAPI=Несовместимая версия API -devmine.plugin.unknownDependency=Неизвестная зависимость -devmine.plugin.circularDependency=Обнаружена круговая зависимость -devmine.plugin.genericLoadError=Невозможно загрузить плагин '{%0}' -devmine.plugin.spacesDiscouraged=Плагин '{%0}' использует пробелы в его имени, это недопустимо -devmine.plugin.loadError=Невозможно загрузить плагин '{%0}': {%1} -devmine.plugin.duplicateError=Невозможно загрузить '{%0}': плагин уже существует -devmine.plugin.fileError=Невозможно загрузить '{%0}' в папке '{%1}': {%2} -devmine.plugin.commandError=Невозможно загрузить команду {%0} для плагина {%1} -devmine.plugin.aliasError=Невозможно загрузить сокращение {%0} для плагина {%1} -devmine.plugin.deprecatedEvent=Плагин '{%0}' зарегистрировал прослушивателя для '{%1}', используя метод '{%2}', но событие было отменено. -devmine.plugin.eventError="Невозможно обработать событие '{%0}' в '{%1}': {%2} в {%3}" + +# -------------------- DevMine language files, only for console -------------------- +DevMine.data.playerNotFound=Информация об игроке "{%0}" не найдена, создаётся новый профиль +DevMine.data.playerCorrupted=Повреждённые данные у игрока "{%0}", создание нового профиля +DevMine.data.playerOld=Обнаружен старый профиль игрока "{%0}", обновляем на новый +DevMine.data.saveError=Невозможно сохранить игрока "{%0}": {%1} +DevMine.level.notFound=Мир "{%0}" не найден +DevMine.level.loadError=Невозможно загрузить мир"{%0}": {%1} +DevMine.level.generationError=Невозможно сгенерировать уровень "{%0}": {%1} +DevMine.level.tickError=Ошибка прорисовки мира "{%0}": {%1} +DevMine.level.chunkUnloadError=Ошибка при выгрузке чанка: {%0} +DevMine.level.backgroundGeneration=Генерируется территория спауна для мира "{%0}" +DevMine.level.defaultError=Мир по умолчанию не загружен +DevMine.level.preparing=Подготовка мира "{%0}" +DevMine.level.unloading=Выгрузка мира "{%0}" +DevMine.server.start=Запускается сервер Minecraft: PE версии {%0} +DevMine.server.networkError=[Сеть] Остановлен интерфейс {%0} из-за {%1} +DevMine.server.networkStart=Открытие сервера на {%0}:{%1} +DevMine.server.info.extended=Сервер использует {%0} {%1}「 {%2}」 , версия API {%3} для Minecraft: PE {%4} (версия протокола {%5}) +DevMine.server.info=Этот сервер использует {%0}, версию {%1} "{%2}" (API {%3}) +DevMine.server.license={%0} распространяется под лицензией LGPL +DevMine.server.tickOverload=Сервер перегружен! +DevMine.server.startFinished=Загружено ({%0} секунд)! Для справки введите "help" или "?" +DevMine.server.defaultGameMode=Игровой режим по умолчанию: {%0} +DevMine.server.query.start=Запуск прослушивателя статуса GS4 +DevMine.server.query.info=Установлен порт query на {%0} +DevMine.server.query.running=Query запущен на {%0}:{%1} + +DevMine.command.alias.illegal=Невозможно зарегистрировать альтернативу команды {%0}, поскольку он содержит недопустимые знаки +DevMine.command.alias.notFound=Невозможно зарегистрировать альтернативу команды {%0}, поскольку он содержит недопустимые команды: {%1} +DevMine.command.exception=Необработанное исключение при выполнении команды '{%0}' в {%1}: {%2} + +DevMine.commands.cave.usage=/cave <угол_поворота> <длина> <Номер ветви> <прочность> <название_мира> | /cave getmypos +DevMine.commands.cave.info=Угол поворота:{%0} Длина:{%1} Номер ветви:{%2} Прочность:{%3} +DevMine.commands.cave.start=Начало создания пещеры, пожалуйста, подождите! + +DevMine.command.plugins.description=Получить список установленых плагинов на этом сервере +DevMine.command.plugins.success=Плагины ({%0}): {%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=Перезагрузить настройки сервера и плагины +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=Перезагрузка сервера... +DevMine.command.reload.reloaded=Перезагрузка завершена. + +DevMine.command.lvdat.description=Изменить настройки карты. +DevMine.command.lvdat.changed=Был сменена настройка {%1} для мира "{%0}", для применения некоторых изменений нужна перезагрузка. +DevMine.command.lvdat.fixname=Имя для мира "{%0}" было успешно исправлено, для применения некоторых изменений нужна перезагрузка. +DevMine.command.lvdat.nofound=Мир "{%0}" не найден или не загружен. +DevMine.command.lvdat.preset=Настройки генератора (пресеты) + +DevMine.command.status.description=Отображает производительность сервера. +DevMine.command.status.usage=/status +DevMine.command.status.title=Статус сервера +DevMine.command.status.player=Число игроков: +DevMine.command.status.days=дн. +DevMine.command.status.hours=ч +DevMine.command.status.minutes=мин +DevMine.command.status.seconds=сек +DevMine.command.status.uptime=Аптайм: +DevMine.command.status.AverageTPS=Средний TPS: +DevMine.command.status.CurrentTPS=Текущий TPS: +DevMine.command.status.Networkupload=Данных отправлено: +DevMine.command.status.Networkdownload=Данных получено: +DevMine.command.status.Threadcount=Количество потоков: +DevMine.command.status.Mainmemory=Основная память потока: +DevMine.command.status.Totalmemory=Общая память: +DevMine.command.status.Totalvirtualmemory=Общая виртуальная память: +DevMine.command.status.Heapmemory=Heap memory: +DevMine.command.status.Maxmemorysystem=Максимальная память (системы): +DevMine.command.status.Maxmemorymanager=Максимальная память (менеджер): +DevMine.command.status.World=Мир +DevMine.command.status.chunks=чанков, +DevMine.command.status.entities=сущностей, +DevMine.command.status.tiles=тайлов. +DevMine.command.status.Time=Время +DevMine.command.status.ms=мс +DevMine.command.gc.description=Запускает процессы сборщика мусора +DevMine.command.gc.usage=/gc +DevMine.command.gc.title=Отчёт очистки +DevMine.command.gc.chunks=Чанков: +DevMine.command.gc.entities=Сущностей: +DevMine.command.gc.tiles=Тайлов: +DevMine.command.gc.cycles=Циклов: +DevMine.command.gc.memory=Освобождённая память: + +DevMine.command.biome.description=Изменяет биом выделенной области. (Для смены снега на дождь) +DevMine.command.biome.posset=Установлена точка {%3} на позиции: ({%1},{%2})[{%0}] +DevMine.command.biome.get=ID биома, где ты стоишь: {%0}. Цвет:{%1},{%2},{%3} +DevMine.command.biome.wrongLev=Нельзя устанавливать точки в разнымх мирах. +DevMine.command.biome.wrongBio=Неверный ID биома. Пример: 1 (Равнины), 2 (Пустыня),13 (Ледяные горы),6 (Болото) +DevMine.command.biome.wrongCol=Неверный цвет! Пример: 146,188,89. Используй: "/biome get" чтобы получить остальные цвета. +DevMine.command.biome.noPos=Используйте "/biome pos1|pos2" чтобы отметить точки. +DevMine.command.biome.set=Был установлен цвет:{%0} +DevMine.command.biome.color=Выбран цвет: {%0},{%1},{%2} + +DevMine.command.timings.description=Записывает тайминги, чтобы показать производительность сервера. +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=Тайминги включены и сброшены. +DevMine.command.timings.disable=Тайминги выключены +DevMine.command.timings.timingsDisabled=Пожалуйста, включите тайминги, набрав в чате /timings on +DevMine.command.timings.reset=Тайминги сброшены +DevMine.command.timings.pasteError=Произошла ошибка при сохранении таймингов +DevMine.command.timings.timingsUpload=Тайминги загружены в {%0} +DevMine.command.timings.timingsRead=Вы можете прочесть результаты таймингов в {%0} +DevMine.command.timings.timingsWrite=Тайминги записаны в {%0} + +DevMine.command.version.description=Получает версию сервера, включая все используемые плагины +DevMine.command.version.usage=/version [имя плагина] +DevMine.command.version.noSuchPlugin=Этот сервер не использует плагин с таким именем. Используйте /plugins, чтобы получить список используемых плагинов. +DevMine.command.give.description=Даёт определённому игроку определённое количество предметов +DevMine.command.give.usage=/give <игрок> <предмет[:урон]> [количество] [тэги...] +DevMine.command.kill.description=Совершает суицид или убивает других игроков +DevMine.command.kill.usage=/kill [игрок] +DevMine.command.particle.description=Добавляет частицы в мир +DevMine.command.particle.usage=/particle <имя> [значение] [данные] +DevMine.command.time.description=Изменяет время в каждом мире +DevMine.command.time.usage=/time ИЛИ /time +DevMine.command.bancidbyname.description=Бан игрока по уникальному номеру устройства +DevMine.command.bancid.description=Бан уникального номера устройства +DevMine.command.banipbyname.description=Бан игрока по IP +DevMine.command.ban.player.description=Бан игрока +DevMine.command.ban.ip.description=Бан IP-адреса +DevMine.command.banlist.description=Список забаненных игроков +DevMine.command.defaultgamemode.description=Устанавливает режим игры по умолчанию +DevMine.command.deop.description=Убирает статус оператора с определённого игрока +DevMine.command.difficulty.description=Устанавливает сложность игры +DevMine.command.enchant.description=Добавляет зачарование предметам +DevMine.command.effect.description=Добавляет/Убирает эффекты у игроков +DevMine.command.gamemode.description=Изменяет режим игры у игрока +DevMine.command.help.description=Показывает меню помощи +DevMine.command.kick.description=Заставить выйти определённого игрока с сервера +DevMine.command.list.description=Показывает всех игроков на сервере +DevMine.command.me.description=Выполняет указанное действие в чате +DevMine.command.op.description=Даёт определённому игроку статус оператора +DevMine.command.unban.cid.description=Разбан уникального номера устройства игрока +DevMine.command.unban.player.description=Разбан игрока по нику +DevMine.command.unban.ip.description=Разбан IP-адреса игрока +DevMine.command.save.description=Сохраняет все файлы сервера +DevMine.command.saveoff.description=Отключает автосохранение сервера +DevMine.command.saveon.description=Включает автосохранение сервера +DevMine.command.say.description=Транслирует сообщение в чат +DevMine.command.seed.description=Показывает сид мира +DevMine.command.setworldspawn.description=Устанавливает точку респауна мира. Если координаты не введены, будут использованы координаты игрока. +DevMine.command.spawnpoint.description=Устанавливает точку возрождения игрока +DevMine.command.stop.description=Выключает сервер +DevMine.command.tp.description=Телепортирует определённого игрока (или Вас) к другому игроку или на другие координаты +DevMine.command.tell.description=Отправляет приватное сообщение указанному игроку +DevMine.command.xp.description=Добавляет опыт или уровень опыта игроку +DevMine.command.summon.description=Создаёт сущность по установленным координатам или координатом игрока +DevMine.command.fill.description=Заполняет выделенную область блоками +DevMine.command.setblock.description=Заменяет блок по координатам + +DevMine.command.weather.description=Установка погоды в мире +DevMine.command.weather.usage=/weather <мир> (0,1,2,3) +DevMine.command.weather.changed=Погода успешно изменена в мире {%0}! +DevMine.command.weather.noregistered=Мир {%0} не был зарегистрирован в менеджере погоды. +DevMine.command.weather.invalid=Некорректная погода.(0,1,2,3) +DevMine.command.weather.wrong=Некорректные параметры. +DevMine.command.weather.invalid.level=Некорректное имя мира. +DevMine.command.whitelist.description=Управление вайтлистом сервера +DevMine.crash.create=Произошла фатальная ошибка и сервер вышел из строя. Создание аварийного дампа +DevMine.crash.error=Не удалось создать дамп: {%0} +DevMine.crash.submit=Пожалуйста, загрузите файл"{%0}" в краш-архив и отправьте ссылку на страницу исправления ошибок. Дайте как можно больше информации. +DevMine.crash.archive=Дамп выхода из строя сервера был автоматически отправлен в краш-архив. Вы можете его просмотреть тут: {%0}, или использовать ID #{%1}. +DevMine.debug.enable=Поддержка LevelDB включена +DevMine.player.invalidMove={%0} некорректно передвинулся! +DevMine.player.logIn={%0}[/{%1}:{%2}] вошел с id сущности {%3} на ({%4}, {%5}, {%6}, {%7}) +DevMine.player.logOut={%0}[/{%1}:{%2}] отключился: {%3} +DevMine.player.transferred={%0}[/{%1}:{%2}] был перемещен в {%3} +DevMine.player.invalidEntity={%0} попытался атаковать неправильную сущность +DevMine.plugin.load=Загрузка {%0} +DevMine.plugin.enable=Включение {%0} +DevMine.plugin.disable=Выключение {%0} +DevMine.plugin.restrictedName=Ограниченное имя +DevMine.plugin.incompatibleAPI=Несовместимая версия API +DevMine.plugin.unknownDependency=Неизвестная зависимость +DevMine.plugin.circularDependency=Обнаружена круговая зависимость +DevMine.plugin.genericLoadError=Невозможно загрузить плагин '{%0}' +DevMine.plugin.spacesDiscouraged=Плагин '{%0}' использует пробелы в его имени, это недопустимо +DevMine.plugin.loadError=Невозможно загрузить плагин '{%0}': {%1} +DevMine.plugin.duplicateError=Невозможно загрузить '{%0}': плагин уже существует +DevMine.plugin.fileError=Невозможно загрузить '{%0}' в папке '{%1}': {%2} +DevMine.plugin.commandError=Невозможно загрузить команду {%0} для плагина {%1} +DevMine.plugin.aliasError=Невозможно загрузить сокращение {%0} для плагина {%1} +DevMine.plugin.deprecatedEvent=Плагин '{%0}' зарегистрировал прослушивателя для '{%1}', используя метод '{%2}', но событие было отменено. +DevMine.plugin.eventError="Невозможно обработать событие '{%0}' в '{%1}': {%2} в {%3}" diff --git a/src/devmine/utilities/languages/locale/tur.ini b/src/devmine/utilities/languages/locale/tur.ini new file mode 100644 index 0000000..d934df8 --- /dev/null +++ b/src/devmine/utilities/languages/locale/tur.ini @@ -0,0 +1,311 @@ + + +language.name=Türkçe +language.selected={%0} ({%1}) konsol dili olarak seçildi + +multiplayer.player.joined={%0} oyuna katıldı +multiplayer.player.left={%0} oyundan ayrıldı + +chat.type.text={%0} : {%1} +chat.type.achievement={%0} adlı oyuncu {%1} başarımını kazandı + +disconnectionScreen.outdatedClient=Eski sürüm! +disconnectionScreen.outdatedServer=Sunucu daha eski bir sürümde! +disconnectionScreen.serverFull=Sunucu dolu! +disconnectionScreen.noReason=Sunucu ile olan bağlantınız kesildi +disconnectionScreen.invalidSkin=Geçersiz skin! +disconnectionScreen.invalidName=Geçersiz isim! + +death.fell.accident.generic={%0} Yüksekten düşerek öldü +death.attack.inFire={%0} yanarak öldü +death.attack.onFire={%0} yanarak can verdi +death.attack.lava={%0} lavda yüzmeye çalıştı +death.attack.inWall={%0} duvarda sıkışarak öldü +death.attack.drown={%0} boğuldu +death.attack.cactus={%0} delinerek öldü +death.attack.generic={%0} öldü +death.attack.explosion={%0} patlayarak öldü +death.attack.explosion.player={%0}, {%1} tarafından havaya uçuruldu +death.attack.magic={%0} sihirlenerek öldürüldü +death.attack.wither={%0} witherlanarak öldü +death.attack.mob={%0}, {%1} tarafından öldürüldü +death.attack.player={%0}, {%1} tarafından öldürüldü +death.attack.player.item={%0}, {%1} tarafından {%2} kullanılarak öldürüldü +death.attack.arrow={%0}, {%1} tarafından vuruldu +death.attack.arrow.item={%0}, {%1} adlı oyuncuyu {%2} kullanarak vurdu +death.attack.fall={%0} yüksekten düşerek öldü +death.attack.outOfWorld={%0} dünyadan aşağı düşerek can verdi + +gameMode.survival=Hayatta Kalma Modu +gameMode.creative=Yaratıcı Mod +gameMode.adventure=Maceracı Mod +gameMode.spectator=İzleyici Mod +gameMode.changed=Oyun modunuz güncellendi + +potion.moveSpeed=Hız +potion.moveSlowdown=Yavaşlık +potion.digSpeed=Sürat +potion.digSlowDown=Kazı Yorgunluğu +potion.damageBoost=Güç +potion.heal=Anında Can +potion.harm=Anlık Zarar +potion.jump=Zıplama Artışı +potion.confusion=Bulantı +potion.regeneration=Yenilenme +potion.resistance=Dayanıklılık +potion.fireResistance=Ateş Dayanıklılığı +potion.waterBreathing=Suda Nefes Alma +potion.invisibility=Görünmezlik +potion.blindness=Körlük +potion.nightVision=Gece Görüşü +potion.hunger=Açlık +potion.weakness=Zayıflık +potion.poison=Zehir +potion.wither=Wither +potion.healthBoost=Can Artışı +potion.absorption=Emme +potion.saturation=Doyma + +commands.generic.exception=Komut uygulanırken bilinmeyen bir hata oluştu +commands.generic.permission=Bu komutu kullanma yetkiniz yok! +commands.generic.notFound=Bilinmeyen komut. Tüm komutları görmek için /help yazınız +commands.generic.player.notFound=Belirtilen oyuncu bulunamadı +commands.generic.usage=Kullanış: {%0} + +commands.time.added=Saate {%0} eklendi +commands.time.set=Dünya saati şu saate ayarlandı: {%0} +commands.time.query=Dünya saati: {%0} + +commands.me.usage=/me + +commands.give.item.notFound=Belirtilen eşya bulunamıyor: {%0} +commands.give.success={%0} * {%1}, {%2}'ye verildi +commands.give.tagError=Veri başlığı ayrıştırması başarısız oldu: {%0} +commands.effect.usage=/effect [saniye] [yükselme] [EfektleriGizle] yada /effect clear +commands.effect.notFound=Bilinmeyen efekt: {%0} +commands.effect.success={%3} adlı oyuncuya {%4} saniyeliğine {%0} (ID {%1}) * {%2} verildi +commands.effect.success.removed={%0}, {%1}'den alındı +commands.effect.success.removed.all={%0} adlı oyuncunun bütün efektleri alındı +commands.effect.failure.notActive={%0} adlı oyuncudan {%1} efekti alınamadı. Çünkü bu efekte sahip değil +commands.effect.failure.notActive.all={%0} adlı oyuncunun efektleri alınamadı. Çünkü hiç bir efekte sahip değil + +commands.enchant.noItem=Hedefin elinde eşya tutmuyor +commands.enchant.notFound={%0} kodunda bir büyü yok +commands.enchant.success=Büyü işlemi başarılı +commands.enchant.usage=/enchant [seviye] + +commands.particle.success={%0} efekti {%1} kere oynatılıyor +commands.particle.notFound={%0} - Bilinmeyen efekt ismi. + +commands.players.usage=/list +commands.players.list=Çevrimiçi oyuncular: {%0}/{%1} + +commands.kill.successful={%0} adlı oyuncu öldürüldü + +commands.banlist.ips=Toplam %d adet engellenmiş IP adresi var: +commands.banlist.players=Toplam {%0} adet engellenmiş oyuncu var: +commands.banlist.usage=/banlist [ips|players] + +commands.defaultgamemode.usage=/defaultgamemode +commands.defaultgamemode.success=Dünyanın varsayılan oyun modu artık : {%0} + +commands.op.success={%0} adlı kullanıcıya OP yetkisi verildi. +commands.op.usage=/op + +commands.deop.success={%0} adlı kullanıcının OP yetkisi alındı. +commands.deop.usage=/deop + +commands.say.usage=/say + +commands.seed.usage=/seed +commands.seed.success=Seed: {%0} + +commands.ban.success={%0} adlı oyuncu banlandı +commands.ban.usage=/ban [sebep...] + +commands.unban.success={%0} adlı oyuncunun engeli kaldırıldı +commands.unban.usage=/pardon + +commands.banip.invalid=Bilinmeyen IP adresi veya çevrimiçi olmayan oyuncu adı girdiniz +commands.banip.success={%0} IP adresi engellendi +commands.banip.success.players=Engellenen IP adresi {%0}, {%1} kullanıcısına ait +commands.banip.usage=/ban-ip [sebep ...] + +commands.unbanip.invalid=Geçersiz IP adresi girdiniz +commands.unbanip.success={%0} IP adresinin engeli kaldırıldı +commands.unbanip.usage=/pardon-ip + +commands.save.usage=/save-all +commands.save-on.usage=/save-on +commands.save-off.usage=/save-off +commands.save.enabled=Otomatik kaydetme özelliği etkinleştirildi +commands.save.disabled=Otomatik kaydetme özelliği devre dışı +commands.save.start=Kaydediliyor... +commands.save.success=Dünya kaydedildi + +commands.stop.usage=/stop +commands.stop.start=Sunucu durduruluyor + +commands.kick.success={%0} oyundan atıldı +commands.kick.success.reason={%0} oyundan atıldı: '{%1}' +commands.kick.usage=/kick [sebep ...] + +commands.tp.success={%0}, {%1} adlı oyuncuya ışınlandı +commands.tp.success.coordinates={%0} adlı oyuncu {%1}, {%2}, {%3} koordinatlarına ışınlandı +commands.tp.usage=/tp [oyuncu1] yada /tp [oyuncu] [ ] + +commands.whitelist.list=Toplam {%0} (görünen {%1}) whitelist oyuncusu var: +commands.whitelist.enabled=Whitelist aktif edildi +commands.whitelist.disabled=Whitelist deaktif edildi +commands.whitelist.reloaded=Whitelist yeniden yüklendi +commands.whitelist.add.success={%0} adlı oyuncu whitelist listesine eklendi +commands.whitelist.add.usage=/whitelist add +commands.whitelist.remove.success={%0} adlı oyuncu whitelist listesinden kaldırıldı +commands.whitelist.remove.usage=/whitelist remove +commands.whitelist.usage=/whitelist + +commands.gamemode.success.self=Oyun modunuz {%2} moduna değiştirildi +commands.gamemode.success.other={%1} adlı oyuncunun oyun modu {%2} moduna değiştirildi +commands.gamemode.usage=/gamemode [oyuncu] + +commands.help.header=--- Yardım sayfası {%0} / {%1} (/help ) --- +commands.help.usage=/help [sayfa|komut adı] + +commands.message.usage=/tell +commands.message.sameTarget=Kendinize mesaj yollayamazsınız! + +commands.difficulty.usage=/difficulty +commands.difficulty.success=Oyun zorluk seviyesi başarıyla değiştirildi! + +commands.spawnpoint.usage=/spawnpoint [oyuncu] [ ] +commands.spawnpoint.success={%0} adlı oyuncunun başlangıç noktası ({%1}, {%2}, {%3}) koordinatlarına olarak değiştirildi + +commands.setworldspawn.usage=/setworldspawn [ ] +commands.setworldspawn.success=Dünya başlangıç noktası ({%0}, {%1}, {%2}) koordinatlarına değiştirildi + + + +DevMine.data.playerNotFound=Oyuncu verisi bulunamadı: "{%0}", yeni profil oluşturuluyor +DevMine.data.playerCorrupted=Bozuk veri "{%0}" bulunamadı, yeni profil oluşturuluyor +DevMine.data.playerOld=Eski veri "{%0}" bulundu, profil güncelleniyor +DevMine.data.saveError=Oyuncu kaydedilemiyor "{%0}": {%1} + +DevMine.level.notFound=Dünya "{%0}" bulunamadı +DevMine.level.loadError=Dünya yüklenmiyor "{%0}": {%1} +DevMine.level.generationError=Dünya oluşturulamıyor "{%0}": {%1} +DevMine.level.tickError=Dünya işaretlenemiyor "{%0}": {%1} +DevMine.level.chunkUnloadError=Chunk yüklemesi kaldırılırken hata: {%0} +DevMine.level.backgroundGeneration=Spawn bölgesi "{%0}" oluşturulmaya başlandı +DevMine.level.defaultError=Varsayılan dünya yüklenemedi +DevMine.level.preparing=Dünya hazırlanıyor: "{%0}" +DevMine.level.unloading=Dünya yüklemesi kaldırılıyor "{%0}" + +DevMine.server.start=Minecraft: PE sunucu versiyonu {%0} başlatılıyor +DevMine.server.networkError=[Şebeke] Arayüz {%1} için {%0} nedeniyle durduruldu +DevMine.server.networkStart=Sunucu {%0}:{%1} adresinde açılıyor +DevMine.server.info=Bu sunucu {%0} versiyonunda {%1} "{%2}" (API {%3}) çalışıyor +DevMine.server.info.extended=This server is running {%0} {%1} 「{%2}」 implementing API version {%3} for Minecraft: PE {%4} (protocol version {%5}) +DevMine.server.license={%0} is distributed under the LGPL License +DevMine.server.tickOverload=HATA! Sunucu aşırı mı yüklendi? +DevMine.server.startFinished={%0} saniye içinde tamamlandı. Yardım için /help yazınız +DevMine.server.defaultGameMode=Varsayılan oyun modu: {%0} +DevMine.server.query.start=GS4 durum dinleyicisi başlatılıyor +DevMine.server.query.info=Query port kuruluyor: {%0} +DevMine.server.query.running=Şurada sorgulanıyor: {%0}:{%1} + +DevMine.command.alias.illegal={%0} kayıt edilemiyor. Çünkü yasaklı karakterler içeriyor +DevMine.command.alias.notFound=Takma ad {%0} bulunamadı. Çünkü olmayan bu komutları içerir: {%1} +DevMine.command.exception=İşlenmeyen işletme komutu: '{%0}' 'de {%1}: {%2} +DevMine.command.plugins.description=Sunucuda çalışan eklentileri gösterir +DevMine.command.plugins.success=Eklentiler ({%0}): {%1} +DevMine.command.plugins.usage=/plugins +DevMine.command.reload.description=Sunucu ayarlarını ve eklentilerini yeniden yükler +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=Sunucu yeniden yükleniyor... +DevMine.command.reload.reloaded=Yeniden yükleme tamamlandı. +DevMine.command.status.description=Sunucunun performansını geri okur. +DevMine.command.status.usage=/status +DevMine.command.gc.description=Toplanmış atık dosyaları yakar +DevMine.command.gc.usage=/gc +DevMine.command.timings.description=Timings'i sunucunun performansını görmek için kaydeder. +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=Timings & Reset aktif edildi +DevMine.command.timings.disable=Timings devre dışı bırakıldı +DevMine.command.timings.timingsDisabled=Timings'i aktif etmek için /timings on yazınız +DevMine.command.timings.reset=Timigs yeniden başlatma +DevMine.command.timings.pasteError=Raporu geçerken bir hata meydana geldi +DevMine.command.timings.timingsUpload=Timings şuraya yüklendi: {%0} +DevMine.command.timings.timingsRead=Sonuçları {%0}'da okuyabilirsin +DevMine.command.timings.timingsWrite=Timings şuraya yazıldı: {%0} + +DevMine.command.version.description=Sunucunun ve kullanımda olan eklentilerin versiyonunu alırsınız +DevMine.command.version.usage=/version [eklenti adı] +DevMine.command.version.noSuchPlugin=Bu sunucu bu isimde olan bir eklenti çalıştıramaz. /plugins yazarak eklenti listesine bakabilirsiniz + +DevMine.command.give.description=Belirtilen oyuncuya belli miktarda eşya verir +DevMine.command.give.usage=/give [miktar] [başlıklar..] + +DevMine.command.kill.description=Kendini veya diğer oyuncuları öldür +DevMine.command.kill.usage=/kill [oyuncu] + +DevMine.command.particle.description=Dünyaya parçacık efekti eklendi +DevMine.command.particle.usage=/particle [adet] [data] + +DevMine.command.time.description=Her bir dünyadaki saati değiştir +DevMine.command.time.usage=/time veya /time + +DevMine.command.ban.player.description=Oyuncuyu sunucudan engeller +DevMine.command.ban.ip.description=Belirlenen IP adresini sunucudan engelller +DevMine.command.banlist.description=Sunucudan engellenen oyuncuları gör +DevMine.command.defaultgamemode.description=Varsayılan oyun modunu ayarla +DevMine.command.deop.description=Belirlenen oyuncunun OP durumunu alır +DevMine.command.difficulty.description=Varsayılan oyun zorluğunu ayarla +DevMine.command.enchant.description=Eşyalara büyü ekler +DevMine.command.effect.description=Oyuncuya efekt ekle veya kaldır +DevMine.command.gamemode.description=Belirlenen oyuncunun oyun modunu değiştirir +DevMine.command.help.description=Yardım menüsünü gösterir +DevMine.command.kick.description=Belirlenen oyuncuyu sunucudan atar +DevMine.command.list.description=Çevrimiçi oyuncular listesi +DevMine.command.me.description=Yaptığınız aksiyonu sohbette anlatır +DevMine.command.op.description=Belirlenen oyuncuya OP verir +DevMine.command.unban.player.description=Belirlenen oyuncunun sunucuya girme engelini açar +DevMine.command.unban.ip.description=Belirlenen IP adresinin sunucuya girme engelini açar +DevMine.command.save.description=Sunucuyu diske kaydeder +DevMine.command.saveoff.description=Sunucunun otomatik kaydetmesini deaktif eder +DevMine.command.saveon.description=Sunucunun otomatik kaydetmesini aktif eder +DevMine.command.say.description=Belirlenen mesajı gönderici olarak yayınlar +DevMine.command.seed.description=Dünyanın seed'ini gösterir +DevMine.command.setworldspawn.description=Dünya başlangıç noktasını ayarlar. +DevMine.command.spawnpoint.description=Oyuncunun başlangıç noktasını ayarlar +DevMine.command.stop.description=Sunucuyu durdurur +DevMine.command.tp.description=Belirlenen oyuncuya ışınlar veya belirlenen oyuncuyu başka bir oyuncuya ışınlar +DevMine.command.tell.description=Belirlenen oyuncuya özel mesaj yollar +DevMine.command.whitelist.description=Sunucuya girme hakkı olan oyuncuları ayarlar +DevMine.crash.create=Bilinmeyen bir hata oluştu ve sunucu çöktü. Çökme arşivi oluşturuluyor +DevMine.crash.error=Çökme arşivi oluşturulamadı: {%0} +DevMine.crash.submit=Lütfen "{%0}" dosyasını Çökme Arşivine yükleyin ve linki Bug Raporlama sayfasına gönderin. Size bir çok bilgi sunulacak. +DevMine.crash.archive=Çökme bilgisi Çökme Arşivine otomatik olarak gönderildi. Onu {%0}'da görüntüleyebilirsin veya ID #{%1}'i kullanabilirsin. + +DevMine.debug.enable=LevelDB yardımı aktif edildi + +DevMine.player.invalidMove={%0} moved wrongly! +DevMine.player.logIn={%0}[/{%1}:{%2}], {%3} Entity ID'si ile ({%4}, {%5}, {%6}, {%7})'da giriş yaptı +DevMine.player.logOut={%0}[/{%1}:{%2}], {%3} sebebiyle çıkış yaptı +DevMine.player.invalidEntity={%0} bilinmeyen bir varlığa saldırmayı denedi + +DevMine.plugin.load={%0} Yükleniyor +DevMine.plugin.enable={%0} aktif ediliyor +DevMine.plugin.disable={%0} deaktif ediliyor +DevMine.plugin.restrictedName=Yasak ad +DevMine.plugin.incompatibleAPI=Uyumsuz API versiyonu +DevMine.plugin.unknownDependency=Bilinmeyen bağımlı +DevMine.plugin.circularDependency=Dairesel bağımlı tespit edildi +DevMine.plugin.genericLoadError=Eklenti yüklenemiyor '{%0}' +DevMine.plugin.spacesDiscouraged='{%0}' eklentisi isminde boşluk barındırıyor, vazgeçildi +DevMine.plugin.loadError=Eklenti yüklenemedi '{%0}': {%1} +DevMine.plugin.duplicateError='{%0}' adlı eklenti zaten var olduğundan yüklenemedi +DevMine.plugin.fileError='{%0}' eklentisi '{%1}': {%2} dosyasında yüklenemedi +DevMine.plugin.commandError={%0} komutu {%1} eklentisi için yüklenemedi +DevMine.plugin.aliasError={%0} takma adı {%1} eklentisi için yüklenemedi +DevMine.plugin.deprecatedEvent='{%0}' eklentisi bir '{%1}' dinleyicisi için '{%2}' yönteminde kayıt oldu, ama durum önerilmiyor. +DevMine.plugin.eventError="'{%0}' olayı '{%1}': {%2} 'ye {%3}'de geçilemiyor" diff --git a/src/devmine/utilities/languages/locale/ukr.ini b/src/devmine/utilities/languages/locale/ukr.ini new file mode 100644 index 0000000..480a8e4 --- /dev/null +++ b/src/devmine/utilities/languages/locale/ukr.ini @@ -0,0 +1,431 @@ +# Language file compatible with Minecraft: Pocket Edition identifiers +# +# A message doesn't need to be there to be shown correctly on the client. +# Only messages shown in DevMine itself need to be here + +language.name=Ukrainian +language.selected=Обрано {%0} ({%1}) в якості основної мови + +multiplayer.player.joined={%0} приєднався до гри +multiplayer.player.left={%0} покинув гру + +chat.type.text={%0} : {%1} +chat.type.emote=* {%0} {%1} +chat.type.announcement=[{%0}] {%1} +chat.type.admin=[{%0}: {%1}] +chat.type.achievement=Гравець {%0} отримав досягнення {%1}! + +disconnectionScreen.notAuthenticated=Необхідно авторизуватися в Xbox! +disconnectionScreen.outdatedClient=Застарілий клієнт! +disconnectionScreen.outdatedServer=Застарілий сервер! +disconnectionScreen.serverFull=Сервер переповнений! +disconnectionScreen.noReason=Від’єднано від серверу. +disconnectionScreen.invalidSkin=Помилковий формат скіну! +disconnectionScreen.invalidName=Неприпустиме нік! + +death.fell.accident.generic={%0} впав з високого місця +death.attack.inFire={%0} згорів +death.attack.onFire={%0} згорів +death.attack.lava={%0} вирішив поплавати в лаві... +death.attack.inWall={%0} задихнувся в стіні +death.attack.drown={%0} потонув +death.attack.cactus={%0} став жертвою кактуса ;-) +death.attack.generic={%0} помер +death.attack.explosion={%0} вибухнув +death.attack.explosion.player={%0} був підірваний {%1} +death.attack.magic={%0} вбитий магією +death.attack.wither={%0} висушений +death.attack.mob={%0} був вбитий {%1} +death.attack.player={%0} був вбитий {%1} +death.attack.player.item={%0} був вбитий {%1} з {%2} +death.attack.arrow={%0} був застрелений {%1} +death.attack.arrow.item={%0} був застрелений {%1} з {%2} +death.attack.fall={%0} впав з високого місця +death.attack.outOfWorld={%0} випав зі світу + +gameMode.survival=Режим виживання +gameMode.creative=Творчий режим +gameMode.adventure=Пригодницький режим +gameMode.spectator=Режим спостерігача +gameMode.changed=Ваш ігровий режим було оновлено + +potion.moveSpeed=Швидкість +potion.moveSlowdown=Уповільнення +potion.digSpeed=Поспіх +potion.digSlowDown=Втома +potion.damageBoost=Сила +potion.heal=Миттєве Лікування +potion.harm=Миттєва Втрата +potion.jump=Посилення Стрибка +potion.confusion=Нудота +potion.regeneration=Регенерація +potion.resistance=Супротив Втратам +potion.fireResistance=Вогнестійкість +potion.waterBreathing=Підводне Дихання +potion.invisibility=Невидимість +potion.blindness=Сліпота +potion.nightVision=Нічний Зір +potion.hunger=Голод +potion.weakness=Слабкість +potion.poison=Отруєння +potion.wither=Висушення +potion.healthBoost=Підвищення Здоров’я +potion.absorption=Поглинання +potion.saturation=Насичення + +commands.generic.exception=Увага! Невідома помилка при виконанні команди +commands.generic.permission=У Вас недостатньо прав для використання цієї команди +commands.generic.notFound=Невідома команда. Використовуйте /help для перегляду списку команд +commands.generic.player.notFound=Гравця не знайдено +commands.generic.usage=Використання: {%0} +commands.generic.level=Назва світу +commands.generic.seed=Назва сіду +commands.generic.name=нік +commands.generic.generator=Назва генератору +commands.generic.opt.missing=Необхідні налаштування відсутні,будь ласка, повторіть введення. +commands.generic.runingame=Використовуйте цю команду тільки в грі. + +commands.time.added=Додано {%0} до часу +commands.time.set=Встановлено час - {%0} +commands.time.query=Час ‒ {%0} + +commands.me.usage=/me <дія> + +commands.give.item.notFound=Предмет з іменем {%0} не знайдено +commands.give.success=Дано {%0} Х {%1} гравцю {%2} +commands.give.tagError=Розбір тегу данных завершився невдало: {%0} + +commands.effect.usage=/effect <гравець> <ефект> [к-сть секунд] [рівень] [прибратиЧастинки] АБО /effect <гравець> clear +commands.effect.notFound=Не існує ефекту з ID {%0} +commands.effect.success=Дано {%0} (ID {%1}) Х {%2} гравцю {%3} на {%4} секунд +commands.effect.success.removed=Ефект {%0} забрано у {%1} +commands.effect.success.removed.all=Всі ефекти були зняті з {%0} +commands.effect.failure.notActive=Неможливо прибрати ефект {%0} у {%1}, поскільки гравець не має цього ефекту +commands.effect.failure.notActive.all=Неможливо прибрати ефекти у {%0}, поскільки гравець взагалі без ефектів + +commands.enchant.maxLevel=Діапазон рівнів зачарування: 1 - {%0} +commands.enchant.noItem=У гравця немає такого предмету +commands.enchant.notFound=Немає такого зачарування з ID {%0} +commands.enchant.success=Зачарування завершилося вдало +commands.enchant.cantEnchant=Цей предмет неможливо зачарувати +commands.enchant.usage=/enchant <гравець> [рівень] + +commands.particle.success=Відтворюються частинки ефекту {%0} {%1} разів +commands.particle.notFound=Невідомий ефект {%0} + +commands.players.usage=/list +commands.players.list=Зараз {%0}/{%1} гравців на сервері: + +commands.kill.successful=Вбито {%0} + +commands.banlist.ips=Всього заблоковано %d IP адрес: +commands.banlist.players=Всього заблоковано {%0} гравців: +commands.banlist.cids=Всього заблоковано {%0} номерів пристроїв: +commands.banlist.usage=/banlist [ips|players] + +commands.defaultgamemode.usage=/defaultgamemode <режим гри> +commands.defaultgamemode.success=Ігровой режим світу за замовчуванням ‒ {%0} + +commands.op.success={%0} тепер оператор серверу +commands.op.usage=/op <гравець> + +commands.deop.success={%0} вже не оператор серверу +commands.deop.usage=/deop <гравець> + +commands.say.usage=/say <повідомлення> + +commands.seed.usage=/seed +commands.seed.success=Сід: {%0} + +commands.bancidbyname.success=Гравця {%0} заблоковано по номеру пристрою +commands.bancidbyname.usage=/bancidbyname <нік гравця> + +commands.bancid.success=Заблоковано номер пристрою: {%0} +commands.bancid.usage=/bancid <номер пристрою> + +commands.unbancid.usage=/pardoncid <номер пристрою> +commands.unbancid.success=Розблоковано номер пристрою {%0} + +commands.ban.success=Заблоковано гравця {%0} +commands.ban.usage=/ban <нік гравця> [причина] [час(в днях)] + +commands.unban.success=Розблоковано гравця {%0} +commands.unban.usage=/pardon <нік> + +commands.banip.invalid=Ви ввели неправильну IP-адресу чи даний гравець не в мережі +commands.banip.success=Заблоковано IP адресу {%0} +commands.banip.success.players=Заблоковано IP адресу {%0}, що належав {%1} +commands.banip.usage=/ban-ip [причина] + +commands.unbanip.invalid=Ви ввели неправильну IP адресу +commands.unbanip.success=Розблоковано IP адресу {%0} +commands.unbanip.usage=/pardon-ip <адреса> + +commands.banipbyname.success=Гравця з ніком {%0} заблоковано по IP +commands.banipbyname.usage=/banipbyname <гравець> + +commands.fill.usage=/fill + +commands.save.usage=/save-all +commands.save-on.usage=/save-on +commands.save-off.usage=/save-off +commands.save.enabled=Ввімкнено автоматичне збереження світу +commands.save.disabled=Автоматичне збереження світу було вимкнено +commands.save.start=Збереження світу... +commands.save.success=Світ збережено + +commands.setblock.usage=/setblock <назва блоку> [втрата] +command.setblock.invalidBlock=Недопустима назва блоку чи ID + +commands.stop.usage=/stop +commands.stop.start=Зупинка серверу + +commands.kick.success={%0} було від’єднано від серверу +commands.kick.success.reason=Гравця {%0} було від’єднано від серверу. Причина: '{%1}' +commands.kick.usage=/kick <гравець> [причина] + +commands.tp.success=Переміщено {%0} до {%1} +commands.tp.success.coordinates=Переміщено {%0} на координати {%1}, {%2}, {%3} +commands.tp.usage=/tp [цільовий гравець] <назначений гравець> або /tp [цільовий гравець] [ ] + +commands.whitelist.list=Білий список має {%0} гравців (з {%1} відображених): +commands.whitelist.enabled=Білий список ввімкнено +commands.whitelist.disabled=Білий список вимкнено +commands.whitelist.reloaded=Білий список перезавантажено +commands.whitelist.add.success={%0} додано до білого списку +commands.whitelist.add.usage=/whitelist add <гравець> +commands.whitelist.remove.success={%0} видалено з білого списку +commands.whitelist.remove.usage=/whitelist remove <гравець> +commands.whitelist.usage=/whitelist + +commands.gamemode.success.self=Встановлено власний режим гри - {%2} +commands.gamemode.success.other=Режим гри для гравця {%1} змінено на {%2} +commands.gamemode.usage=/gamemode <режим гри> [гравець] + +commands.help.header=--- Строінка {%0} з {%1} (/help <сторінка>) --- +commands.help.usage=/help [сторінка|назва команди] + +commands.message.usage=/tell <гравець> <приватне повідомлення> +commands.message.sameTarget=Нащо самому собі писати приватне повідомлення?! + +commands.difficulty.usage=/difficulty <складність гри> +commands.difficulty.success=Складність гри змінено на {%0} + +commands.spawnpoint.usage=/spawnpoint [гравець] [ ] +commands.spawnpoint.success=Місце появи гравця {%0} - ({%1}, {%2}, {%3}) + +commands.setworldspawn.usage=/setworldspawn [ ] +commands.setworldspawn.success=Місце появи у світі - ({%0}, {%1}, {%2}) + +commands.summon.usage=/summon [сутність] [ ] [назва] + +commands.xp.failure.withdrawXp=Неможливо дати гравцю від’ємне значення досвіду +commands.xp.success=Дано {%0} досвіду гравцю {%1} +commands.xp.success.levels=Дано {%0} рівнів досвіду гравцю {%1} +commands.xp.success.negative.levels=Забрано {%0} рівнів досвіду від гравця {%1} +commands.xp.usage=/xp <кількість> [гравець] або /xp <кількість рівнів> [гравець] + +# -------------------- DevMine language files, only for console -------------------- +DevMine.data.playerNotFound=Інформацію про гравця "{%0}" не знайдено, створюємо новий профіль +DevMine.data.playerCorrupted=Дані гравця "{%0}" пошкоджено, створюємо новий профіль +DevMine.data.playerOld=Профіль гравця "{%0}" застарілий, оновлюємо на новий +DevMine.data.saveError=Помилка збереження профіля гравця "{%0}": {%1} + +DevMine.level.notFound=Світ "{%0}" не знайдено +DevMine.level.loadError=Помилка завантаження світу "{%0}": {%1} +DevMine.level.generationError=Помилка генерації світу "{%0}": {%1} +DevMine.level.tickError=Помилка промальовки світу "{%0}": {%1} +DevMine.level.chunkUnloadError=Помилка під час вивантаження чанку: {%0} +DevMine.level.backgroundGeneration=Генерується місце появи для світу "{%0}" +DevMine.level.defaultError=Помилка завантаження світу за замовчуванням +DevMine.level.preparing=Підготовка світу "{%0}" +DevMine.level.unloading=Вивантаження світу "{%0}" + +DevMine.server.start=Запускається сервер Minecraft PE {%0} +DevMine.server.networkError=[Мережа] Зупинено інтерфейс {%0}. Причина: {%1} +DevMine.server.networkStart=Реєстрація серверу на {%0}:{%1} +DevMine.server.info.extended=Сервер використовує {%0} {%1} 「{%2}」. Версія API: {%3}. Версія Minecraft PE: {%4}. Протокол версії {%5} +DevMine.server.info=Цей сервер використовує {%0}, версію {%1} "{%2}" (API {%3}) +DevMine.server.license={%0} розповсюджується за ліцензією LGPL +DevMine.server.tickOverload=Сервер перевантажено! +DevMine.server.startFinished=Завантаження виконано. Час: {%0} секунд. Довідка по командам - "help" або "?" +DevMine.server.defaultGameMode=Режим гри за замовчуванням: {%0} +DevMine.server.query.start=Запуск прослуховувача GS4 +DevMine.server.query.info=QUERY порт - {%0} +DevMine.server.query.running=Реєстрація QUERY на {%0}:{%1} + +DevMine.command.alias.illegal=Введено недопустимі знаки для альтернативи команди {%0} +DevMine.command.alias.notFound=Помилка реєстрації альтернативи команди {%0}: знайдено недопустимі команди - {%1} +DevMine.command.exception=Необроблене виключення при виконанні команди '{%0}' в {%1}: {%2} + +DevMine.commands.cave.usage=/cave <кут повороту> <довжина> <номер вітки> <міцність> <назва світу> | /cave getmypos +DevMine.commands.cave.info=Кут повороту: {%0}. Довжина: {%1}. Номер вітки: {%2}. Міцність: {%3}. +DevMine.commands.cave.start=Створення печери розпочато! Будь ласка, зачекайте. + +DevMine.command.plugins.description=Список плагінів серверу +DevMine.command.plugins.success=Плагіни ({%0}): {%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=Перезавантажити налаштування серверу и плагіни +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=Перезавантаження серверу... +DevMine.command.reload.reloaded=Перезавантаження виконано. + +DevMine.command.lvdat.description=Змінити налаштування мапи. +DevMine.command.lvdat.changed=Змінено параметр {%1} для світу "{%0}", необхідне перезавантаження для активації змін. +DevMine.command.lvdat.fixname=Назву світу "{%0}" було успішно відредаговано, необхідне перезавантаження для активації змін. +DevMine.command.lvdat.nofound=Світ "{%0}" не знайдено або не завантажено. +DevMine.command.lvdat.preset=Налаштування генератору (пресети) + +DevMine.command.status.description=Інформація про продуктивність серверу. +DevMine.command.status.usage=/status + +DevMine.command.status.title=Статус серверу +DevMine.command.status.player=Всього гравців: +DevMine.command.status.days=днів +DevMine.command.status.hours=годин +DevMine.command.status.minutes=хвилин +DevMine.command.status.seconds=секунд +DevMine.command.status.uptime=Час роботи серверу: +DevMine.command.status.AverageTPS=Середній TPS: +DevMine.command.status.CurrentTPS=Поточний TPS: +DevMine.command.status.Networkupload=Даних відправлено: +DevMine.command.status.Networkdownload=Даних отримано: +DevMine.command.status.Threadcount=Кількість потоків: +DevMine.command.status.Mainmemory=Основна пам’ять потоку: +DevMine.command.status.Totalmemory=Загальна пам’ять: +DevMine.command.status.Totalvirtualmemory=Загальна віртуальна пам’ять: +DevMine.command.status.Heapmemory=Пам’ять кучі (Java Heap Memory): +DevMine.command.status.Maxmemorysystem=Максимальна пам’ять системи: +DevMine.command.status.Maxmemorymanager=Максимальна пам’ять менеджера: +DevMine.command.status.World=Світ +DevMine.command.status.chunks=чанків, +DevMine.command.status.entities=сутностей, +DevMine.command.status.tiles=тайлів. +DevMine.command.status.Time=Час +DevMine.command.status.ms=мс + +DevMine.command.gc.description=Запускає процес збирання сміття +DevMine.command.gc.usage=/gc +DevMine.command.gc.title=Результат очистки +DevMine.command.gc.chunks=Чанків: +DevMine.command.gc.entities=Сутностей: +DevMine.command.gc.tiles=Тайлів: +DevMine.command.gc.cycles=Циклів: +DevMine.command.gc.memory=Звільнена пам’ять: + +DevMine.command.biome.description=Змінює біом обраної області. +DevMine.command.biome.posset=Встановлено точку {%3} на позиції: ({%1},{%2})[{%0}] +DevMine.command.biome.get=ID біома, де Ви знаходитесь: {%0}. Колір: {%1},{%2},{%3} +DevMine.command.biome.wrongLev=Точки знаходяться в різних світах. +DevMine.command.biome.wrongBio=Помилковий ID біому. Приклад біомів: 1 (Рівнини), 2 (Пустеля),13 (Льодяні гори),6 (Болото) +DevMine.command.biome.wrongCol=Неправильний колір! Приклад: 146,188,89. Використовуйте: "/biome get" для отримання решти кольорів. +DevMine.command.biome.noPos=Використовуйте "/biome pos1|pos2", щоб встановити точки. +DevMine.command.biome.set=Колір було змінено на {%0} +DevMine.command.biome.color=Обрано колір {%0},{%1},{%2} + +DevMine.command.timings.description=Фіксує інформацію про середню продуктивність серверу. +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=Розпочато фіксування даних про продуктивність серверу. +DevMine.command.timings.disable=Фіксування даних про продуктивність серверу припинено. +DevMine.command.timings.timingsDisabled=Для повторної активації фіксування даних про продуктивність серверу використовуйте /timings on +DevMine.command.timings.reset=Дані про продуктивність серверу було скинуто +DevMine.command.timings.pasteError=Помилка при фіксуванні даних про продуктивність серверу +DevMine.command.timings.timingsUpload=Дані про продуктивність серверу завантажені з {%0} +DevMine.command.timings.timingsRead=Дані про продуктивність серверу Ви можете отримати тут: {%0} +DevMine.command.timings.timingsWrite=Дані про продуктивність серверу збережені до {%0} + +DevMine.command.version.description=Інформація про версію серверу і про встановлені плагіни +DevMine.command.version.usage=/version [назва плагіну] +DevMine.command.version.noSuchPlugin=Плагіна з такою назвою не знайдено. Використовуйте /plugins для отримання списку плагінів. + +DevMine.command.give.description=Дає гравцю зазначену к-сть предмету +DevMine.command.give.usage=/give <гравець> <предмет[:втрата]> [кількість] [теги] + +DevMine.command.kill.description=Скоєння самогубства або вбивство іншого гравця +DevMine.command.kill.usage=/kill [гравець] + +DevMine.command.particle.description=Додавання частинок у світ +DevMine.command.particle.usage=/particle <назва> [значення] [дані] + +DevMine.command.time.description=Перегляд або глобальна зміна часу +DevMine.command.time.usage=/time <значення> або /time + +DevMine.command.bancidbyname.description=Блокування гравця по номеру пристрою +DevMine.command.bancid.description=Блокування номера пристрою +DevMine.command.banipbyname.description=Блокування гравця по IP +DevMine.command.ban.player.description=Блокування гравця +DevMine.command.ban.ip.description=Блокування IP адреси +DevMine.command.banlist.description=Список заблокованих гравців +DevMine.command.defaultgamemode.description=Встановлює режим гри за замовчуванням +DevMine.command.deop.description=Знімає статус оператора з гравця +DevMine.command.difficulty.description=Встановлює складність гри +DevMine.command.enchant.description=Додає зачарування предметам +DevMine.command.effect.description=Зміна ефектів у гравців +DevMine.command.gamemode.description=Зміна режиму гри у гравця +DevMine.command.help.description=Довідка +DevMine.command.kick.description=Примусове від’єднання гравця від серверу +DevMine.command.list.description=Список гравців серверу, що зараз грають +DevMine.command.me.description=Виконує вказану дію в чаті +DevMine.command.op.description=Встановлює статус оператора для гравця + +DevMine.command.unban.cid.description=Розблокування номера пристрою +DevMine.command.unban.player.description=Розблокування гравця по ніку +DevMine.command.unban.ip.description=Розблокування IP адреси + +DevMine.command.save.description=Збереження файлів серверу +DevMine.command.saveoff.description=Вимикання автоматичного збереження +DevMine.command.saveon.description=Вмикання автоматичного збереження +DevMine.command.say.description=Написати в чат від імені серверу +DevMine.command.seed.description=Поточний сід світу +DevMine.command.setworldspawn.description=Встановлення місце появи гравців у світі. +DevMine.command.spawnpoint.description=Встановлення місце появи окремого гравця у світі +DevMine.command.stop.description=Вимикання серверу +DevMine.command.tp.description=Переміщення гравців +DevMine.command.tell.description=Надсилання приватного повідомлення гравцю +DevMine.command.xp.description=Зміна досвіду в гравця +DevMine.command.summon.description=Створення сутності +DevMine.command.fill.description=Заповнює вибрану область блоками +DevMine.command.fill.missingParameter=Пропущені параметри +DevMine.command.fill.usage=/fill +DevMine.command.setblock.description=Змінює блок по відповідних координатах + +DevMine.command.weather.description=Зміна погоди у світі +DevMine.command.weather.usage=/weather <світ> (0,1,2,3) +DevMine.command.weather.changed=Успішно змінено погоду в світі {%0}! +DevMine.command.weather.noregistered=Світ {%0} не було зареєстровано в менеджері погоди. +DevMine.command.weather.invalid=Помилкове значення погоди. +DevMine.command.weather.wrong=Некорректні параметри. +DevMine.command.weather.invalid.level=Неправильна назва світу. + +DevMine.command.whitelist.description=Керування білим списком серверу + +DevMine.crash.create=Увага! Роботу серверу припинено через фатальну помилку. Створення аварійного дампу. +DevMine.crash.error=Помилка створення дампу: {%0} +DevMine.crash.submit=Буль ласка, завантажте файл "{%0}" до Crash Archive і надішліть посилання на сторінку Bug Reporting. Вкажіть якомога більше інформації про цю помилку. +DevMine.crash.archive=Аварійний дамп було автоматично відправлено до Crash Archive. Ви можете подивитися його тут: {%0}, або використати ID #{%1}. + +DevMine.debug.enable=Підтримку LevelDB ввімкнено + +DevMine.player.invalidMove={%0} некорректно пересунувся! +DevMine.player.logIn={%0}[/{%1}:{%2}] приєднався з ID сутності {%3} на ({%4}, {%5}, {%6}, {%7}) +DevMine.player.logOut={%0}[/{%1}:{%2}] від’єднався: {%3} +DevMine.player.transferred={%0}[/{%1}:{%2}] було переміщено до {%3} +DevMine.player.invalidEntity={%0} спробував атакувати некорректну сутність + +DevMine.plugin.load=Завантаження {%0} +DevMine.plugin.enable=Ввімкнення {%0} +DevMine.plugin.disable=Вимкнення {%0} +DevMine.plugin.restrictedName=Обмежене ім’я +DevMine.plugin.incompatibleAPI=Несумісна версія API +DevMine.plugin.unknownDependency=Невідома залежність +DevMine.plugin.circularDependency=Виявлена кругова залежність +DevMine.plugin.genericLoadError=Помилка завантаження плагіну '{%0}' +DevMine.plugin.spacesDiscouraged=Назва плагіну '{%0}' вказана з використанням пробілів, що є недопустимим +DevMine.plugin.loadError=Помилка завантаження плагіну '{%0}': {%1} +DevMine.plugin.duplicateError=Помилка завантаження '{%0}': плагін вже існує +DevMine.plugin.fileError=Помилка завантаження '{%0}' в папці '{%1}': {%2} +DevMine.plugin.commandError=Помилка завантаження команди {%0} для плагіну {%1} +DevMine.plugin.aliasError=Помилка завантаження альтернативу {%0} для плагіну {%1} +DevMine.plugin.deprecatedEvent=Плагін '{%0}' зареєстрував прослуховувача для '{%1}', використовуючи метод '{%2}'. Ця подія є застарілою. +DevMine.plugin.eventError="Помилка обробки події '{%0}' в '{%1}': {%2} в {%3}" diff --git a/src/devmine/utilities/languages/locale/vie.ini b/src/devmine/utilities/languages/locale/vie.ini index dc30a4a..7df598d 100644 --- a/src/devmine/utilities/languages/locale/vie.ini +++ b/src/devmine/utilities/languages/locale/vie.ini @@ -1,7 +1,7 @@ # Language file compatible with Minecraft: Pocket Edition identifiers # # A message doesn't need to be there to be shown correctly on the client. -# Only messages shown in devmine itself need to be here +# Only messages shown in DevMine itself need to be here language.name=Vietnamese language.selected=Chọn {%0} ({%1}) là ngôn ngữ chính @@ -9,7 +9,7 @@ language.selected=Chọn {%0} ({%1}) là ngôn ngữ chính multiplayer.player.joined={%0} tham gia server multiplayer.player.left={%0} rời khỏi server -chat.type.text=<{%0}> {%1} +chat.type.text={%0} : {%1} chat.type.emote=* {%0} {%1} chat.type.announcement=[{%0}] {%1} chat.type.admin=[{%0}: {%1}] @@ -180,8 +180,8 @@ commands.whitelist.remove.success=Loại {%0} khỏi danh sách trắng commands.whitelist.remove.usage=/whitelist remove commands.whitelist.usage=/whitelist -commands.gamemode.success.self=Đặt chế độ chơi là {%0} -commands.gamemode.success.other=Đặt {%0} cho {%1} +commands.gamemode.success.self=Đặt chế độ chơi là {%2} +commands.gamemode.success.other=Đặt {%1} cho {%2} commands.gamemode.usage=/gamemode [người chơi] commands.help.header=---> Xem trang hướng dẫn {%0} trong {%1} (/help ) --- commands.help.usage=/help [sô trang|câu lệnh] @@ -198,187 +198,189 @@ commands.setworldspawn.usage=/setworldspawn [ ] commands.setworldspawn.success=Đặt điểm mặc định ở ({%0}, {%1}, {%2}) commands.summon.usage=/summon [tên mob] [ ] [đặt tên cho mob] -commands.cave.usage=/cave | /cave getmypos -commands.cave.info=Angle of rotation:{%0} Length:{%1} Branch Number:{%2} Strength:{%3} -commands.cave.start=Start to generate cave,please wait -# -------------------- devmine language files, only for console -------------------- -devmine.data.playerNotFound=Player data not found for "{%0}", creating new profile -devmine.data.playerCorrupted=Corrupted data found for "{%0}", creating new profile -devmine.data.playerOld=Old Player data found for "{%0}", upgrading profile -devmine.data.saveError=Could not save player "{%0}": {%1} -devmine.level.notFound=Level "{%0}" not found -devmine.level.loadError=Could not load level "{%0}": {%1} -devmine.level.generationError=Could not generate level "{%0}": {%1} -devmine.level.tickError=Could not tick level "{%0}": {%1} -devmine.level.chunkUnloadError=Error while unloading a chunk: {%0} -devmine.level.backgroundGeneration=Spawn terrain for level "{%0}" is being generated in the background -devmine.level.defaultError=No default level has been loaded -devmine.level.preparing=Preparing level "{%0}" -devmine.level.unloading=Unloading level "{%0}" -devmine.server.start=Starting Minecraft: PE server version {%0} -devmine.server.networkError=[Network] Stopped interface {%0} due to {%1} -devmine.server.networkStart=Opening server on {%0}:{%1} -devmine.server.info=This server is running {%0} version {%1} "{%2}" (API {%3}) -devmine.server.info.extended=This server is running {%0} {%1} 「{%2}」 implementing API version {%3} for Minecraft: PE {%4} (protocol version {%5}) -devmine.server.license={%0} is distributed under the LGPL License -devmine.server.tickOverload=Can't keep up! Is the server overloaded? -devmine.server.startFinished=Done ({%0}s)! For help, type "help" or "?" -devmine.server.defaultGameMode=Default game type: {%0} -devmine.server.query.start=Starting GS4 status listener -devmine.server.query.info=Setting query port to {%0} -devmine.server.query.running=Query running on {%0}:{%1} - -devmine.command.alias.illegal=Could not register alias {%0} because it contains illegal characters -devmine.command.alias.notFound=Could not register alias {%0} because it contains commands that do not exist: {%1} -devmine.command.exception=Unhandled exception executing command '{%0}' in {%1}: {%2} - -devmine.command.plugins.description=Gets a list of plugins running on the server -devmine.command.plugins.success=Plugins ({%0}): {%1} -devmine.command.plugins.usage=/plugins - -devmine.command.reload.description=Reloads the server configuration and plugins -devmine.command.reload.usage=/reload -devmine.command.reload.reloading=Reloading server... -devmine.command.reload.reloaded=Reload complete. - -devmine.command.lvdat.description=Change properties of a map. -devmine.command.lvdat.changed=has changed {%1} of level "{%0}", some change need to reboot your server. -devmine.command.lvdat.fixname=fixname successfully for level "{%0}", some change need to reboot your server. -devmine.command.lvdat.nofound=level "{%0}" no found or load failed. -devmine.command.lvdat.preset=Generator setting (preset) - -devmine.command.status.description=Reads back the server's performance. -devmine.command.status.usage=/status -devmine.command.status.title=Server status -devmine.command.status.player=Player count: -devmine.command.status.days=days -devmine.command.status.hours=hours -devmine.command.status.minutes=minutes -devmine.command.status.seconds=seconds -devmine.command.status.uptime=Uptime: -devmine.command.status.AverageTPS=Average TPS: -devmine.command.status.CurrentTPS=Current TPS: -devmine.command.status.Networkupload=Network upload: -devmine.command.status.Networkdownload=Network download: -devmine.command.status.Threadcount=Thread count: -devmine.command.status.Mainmemory=Main thread memory; -devmine.command.status.Totalmemory=Total memory: -devmine.command.status.Totalvirtualmemory=Total virtual memory: -devmine.command.status.Heapmemory=Heap memory: -devmine.command.status.Maxmemorysystem=Maximum memory (system): -devmine.command.status.Maxmemorymanager=Maximum memory (manager): -devmine.command.status.World=World -devmine.command.status.chunks=chunks, -devmine.command.status.entities=entities, -devmine.command.status.solidentities=solidentities. -devmine.command.status.Time=Time -devmine.command.status.ms=ms -devmine.command.gc.description=Fires garbage collection tasks -devmine.command.gc.usage=/gc -devmine.command.gc.title=Danh sách dọn dẹp: -devmine.command.gc.chunks=Chunks: -devmine.command.gc.entities=Vật thể: -devmine.command.gc.solidentities=solidentities: -devmine.command.gc.cycles=Cycles: -devmine.command.gc.memory=Bộ nhớ được thả: - -devmine.command.biome.description=change the biome of the area.(To change snow or rain) -devmine.command.biome.posset=Has set pos{%3} at:({%1},{%2})[{%0}] -devmine.command.biome.get=The ID of biome you stay is {%0} Color:{%1},{%2},{%3} -devmine.command.biome.wrongLev=Cannot set point in different level. -devmine.command.biome.wrongBio=Wrong ID of biome. e.g. 1 (Plains), 2 (Desert),13 (Ice Mountains),6 (Swampland) -devmine.command.biome.wrongCol=Wrong Color. e.g. 146,188,89 .Use "/biome get" to get other color. -devmine.command.biome.noPos=Plz use "/biome pos1|pos2" to select the area first. -devmine.command.biome.set=Has set biome as:{%0} -devmine.command.biome.color=Has set color as:{%0},{%1},{%2} - -devmine.command.timings.description=Records timings to see performance of the server. -devmine.command.timings.usage=/timings -devmine.command.timings.enable=Enabled Timings & Reset -devmine.command.timings.disable=Disabled Timings -devmine.command.timings.timingsDisabled=Please enable timings by typing /timings on -devmine.command.timings.reset=Timings reset -devmine.command.timings.pasteError=An error happened while pasting the report -devmine.command.timings.timingsUpload=Timings uploaded to {%0} -devmine.command.timings.timingsRead=You can read the results at {%0} -devmine.command.timings.timingsWrite=Timings written to {%0} -devmine.command.version.description=Gets the version of this server including any plugins in use -devmine.command.version.usage=/version [plugin name] -devmine.command.version.noSuchPlugin=This server is not running any plugin by that name. Use /plugins to get a list of plugins. -devmine.command.give.description=Gives the specified player a certain amount of items -devmine.command.give.usage=/give [amount] [tags...] -devmine.command.kill.description=Commit suicide or kill other players -devmine.command.kill.usage=/kill [player] -devmine.command.particle.description=Adds particles to a world -devmine.command.particle.usage=/particle [count] [data] -devmine.command.time.description=Changes the time on each world -devmine.command.time.usage=/time OR /time -devmine.command.bancidbyname.description=Prevents the specified CID by name from using this server禁止指定玩家的設備 ID -devmine.command.bancid.description=Prevents the specified CID from using this server -devmine.command.banipbyname.description=Prevents the specified IP address by name from using this server -devmine.command.ban.player.description=Prevents the specified player from using this server -devmine.command.ban.ip.description=Prevents the specified IP address from using this server -devmine.command.banlist.description=View all players banned from this server -devmine.command.defaultgamemode.description=Set the default gamemode -devmine.command.deop.description=Takes the specified player's operator status -devmine.command.difficulty.description=Sets the game difficulty -devmine.command.enchant.description=Adds enchantments on items -devmine.command.effect.description=Adds/Removes effects on players -devmine.command.gamemode.description=Changes the player to a specific game mode -devmine.command.help.description=Shows the help menu -devmine.command.kick.description=Removes the specified player from the server -devmine.command.list.description=Lists all online players -devmine.command.me.description=Performs the specified action in chat -devmine.command.op.description=Gives the specified player operator status -devmine.command.unban.cid.description=Allows the specified CID to use this server -devmine.command.unban.player.description=Allows the specified player to use this server -devmine.command.unban.ip.description=Allows the specified IP address to use this server -devmine.command.save.description=Saves the server to disk -devmine.command.saveoff.description=Disables server autosaving -devmine.command.saveon.description=Enables server autosaving -devmine.command.say.description=Broadcasts the given message as the sender -devmine.command.seed.description=Shows the world seed -devmine.command.setworldspawn.description=Sets a worlds's spawn point. If no coordinates are specified, the player's coordinates will be used. -devmine.command.spawnpoint.description=Sets a player's spawn point -devmine.command.stop.description=Stops the server -devmine.command.tp.description=Teleports the given player (or yourself) to another player or coordinates -devmine.command.tell.description=Sends a private message to the given player -devmine.command.xp.description=Add experience or experience level to the given player -devmine.command.summon.description=Summons a entity at the player's location or a specific location -devmine.command.fill.description=fills a specific selection with blocks -devmine.command.setblock.description=Changes a block to another block - -devmine.command.weather.description=Set weather for level -devmine.command.weather.usage=/weather -devmine.command.weather.changed=Weather changed successfully in level {%0}! -devmine.command.weather.noregistered=level {%0} hasn't registered to WeatherManager. -devmine.command.weather.invalid=Invalid weather.(0,1,2,3) -devmine.command.weather.wrong=Wrong parameters. -devmine.command.weather.invalid.level=Invalid level name. -devmine.command.whitelist.description=Manages the list of players allowed to use this server -devmine.crash.create=An unrecoverable error has occurred and the server has crashed. Creating a crash dump -devmine.crash.error=Could not create crash dump: {%0} -devmine.crash.submit=Please upload the "{%0}" file to the Crash Archive and submit the link to the Bug Reporting page. Give as much info as you can. -devmine.crash.archive=The crash dump has been automatically submitted to the Crash Archive. You can view it on {%0} or use the ID #{%1}. -devmine.debug.enable=LevelDB support enabled -devmine.player.invalidMove={%0} moved wrongly! -devmine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] logged in with entity id {%4} at ({%5}, {%6}, {%7}, {%8}) -devmine.player.logOut={%0}[/{%1}:{%2}] logged out due to {%3} -devmine.player.transferred={%0}[/{%1}:{%2}] was transferred to {%3} -devmine.player.invalidEntity={%0} tried to attack an invalid entity -devmine.plugin.load=Loading {%0} -devmine.plugin.enable=Enabling {%0} -devmine.plugin.disable=Disabling {%0} -devmine.plugin.restrictedName=Restricted name -devmine.plugin.incompatibleAPI=Incompatible API version -devmine.plugin.unknownDependency=Unknown dependency -devmine.plugin.circularDependency=Circular dependency detected -devmine.plugin.genericLoadError=Could not load plugin '{%0}' -devmine.plugin.spacesDiscouraged=Plugin '{%0}' uses spaces in its name, this is discouraged -devmine.plugin.loadError=Could not load plugin '{%0}': {%1} -devmine.plugin.duplicateError=Could not load plugin '{%0}': plugin exists -devmine.plugin.fileError=Could not load '{%0}' in folder '{%1}': {%2} -devmine.plugin.commandError=Could not load command {%0} for plugin {%1} -devmine.plugin.aliasError=Could not load alias {%0} for plugin {%1} -devmine.plugin.deprecatedEvent=Plugin '{%0}' has registered a listener for '{%1}' on method '{%2}', but the event is Deprecated. -devmine.plugin.eventError="Could not pass event '{%0}' to '{%1}': {%2} on {%3} + +# -------------------- DevMine language files, only for console -------------------- +DevMine.data.playerNotFound=Player data not found for "{%0}", creating new profile +DevMine.data.playerCorrupted=Corrupted data found for "{%0}", creating new profile +DevMine.data.playerOld=Old Player data found for "{%0}", upgrading profile +DevMine.data.saveError=Could not save player "{%0}": {%1} +DevMine.level.notFound=Level "{%0}" not found +DevMine.level.loadError=Could not load level "{%0}": {%1} +DevMine.level.generationError=Could not generate level "{%0}": {%1} +DevMine.level.tickError=Could not tick level "{%0}": {%1} +DevMine.level.chunkUnloadError=Error while unloading a chunk: {%0} +DevMine.level.backgroundGeneration=Spawn terrain for level "{%0}" is being generated in the background +DevMine.level.defaultError=No default level has been loaded +DevMine.level.preparing=Preparing level "{%0}" +DevMine.level.unloading=Unloading level "{%0}" +DevMine.server.start=Starting Minecraft: PE server version {%0} +DevMine.server.networkError=[Network] Stopped interface {%0} due to {%1} +DevMine.server.networkStart=Opening server on {%0}:{%1} +DevMine.server.info=This server is running {%0} version {%1} "{%2}" (API {%3}) +DevMine.server.info.extended=This server is running {%0} {%1} 「{%2}」 implementing API version {%3} for Minecraft: PE {%4} (protocol version {%5}) +DevMine.server.license={%0} is distributed under the LGPL License +DevMine.server.tickOverload=Can't keep up! Is the server overloaded? +DevMine.server.startFinished=Done ({%0}s)! For help, type "help" or "?" +DevMine.server.defaultGameMode=Default game type: {%0} +DevMine.server.query.start=Starting GS4 status listener +DevMine.server.query.info=Setting query port to {%0} +DevMine.server.query.running=Query running on {%0}:{%1} + +DevMine.command.alias.illegal=Could not register alias {%0} because it contains illegal characters +DevMine.command.alias.notFound=Could not register alias {%0} because it contains commands that do not exist: {%1} +DevMine.command.exception=Unhandled exception executing command '{%0}' in {%1}: {%2} + +DevMine.commands.cave.usage=/cave | /cave getmypos +DevMine.commands.cave.info=Angle of rotation:{%0} Length:{%1} Branch Number:{%2} Strength:{%3} +DevMine.commands.cave.start=Start to generate cave,please wait + +DevMine.command.plugins.description=Gets a list of plugins running on the server +DevMine.command.plugins.success=Plugins ({%0}): {%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=Reloads the server configuration and plugins +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=Reloading server... +DevMine.command.reload.reloaded=Reload complete. + +DevMine.command.lvdat.description=Change properties of a map. +DevMine.command.lvdat.changed=has changed {%1} of level "{%0}", some change need to reboot your server. +DevMine.command.lvdat.fixname=fixname successfully for level "{%0}", some change need to reboot your server. +DevMine.command.lvdat.nofound=level "{%0}" no found or load failed. +DevMine.command.lvdat.preset=Generator setting (preset) + +DevMine.command.status.description=Reads back the server's performance. +DevMine.command.status.usage=/status +DevMine.command.status.title=Server status +DevMine.command.status.player=Player count: +DevMine.command.status.days=days +DevMine.command.status.hours=hours +DevMine.command.status.minutes=minutes +DevMine.command.status.seconds=seconds +DevMine.command.status.uptime=Uptime: +DevMine.command.status.AverageTPS=Average TPS: +DevMine.command.status.CurrentTPS=Current TPS: +DevMine.command.status.Networkupload=Network upload: +DevMine.command.status.Networkdownload=Network download: +DevMine.command.status.Threadcount=Thread count: +DevMine.command.status.Mainmemory=Main thread memory: +DevMine.command.status.Totalmemory=Total memory: +DevMine.command.status.Totalvirtualmemory=Total virtual memory: +DevMine.command.status.Heapmemory=Heap memory: +DevMine.command.status.Maxmemorysystem=Maximum memory (system): +DevMine.command.status.Maxmemorymanager=Maximum memory (manager): +DevMine.command.status.World=World +DevMine.command.status.chunks=chunks, +DevMine.command.status.entities=entities, +DevMine.command.status.tiles=tiles. +DevMine.command.status.Time=Time +DevMine.command.status.ms=ms +DevMine.command.gc.description=Fires garbage collection tasks +DevMine.command.gc.usage=/gc +DevMine.command.gc.title=Danh sách dọn dẹp: +DevMine.command.gc.chunks=Chunks: +DevMine.command.gc.entities=Vật thể: +DevMine.command.gc.tiles=Tiles: +DevMine.command.gc.cycles=Cycles: +DevMine.command.gc.memory=Bộ nhớ được thả: + +DevMine.command.biome.description=change the biome of the area.(To change snow or rain) +DevMine.command.biome.posset=Has set pos{%3} at:({%1},{%2})[{%0}] +DevMine.command.biome.get=The ID of biome you stay is {%0} Color:{%1},{%2},{%3} +DevMine.command.biome.wrongLev=Cannot set point in different level. +DevMine.command.biome.wrongBio=Wrong ID of biome. e.g. 1 (Plains), 2 (Desert),13 (Ice Mountains),6 (Swampland) +DevMine.command.biome.wrongCol=Wrong Color. e.g. 146,188,89 .Use "/biome get" to get other color. +DevMine.command.biome.noPos=Plz use "/biome pos1|pos2" to select the area first. +DevMine.command.biome.set=Has set biome as:{%0} +DevMine.command.biome.color=Has set color as:{%0},{%1},{%2} + +DevMine.command.timings.description=Records timings to see performance of the server. +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=Enabled Timings & Reset +DevMine.command.timings.disable=Disabled Timings +DevMine.command.timings.timingsDisabled=Please enable timings by typing /timings on +DevMine.command.timings.reset=Timings reset +DevMine.command.timings.pasteError=An error happened while pasting the report +DevMine.command.timings.timingsUpload=Timings uploaded to {%0} +DevMine.command.timings.timingsRead=You can read the results at {%0} +DevMine.command.timings.timingsWrite=Timings written to {%0} +DevMine.command.version.description=Gets the version of this server including any plugins in use +DevMine.command.version.usage=/version [plugin name] +DevMine.command.version.noSuchPlugin=This server is not running any plugin by that name. Use /plugins to get a list of plugins. +DevMine.command.give.description=Gives the specified player a certain amount of items +DevMine.command.give.usage=/give [amount] [tags...] +DevMine.command.kill.description=Commit suicide or kill other players +DevMine.command.kill.usage=/kill [player] +DevMine.command.particle.description=Adds particles to a world +DevMine.command.particle.usage=/particle [count] [data] +DevMine.command.time.description=Changes the time on each world +DevMine.command.time.usage=/time OR /time +DevMine.command.bancidbyname.description=Prevents the specified CID by name from using this server禁止指定玩家的設備 ID +DevMine.command.bancid.description=Prevents the specified CID from using this server +DevMine.command.banipbyname.description=Prevents the specified IP address by name from using this server +DevMine.command.ban.player.description=Prevents the specified player from using this server +DevMine.command.ban.ip.description=Prevents the specified IP address from using this server +DevMine.command.banlist.description=View all players banned from this server +DevMine.command.defaultgamemode.description=Set the default gamemode +DevMine.command.deop.description=Takes the specified player's operator status +DevMine.command.difficulty.description=Sets the game difficulty +DevMine.command.enchant.description=Adds enchantments on items +DevMine.command.effect.description=Adds/Removes effects on players +DevMine.command.gamemode.description=Changes the player to a specific game mode +DevMine.command.help.description=Shows the help menu +DevMine.command.kick.description=Removes the specified player from the server +DevMine.command.list.description=Lists all online players +DevMine.command.me.description=Performs the specified action in chat +DevMine.command.op.description=Gives the specified player operator status +DevMine.command.unban.cid.description=Allows the specified CID to use this server +DevMine.command.unban.player.description=Allows the specified player to use this server +DevMine.command.unban.ip.description=Allows the specified IP address to use this server +DevMine.command.save.description=Saves the server to disk +DevMine.command.saveoff.description=Disables server autosaving +DevMine.command.saveon.description=Enables server autosaving +DevMine.command.say.description=Broadcasts the given message as the sender +DevMine.command.seed.description=Shows the world seed +DevMine.command.setworldspawn.description=Sets a worlds's spawn point. If no coordinates are specified, the player's coordinates will be used. +DevMine.command.spawnpoint.description=Sets a player's spawn point +DevMine.command.stop.description=Stops the server +DevMine.command.tp.description=Teleports the given player (or yourself) to another player or coordinates +DevMine.command.tell.description=Sends a private message to the given player +DevMine.command.xp.description=Add experience or experience level to the given player +DevMine.command.summon.description=Summons a entity at the player's location or a specific location +DevMine.command.fill.description=fills a specific selection with blocks +DevMine.command.setblock.description=Changes a block to another block + +DevMine.command.weather.description=Set weather for level +DevMine.command.weather.usage=/weather +DevMine.command.weather.changed=Weather changed successfully in level {%0}! +DevMine.command.weather.noregistered=level {%0} hasn't registered to WeatherManager. +DevMine.command.weather.invalid=Invalid weather.(0,1,2,3) +DevMine.command.weather.wrong=Wrong parameters. +DevMine.command.weather.invalid.level=Invalid level name. +DevMine.command.whitelist.description=Manages the list of players allowed to use this server +DevMine.crash.create=An unrecoverable error has occurred and the server has crashed. Creating a crash dump +DevMine.crash.error=Could not create crash dump: {%0} +DevMine.crash.submit=Please upload the "{%0}" file to the Crash Archive and submit the link to the Bug Reporting page. Give as much info as you can. +DevMine.crash.archive=The crash dump has been automatically submitted to the Crash Archive. You can view it on {%0} or use the ID #{%1}. +DevMine.debug.enable=LevelDB support enabled +DevMine.player.invalidMove={%0} moved wrongly! +DevMine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] logged in with entity id {%4} at ({%5}, {%6}, {%7}, {%8}) +DevMine.player.logOut={%0}[/{%1}:{%2}] logged out due to {%3} +DevMine.player.transferred={%0}[/{%1}:{%2}] was transferred to {%3} +DevMine.player.invalidEntity={%0} tried to attack an invalid entity +DevMine.plugin.load=Loading {%0} +DevMine.plugin.enable=Enabling {%0} +DevMine.plugin.disable=Disabling {%0} +DevMine.plugin.restrictedName=Restricted name +DevMine.plugin.incompatibleAPI=Incompatible API version +DevMine.plugin.unknownDependency=Unknown dependency +DevMine.plugin.circularDependency=Circular dependency detected +DevMine.plugin.genericLoadError=Could not load plugin '{%0}' +DevMine.plugin.spacesDiscouraged=Plugin '{%0}' uses spaces in its name, this is discouraged +DevMine.plugin.loadError=Could not load plugin '{%0}': {%1} +DevMine.plugin.duplicateError=Could not load plugin '{%0}': plugin exists +DevMine.plugin.fileError=Could not load '{%0}' in folder '{%1}': {%2} +DevMine.plugin.commandError=Could not load command {%0} for plugin {%1} +DevMine.plugin.aliasError=Could not load alias {%0} for plugin {%1} +DevMine.plugin.deprecatedEvent=Plugin '{%0}' has registered a listener for '{%1}' on method '{%2}', but the event is Deprecated. +DevMine.plugin.eventError="Could not pass event '{%0}' to '{%1}': {%2} on {%3} diff --git a/src/devmine/utilities/languages/locale/zho.ini b/src/devmine/utilities/languages/locale/zho.ini index 534d5b2..4a69e6e 100644 --- a/src/devmine/utilities/languages/locale/zho.ini +++ b/src/devmine/utilities/languages/locale/zho.ini @@ -1,20 +1,21 @@ # Language file compatible with Minecraft: Pocket Edition identifiers= #= # A message doesn't need to be there to be shown correctly on the client.= -# Only messages shown in devmine itself need to be here= +# Only messages shown in DevMine itself need to be here= language.name=中文(繁體) language.selected=設定 {%0} ({%1}) 為基本語言 -multiplayer.player.joined={%0} 加入了遊戲 -multiplayer.player.left={%0} 離開了遊戲 +multiplayer.player.joined={%0} 加入了伺服器 +multiplayer.player.left={%0} 離開了伺服器 -chat.type.text=<{%0}> {%1} +chat.type.text={%0} : {%1} chat.type.emote=* {%0} {%1} chat.type.announcement=[{%0}] {%1} chat.type.admin=[{%0}: {%1}] chat.type.achievement={%0} 剛剛獲得了成就 {%1} +disconnectionScreen.notAuthenticated=您需要 Xbox 登入 disconnectionScreen.outdatedClient=用戶端版本過舊! disconnectionScreen.outdatedServer=伺服器版本過舊! disconnectionScreen.serverFull=伺服器人數已滿! @@ -114,6 +115,7 @@ commands.players.list=共有 {%0}/{%1} 玩家在線上: commands.kill.successful=已刪除 {%0} commands.banlist.ips=共有 %d 個被封鎖的 IP 位址: commands.banlist.players=共有 {%0} 個被封鎖的玩家: +commands.banlist.cids=共有 {%0} 禁止的 CIDs: commands.banlist.usage=/banlist [ips|players] commands.defaultgamemode.usage=/defaultgamemode <模式> commands.defaultgamemode.success=預設遊戲模式已設定為 {%0} @@ -130,12 +132,13 @@ commands.seed.usage=/seed commands.seed.success=種子碼:{%0} commands.bancidbyname.success=封鎖玩家 {%0} 的CID -commands.bancidbyname.usage=/bancidbyname +commands.bancidbyname.usage=/bancidbyname <玩家名稱> commands.bancid.success=封鎖CID: {%0} -commands.bancid.usage=/bancid +commands.bancid.usage=/bancid <設備ID> -commands.unbancid.usage=/pardoncid +commands.unbancid.usage=/pardoncid <設備ID> +commands.unbancid.success=Unbanned CID {%0} commands.ban.success=封鎖玩家 {%0} commands.ban.usage=/ban <玩家名稱> [原因...] [時間(天)] @@ -153,7 +156,7 @@ commands.unbanip.success=解除封鎖 IP 位址 {%0} commands.unbanip.usage=/pardon-ip commands.banipbyname.success=封鎖玩家 {%0} 的IP -commands.banipbyname.usage=/banipbyname +commands.banipbyname.usage=/banipbyname <玩家名稱> commands.save.usage=/save-all commands.save-on.usage=/save-on @@ -164,7 +167,7 @@ commands.save.start=正在儲存... commands.save.success=儲存完畢 commands.setblock.usage=/setblock <方塊名> [數據值] -command.fill.invalidBlock=無效的方塊名/ID +command.setblock.invalidBlock=無效的方塊名稱/ID commands.stop.usage=/stop commands.stop.start=停止伺服器中 @@ -187,8 +190,8 @@ commands.whitelist.remove.success=從白名單刪除 {%0} commands.whitelist.remove.usage=/whitelist remove <玩家名稱> commands.whitelist.usage=/whitelist -commands.gamemode.success.self=設定自身的遊戲模式為 {%0} -commands.gamemode.success.other=設定 {%0} 的遊戲模式為 {%1} +commands.gamemode.success.self=設定自身的遊戲模式為 {%2} +commands.gamemode.success.other=設定 {%1} 的遊戲模式為 {%2} commands.gamemode.usage=/gamemode <模式> [玩家名稱] commands.help.header=--- 查看幫助列表第 {%0} 頁共 {%1} 頁 (/help ) --- commands.help.usage=/help [頁數|指令名稱] @@ -206,191 +209,199 @@ commands.setworldspawn.success=設定世界重生點為 ({%0}, {%1}, {%2}) commands.summon.usage=/summon <實體名稱> [ ] [數據標籤] -commands.cave.usage=/cave <旋轉角度> <洞穴長度> <分叉數> <洞穴強度> | /cave getmypos -commands.cave.info=旋轉角度:{%0} 洞穴長度:{%1} 分叉數:{%2} 洞穴強度:{%3} -commands.cave.start=開始生成礦洞,可能需要較多時間 -commands.cave.success=礦洞生成完畢啦 - -# -------------------- devmine language files, only for console -------------------- -devmine.data.playerNotFound=無法找到玩家數據 "{%0}",正在創建新的數據檔 -devmine.data.playerCorrupted=發現損壞的數據 "{%0}",創建新的設定檔 -devmine.data.playerOld=發現舊的玩家數據 "{%0}",更新設定檔 -devmine.data.saveError=無法儲存 "{%0}" 的玩家資料:{%1} -devmine.level.notFound=無法找到 "{%0}" 地圖 -devmine.level.loadError=無法讀取地圖 "{%0}":{%1} -devmine.level.generationError=無法產生地圖 "{%0}":{%1} -devmine.level.tickError=計算地圖「{%0}」時出現錯誤︰{%1} -devmine.level.chunkUnloadError=移除一個區塊時發生錯誤:{%0} -devmine.level.backgroundGeneration=正在於背景生成世界 「{%0}「 的地形 -devmine.level.defaultError=沒有讀取預設的地圖 -devmine.level.preparing=準備地圖中... "{%0}" -devmine.level.unloading=正在移除地圖 "{%0}" -devmine.server.start=正在啟動支援 Minecraft:PE {%0} 版本的伺服器 -devmine.server.networkError=[網路] 停止接口 {%0} 由於 {%1} -devmine.server.networkStart=正在啟動伺服器在 {%0}:{%1} -devmine.server.info=此伺服器正在運作 {%0} {%1} 版本 "{%2}" (API {%3}) -devmine.server.info.extended=此伺服器正在運作 {%0} {%1} 「{%2}」 執行 API 版本 {%3} 支援 Minecraft:PE {%4} (協定版本 {%5}) -devmine.server.license={%0} 根據 LGPL 許可發佈 -devmine.server.tickOverload=注意!伺服器有超載的可能 -devmine.server.startFinished=讀取完成 ({%0}s)!如需幫助,請輸入 "help" 或 "?" -devmine.server.defaultGameMode=預設的遊戲類型:{%0} -devmine.server.query.start=啟動 GS4 狀態監聽器 -devmine.server.query.info=設定 query 接口到 {%0} -devmine.server.query.running=Query 運作在 {%0}:{%1} - -devmine.command.alias.illegal=不能註冊別名 {%0},因為它包含非法字符 -devmine.command.alias.notFound=未能登記別稱 {%0} ,因為它包含不存在的指令: {%1} -devmine.command.exception=於 {%1} 執行指令 「{%0}「 時,出現了未被處理的錯誤: {%2} - -devmine.command.plugins.description=獲取在伺服器上運行的插件列表 -devmine.command.plugins.success=插件 ({%0}):{%1} -devmine.command.plugins.usage=/plugins - -devmine.command.reload.description=重新讀取伺服器設定和插件 -devmine.command.reload.usage=/reload -devmine.command.reload.reloading=重新讀取伺服器... -devmine.command.reload.reloaded=重新讀取完成 - -devmine.command.lvdat.description=修改地圖屬性 -devmine.command.lvdat.changed=對地圖{%0}的{%1}屬性修改已保存,部分屬性可能需要重啟伺服器後生效。 -devmine.command.lvdat.fixname=已修正地圖{%0}的名稱,建議重啟伺服器。 -devmine.command.lvdat.nofound=地圖{%0}沒有創建或者加載失敗。 -devmine.command.lvdat.preset=生成器選項(預設) - -devmine.command.status.description=重新讀取伺服器的性能。 -devmine.command.status.usage=/status - -devmine.command.status.title=伺服器狀態 -devmine.command.status.player=伺服器人數: -devmine.command.status.days=天 -devmine.command.status.hours=小時 -devmine.command.status.minutes=分 -devmine.command.status.seconds=秒 -devmine.command.status.uptime=運行時間: -devmine.command.status.AverageTPS=平均TPS: -devmine.command.status.CurrentTPS=瞬時TPS: -devmine.command.status.Networkupload=網路上傳: -devmine.command.status.Networkdownload=網路下載: -devmine.command.status.Threadcount=線程總數: -devmine.command.status.Mainmemory=線程總數: -devmine.command.status.Totalmemory=總記憶體: -devmine.command.status.Totalvirtualmemory=總虛擬記憶體: -devmine.command.status.Heapmemory=堆棧記憶體: -devmine.command.status.Maxmemorysystem=系統最大記憶體: -devmine.command.status.Maxmemorymanager=核心全域最大記憶體: -devmine.command.status.World=世界 -devmine.command.status.chunks=區塊, -devmine.command.status.entities=實體, -devmine.command.status.solidentities=solidentities. -devmine.command.status.Time=時間 -devmine.command.status.ms=毫秒 - -devmine.command.gc.description=啟動垃圾清除任務 -devmine.command.gc.usage=/gc -devmine.command.gc.title=垃圾回收結果 -devmine.command.gc.chunks=區塊: -devmine.command.gc.entities=實體: -devmine.command.gc.solidentities=方塊: -devmine.command.gc.cycles=循環: -devmine.command.gc.memory=記憶體釋放: - -devmine.command.biome.description=設定指定地圖生物群系 -devmine.command.biome.posset=已設定第{%3}個坐標為:({%1},{%2})[{%0}] -devmine.command.biome.get=您所在的生物群系 ID 為:{%0} 顏色值為:{%1},{%2},{%3} -devmine.command.biome.wrongLev=不能跨地圖設定取點。 -devmine.command.biome.wrongBio=錯誤的生物群系ID,請輸入數字ID(1=草原,2=沙漠,13=雪山,6=沼澤) -devmine.command.biome.wrongCol=錯誤的生物群系顏色,例如 146,188,89 可以使用 /biome get 獲取 -devmine.command.biome.noPos=請先通過 /biome pos1|pos2 設定範圍 -devmine.command.biome.set=已成功設定生物群系為:{%0} -devmine.command.biome.color=已成功設定生態顏色為:{%0},{%1},{%2} - -devmine.command.timings.description=紀錄計時數據,以檢視伺服器的性能。 -devmine.command.timings.usage=/timings -devmine.command.timings.enable=啟用定時和重啟 -devmine.command.timings.disable=停用定時 -devmine.command.timings.timingsDisabled=啟用定時工具透過 /timings on -devmine.command.timings.reset=定時重啟 -devmine.command.timings.pasteError=已記錄在事件記錄檔中 -devmine.command.timings.timingsUpload=計時數據已被上載至 {%0} -devmine.command.timings.timingsRead=你可以在 {%0} 閱讀計時結果 -devmine.command.timings.timingsWrite=計時數據已被儲存至 {%0} -devmine.command.version.description=檢視此伺服器 (及其使用的插件) 的版本 -devmine.command.version.usage=/version [插件名稱] -devmine.command.version.noSuchPlugin=該伺服器沒有運行任何叫這個名稱的插件。使用 /plugins 來獲得插件列表。 -devmine.command.give.description=給指定玩家一定數量的物品 -devmine.command.give.usage=/give <玩家名稱> <物品[:耐久度]> [數量] [附加數據值] -devmine.command.kill.description=自殺或殺死其他玩家 -devmine.command.kill.usage=/kill [玩家名稱] -devmine.command.particle.description=加入粒子效果至世界 -devmine.command.particle.usage=/particle <玩家名稱> [數量] [數據值] -devmine.command.time.description=更改每個世界的時間 -devmine.command.time.usage=/time <數值> 或 /time -devmine.command.bancidbyname.description=禁止指定玩家的設備 ID -devmine.command.bancid.description=禁止指定的設備 ID -devmine.command.banipbyname.description=禁止指定玩家的 IP -devmine.command.ban.player.description=禁止指定的玩家使用此伺服器 -devmine.command.ban.ip.description=禁止指定的 IP 位址使用此伺服器 -devmine.command.banlist.description=查看來自該伺服器禁止的所有玩家 -devmine.command.defaultgamemode.description=設定預設的遊戲模式 -devmine.command.deop.description=移除指定玩家的管理員權限 -devmine.command.difficulty.description=設定遊戲的難易度 -devmine.command.enchant.description=把物件附魔 -devmine.command.effect.description=增加/減少玩家身上的效果 -devmine.command.gamemode.description=改變玩家到一個特定的遊戲模式 -devmine.command.help.description=顯示幫助列表 -devmine.command.kick.description=從伺服器中刪除指定玩家 -devmine.command.list.description=顯示在線玩家列表 -devmine.command.me.description=於聊天中作出指定的動作 -devmine.command.op.description=賦予指定玩家管理員權限 -devmine.command.unban.cid.description=允許指定 CID 使用此伺服器 -devmine.command.unban.player.description=允許指定玩家使用此伺服器 -devmine.command.unban.ip.description=允許指定 IP 位址使用此伺服器 -devmine.command.save.description=儲存伺服器到磁碟上 -devmine.command.saveoff.description=停用自動儲存伺服器 -devmine.command.saveon.description=啟用自動儲存伺服器 -devmine.command.say.description=以發送指令者身份廣播指定的訊息 -devmine.command.seed.description=顯示世界種子碼 -devmine.command.setworldspawn.description=設定一個世界重生點。未指定坐標,將使用玩家的坐標。 -devmine.command.spawnpoint.description=設定玩家重生點 -devmine.command.stop.description=關閉伺服器 -devmine.command.tp.description=傳送指定玩家(或是自己)到另一位玩家或座標 -devmine.command.tell.description=傳送私訊給指定玩家 -devmine.command.xp.description=給指定玩家新增經驗值或等級 -devmine.command.summon.description=召喚指定的實體於玩家位置或指定位置 -devmine.command.setblock.description=將一個方塊更改為另一個方塊 - -devmine.command.weather.description=設定指定地圖的天氣 -devmine.command.weather.usage=/weather <地圖名稱 天氣|天氣> -devmine.command.weather.changed=成功設定地圖{%0}的天氣 -devmine.command.weather.noregistered=地圖{%0}未註冊到天氣管理器 -devmine.command.weather.invalid=無效的天氣!請輸入天氣 0,1,2,3。 -devmine.command.weather.wrong=錯誤的參數 -devmine.command.weather.invalid.level=錯誤的地圖名稱 - -devmine.command.whitelist.description=管理員允許使用此伺服器的玩家列表 -devmine.crash.create=一個不能回復的錯誤發生了,使伺服器崩潰。正在儲存錯誤報告。 -devmine.crash.error=未能儲存錯誤報告︰{%0} -devmine.crash.submit=請上載檔案「{%0}」至線上崩潰儲存庫,並把所獲之連結提交至漏洞報告網頁。請盡量提供更多資料。 -devmine.crash.archive=毀損傾印報告已經自動地被提交到毀損傾印存檔。你可以在{%0} 查看到它或使用ID #{%1}。 -devmine.debug.enable=啟用 LevelDB 支援 -devmine.player.invalidMove={%0} 行動可疑! -devmine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] 登入遊戲,實體ID為 {%4} 座標位在 ({%5}, {%6}, {%7}, {%8}) -devmine.player.logOut={%0}[/{%1}:{%2}] 登出遊戲,原因: {%3} -devmine.player.transferred={%0}[/{%1}:{%2}] 被傳送到 {%3} -devmine.player.invalidEntity={%0} 嘗試攻擊一個無效的實體 -devmine.plugin.load=讀取中... {%0} -devmine.plugin.enable=開啟中... {%0} -devmine.plugin.disable=關閉中... {%0} -devmine.plugin.restrictedName=受限的名稱 -devmine.plugin.incompatibleAPI=不相容的API版本 -devmine.plugin.unknownDependency=本插件無法單獨使用 -devmine.plugin.circularDependency=檢測出循環依賴 -devmine.plugin.genericLoadError=無法讀取插件 '{%0}' -devmine.plugin.spacesDiscouraged=插件 '{%0}' 在名稱中使用了空格,不建議這樣做 -devmine.plugin.loadError=無法讀取插件 '{%0}':{%1} -devmine.plugin.duplicateError=無法讀取插件 '{%0}':已有相同插件 -devmine.plugin.fileError=無法讀取在 '{%1}' 資料夾中的 '{%0}':{%2} -devmine.plugin.commandError=無法讀取 {%1} 插件的 {%0} 指令 -devmine.plugin.aliasError=無法讀取 {%1} 插件的 {%0} 別名 -devmine.plugin.deprecatedEvent=插件 '{%0}' 已經使用 '{%2}' 方法註冊了一個在 '{%1}' 的監聽器,但是該事件已過時。 -devmine.plugin.eventError="無法處理事件 '{%0}' 至 '{%1}':{%2} 在 {%3} 上" + +# -------------------- DevMine language files, only for console -------------------- +DevMine.data.playerNotFound=無法找到玩家數據 "{%0}",正在創建新的數據檔 +DevMine.data.playerCorrupted=發現損壞的數據 "{%0}",創建新的設定檔 +DevMine.data.playerOld=發現舊的玩家數據 "{%0}",更新設定檔 +DevMine.data.saveError=無法儲存 "{%0}" 的玩家資料:{%1} +DevMine.level.notFound=無法找到 "{%0}" 地圖 +DevMine.level.loadError=無法讀取地圖 "{%0}":{%1} +DevMine.level.generationError=無法產生地圖 "{%0}":{%1} +DevMine.level.tickError=計算地圖「{%0}」時出現錯誤︰{%1} +DevMine.level.chunkUnloadError=移除一個區塊時發生錯誤:{%0} +DevMine.level.backgroundGeneration=正在於背景生成世界 「{%0}「 的地形 +DevMine.level.defaultError=沒有讀取預設的地圖 +DevMine.level.preparing=準備地圖中... "{%0}" +DevMine.level.unloading=正在移除地圖 "{%0}" +DevMine.server.start=正在啟動支援 Minecraft:PE {%0} 版本的伺服器 +DevMine.server.networkError=[網路] 停止接口 {%0} 由於 {%1} +DevMine.server.networkStart=正在啟動伺服器在 {%0}:{%1} +DevMine.server.info=此伺服器正在運作 {%0} {%1} 版本 "{%2}" (API {%3}) + +DevMine.server.info.extended=此伺服器正在運作 {%0} {%1} 「{%2}」 執行 API 版本 {%3} 支援 Minecraft:PE {%4} (協定版本 {%5}) +DevMine.server.info.extended1=本伺服器正運行 {%0}{%1} (代號 "{%2}") +DevMine.server.info.extended2=PHP 版本: {%0} +DevMine.server.info.extended3=API: {%0} (iTX API 版本 {%1}) +DevMine.server.info.extended4=Target client: Minecraft PE {%0} (protocol 版本 {%1}) + +DevMine.server.license={%0} 根據 LGPL 許可發佈 +DevMine.server.tickOverload=注意!伺服器有超載的可能 +DevMine.server.startFinished=讀取完成 ({%0}s)!如需幫助,請輸入 "help" 或 "?" +DevMine.server.defaultGameMode=預設的遊戲類型:{%0} +DevMine.server.query.start=啟動 GS4 狀態監聽器 +DevMine.server.query.info=設定 query 接口到 {%0} +DevMine.server.query.running=Query 運作在 {%0}:{%1} + +DevMine.command.alias.illegal=不能註冊別名 {%0},因為它包含非法字符 +DevMine.command.alias.notFound=未能登記別稱 {%0} ,因為它包含不存在的指令: {%1} +DevMine.command.exception=於 {%1} 執行指令 「{%0}「 時,出現了未被處理的錯誤: {%2} + +DevMine.commands.cave.usage=/cave <旋轉角度> <洞穴長度> <分叉數> <洞穴強度> | /cave getmypos +DevMine.commands.cave.info=旋轉角度:{%0} 洞穴長度:{%1} 分叉數:{%2} 洞穴強度:{%3} +DevMine.commands.cave.start=開始生成礦洞,可能需要較多時間 +DevMine.commands.cave.success=礦洞生成完畢啦 + +DevMine.command.plugins.description=獲取在伺服器上運行的插件列表 +DevMine.command.plugins.success=插件 ({%0}):{%1} +DevMine.command.plugins.usage=/plugins + +DevMine.command.reload.description=重新讀取伺服器設定和插件 +DevMine.command.reload.usage=/reload +DevMine.command.reload.reloading=重新讀取伺服器... +DevMine.command.reload.reloaded=重新讀取完成 + +DevMine.command.lvdat.description=修改地圖屬性 +DevMine.command.lvdat.changed=對地圖{%0}的{%1}屬性修改已保存,部分屬性可能需要重啟伺服器後生效。 +DevMine.command.lvdat.fixname=已修正地圖{%0}的名稱,建議重啟伺服器。 +DevMine.command.lvdat.nofound=地圖{%0}沒有創建或者加載失敗。 +DevMine.command.lvdat.preset=生成器選項(預設) + +DevMine.command.status.description=重新讀取伺服器的性能。 +DevMine.command.status.usage=/status + +DevMine.command.status.title=伺服器狀態 +DevMine.command.status.player=伺服器人數: +DevMine.command.status.days=天 +DevMine.command.status.hours=小時 +DevMine.command.status.minutes=分 +DevMine.command.status.seconds=秒 +DevMine.command.status.uptime=運行時間: +DevMine.command.status.AverageTPS=平均TPS: +DevMine.command.status.CurrentTPS=瞬時TPS: +DevMine.command.status.Networkupload=網路上傳: +DevMine.command.status.Networkdownload=網路下載: +DevMine.command.status.Threadcount=線程總數: +DevMine.command.status.Mainmemory=線程總數: +DevMine.command.status.Totalmemory=總記憶體: +DevMine.command.status.Totalvirtualmemory=總虛擬記憶體: +DevMine.command.status.Heapmemory=堆棧記憶體: +DevMine.command.status.Maxmemorysystem=系統最大記憶體: +DevMine.command.status.Maxmemorymanager=核心全域最大記憶體: +DevMine.command.status.World=世界 +DevMine.command.status.chunks=區塊, +DevMine.command.status.entities=實體, +DevMine.command.status.tiles=tiles. +DevMine.command.status.Time=時間 +DevMine.command.status.ms=毫秒 + +DevMine.command.gc.description=啟動垃圾清除任務 +DevMine.command.gc.usage=/gc +DevMine.command.gc.title=垃圾回收結果 +DevMine.command.gc.chunks=區塊: +DevMine.command.gc.entities=實體: +DevMine.command.gc.tiles=方塊: +DevMine.command.gc.cycles=循環: +DevMine.command.gc.memory=記憶體釋放: + +DevMine.command.biome.description=設定指定地圖生物群系 +DevMine.command.biome.posset=已設定第{%3}個坐標為:({%1},{%2})[{%0}] +DevMine.command.biome.get=您所在的生物群系 ID 為:{%0} 顏色值為:{%1},{%2},{%3} +DevMine.command.biome.wrongLev=不能跨地圖設定取點。 +DevMine.command.biome.wrongBio=錯誤的生物群系ID,請輸入數字ID(1=草原,2=沙漠,13=雪山,6=沼澤) +DevMine.command.biome.wrongCol=錯誤的生物群系顏色,例如 146,188,89 可以使用 /biome get 獲取 +DevMine.command.biome.noPos=請先通過 /biome pos1|pos2 設定範圍 +DevMine.command.biome.set=已成功設定生物群系為:{%0} +DevMine.command.biome.color=已成功設定生態顏色為:{%0},{%1},{%2} + +DevMine.command.timings.description=紀錄計時數據,以檢視伺服器的性能。 +DevMine.command.timings.usage=/timings +DevMine.command.timings.enable=啟用定時和重啟 +DevMine.command.timings.disable=停用定時 +DevMine.command.timings.timingsDisabled=啟用定時工具透過 /timings on +DevMine.command.timings.reset=定時重啟 +DevMine.command.timings.pasteError=已記錄在事件記錄檔中 +DevMine.command.timings.timingsUpload=計時數據已被上載至 {%0} +DevMine.command.timings.timingsRead=你可以在 {%0} 閱讀計時結果 +DevMine.command.timings.timingsWrite=計時數據已被儲存至 {%0} +DevMine.command.version.description=檢視此伺服器 (及其使用的插件) 的版本 +DevMine.command.version.usage=/version [插件名稱] +DevMine.command.version.noSuchPlugin=該伺服器沒有運行任何叫這個名稱的插件。使用 /plugins 來獲得插件列表。 +DevMine.command.give.description=給指定玩家一定數量的物品 +DevMine.command.give.usage=/give <玩家名稱> <物品[:耐久度]> [數量] [附加數據值] +DevMine.command.kill.description=自殺或殺死其他玩家 +DevMine.command.kill.usage=/kill [玩家名稱] +DevMine.command.particle.description=加入粒子效果至世界 +DevMine.command.particle.usage=/particle <玩家名稱> [數量] [數據值] +DevMine.command.time.description=更改每個世界的時間 +DevMine.command.time.usage=/time <數值> 或 /time +DevMine.command.bancidbyname.description=禁止指定玩家的設備 ID +DevMine.command.bancid.description=禁止指定的設備 ID +DevMine.command.banipbyname.description=禁止指定玩家的 IP +DevMine.command.ban.player.description=禁止指定的玩家使用此伺服器 +DevMine.command.ban.ip.description=禁止指定的 IP 位址使用此伺服器 +DevMine.command.banlist.description=查看來自該伺服器禁止的所有玩家 +DevMine.command.defaultgamemode.description=設定預設的遊戲模式 +DevMine.command.deop.description=移除指定玩家的管理員權限 +DevMine.command.difficulty.description=設定遊戲的難易度 +DevMine.command.enchant.description=把物件附魔 +DevMine.command.effect.description=增加/減少玩家身上的效果 +DevMine.command.gamemode.description=改變玩家到一個特定的遊戲模式 +DevMine.command.help.description=顯示幫助列表 +DevMine.command.kick.description=從伺服器中刪除指定玩家 +DevMine.command.list.description=顯示在線玩家列表 +DevMine.command.me.description=於聊天中作出指定的動作 +DevMine.command.op.description=賦予指定玩家管理員權限 +DevMine.command.unban.cid.description=允許指定 CID 使用此伺服器 +DevMine.command.unban.player.description=允許指定玩家使用此伺服器 +DevMine.command.unban.ip.description=允許指定 IP 位址使用此伺服器 +DevMine.command.save.description=儲存伺服器到磁碟上 +DevMine.command.saveoff.description=停用自動儲存伺服器 +DevMine.command.saveon.description=啟用自動儲存伺服器 +DevMine.command.say.description=以發送指令者身份廣播指定的訊息 +DevMine.command.seed.description=顯示世界種子碼 +DevMine.command.setworldspawn.description=設定一個世界重生點。未指定坐標,將使用玩家的坐標。 +DevMine.command.spawnpoint.description=設定玩家重生點 +DevMine.command.stop.description=關閉伺服器 +DevMine.command.tp.description=傳送指定玩家(或是自己)到另一位玩家或座標 +DevMine.command.tell.description=傳送私訊給指定玩家 +DevMine.command.xp.description=給指定玩家新增經驗值或等級 +DevMine.command.summon.description=召喚指定的實體於玩家位置或指定位置 +ocketmine.command.fill.description=填充了指定方塊 +DevMine.command.setblock.description=將一個方塊更改為另一個方塊 + +DevMine.command.weather.description=設定指定地圖的天氣 +DevMine.command.weather.usage=/weather <地圖名稱 天氣|天氣> +DevMine.command.weather.changed=成功設定地圖{%0}的天氣 +DevMine.command.weather.noregistered=地圖{%0}未註冊到天氣管理器 +DevMine.command.weather.invalid=無效的天氣!請輸入天氣 0,1,2,3。 +DevMine.command.weather.wrong=錯誤的參數 +DevMine.command.weather.invalid.level=錯誤的地圖名稱 + +DevMine.command.whitelist.description=管理員允許使用此伺服器的玩家列表 +DevMine.crash.create=一個不能回復的錯誤發生了,使伺服器崩潰。正在儲存錯誤報告。 +DevMine.crash.error=未能儲存錯誤報告︰{%0} +DevMine.crash.submit=請上載檔案「{%0}」至線上崩潰儲存庫,並把所獲之連結提交至漏洞報告網頁。請盡量提供更多資料。 +DevMine.crash.archive=毀損傾印報告已經自動地被提交到毀損傾印存檔。你可以在{%0} 查看到它或使用ID #{%1}。 +DevMine.debug.enable=啟用 LevelDB 支援 +DevMine.player.invalidMove={%0} 行動可疑! +DevMine.player.logIn={%0}[/{%1}:{%2}] [ClientID: {%3}] 登入遊戲,實體ID為 {%4} 座標位在 ({%5}, {%6}, {%7}, {%8}) +DevMine.player.logOut={%0}[/{%1}:{%2}] 登出遊戲,原因: {%3} +DevMine.player.transferred={%0}[/{%1}:{%2}] 被傳送到 {%3} +DevMine.player.invalidEntity={%0} 嘗試攻擊一個無效的實體 +DevMine.plugin.load=讀取中... {%0} +DevMine.plugin.enable=開啟中... {%0} +DevMine.plugin.disable=關閉中... {%0} +DevMine.plugin.restrictedName=受限的名稱 +DevMine.plugin.incompatibleAPI=不相容的API版本 +DevMine.plugin.unknownDependency=本插件無法單獨使用 +DevMine.plugin.circularDependency=檢測出循環依賴 +DevMine.plugin.genericLoadError=無法讀取插件 '{%0}' +DevMine.plugin.spacesDiscouraged=插件 '{%0}' 在名稱中使用了空格,不建議這樣做 +DevMine.plugin.loadError=無法讀取插件 '{%0}':{%1} +DevMine.plugin.duplicateError=無法讀取插件 '{%0}':已有相同插件 +DevMine.plugin.fileError=無法讀取在 '{%1}' 資料夾中的 '{%0}':{%2} +DevMine.plugin.commandError=無法讀取 {%1} 插件的 {%0} 指令 +DevMine.plugin.aliasError=無法讀取 {%1} 插件的 {%0} 別名 +DevMine.plugin.deprecatedEvent=插件 '{%0}' 已經使用 '{%2}' 方法註冊了一個在 '{%1}' 的監聽器,但是該事件已過時。 +DevMine.plugin.eventError="無法處理事件 '{%0}' 至 '{%1}':{%2} 在 {%3} 上" diff --git a/src/devmine/utilities/main/Binary.php b/src/devmine/utilities/main/Binary.php index 4ea8327..c0e39ef 100644 --- a/src/devmine/utilities/main/Binary.php +++ b/src/devmine/utilities/main/Binary.php @@ -5,13 +5,19 @@ /** * Various Utilities used around the code */ + namespace devmine\utilities\main; + use devmine\creatures\entities\Entity; +use devmine\inventory\items\Item; class Binary{ const BIG_ENDIAN = 0x00; const LITTLE_ENDIAN = 0x01; + private static function checkLength($str, $expect){ + assert(($len = strlen($str)) === $expect, "Expected $expect bytes, got $len"); + } /** * Reads a 3-byte big-endian number @@ -21,6 +27,7 @@ class Binary{ * @return mixed */ public static function readTriad($str){ + self::checkLength($str, 3); return unpack("N", "\x00" . $str)[1]; } @@ -43,6 +50,7 @@ public static function writeTriad($value){ * @return mixed */ public static function readLTriad($str){ + self::checkLength($str, 3); return unpack("V", $str . "\x00")[1]; } @@ -58,125 +66,116 @@ public static function writeLTriad($value){ } /** - * Writes a coded epilogos string + * Writes a coded metadata string * * @param array $data * * @return string */ - public static function writeepilogos(array $data){ - $m = ""; - foreach($data as $bottom => $d){ - $m .= chr(($d[0] << 5) | ($bottom & 0x1F)); + public static function writeMetadata(array $data){ + $stream = new BinaryStream(); + $stream->putUnsignedVarInt(count($data)); + foreach($data as $key => $d){ + $stream->putUnsignedVarInt($key); //data key + $stream->putUnsignedVarInt($d[0]); //data type switch($d[0]){ case Entity::DATA_TYPE_BYTE: - $m .= self::writeByte($d[1]); + $stream->putByte($d[1]); break; case Entity::DATA_TYPE_SHORT: - $m .= self::writeLShort($d[1]); + $stream->putLShort($d[1]); //SIGNED short! break; case Entity::DATA_TYPE_INT: - $m .= self::writeLInt($d[1]); + $stream->putVarInt($d[1]); break; case Entity::DATA_TYPE_FLOAT: - $m .= self::writeLFloat($d[1]); + $stream->putLFloat($d[1]); break; case Entity::DATA_TYPE_STRING: - $m .= self::writeLShort(strlen($d[1])) . $d[1]; + $stream->putString($d[1]); break; case Entity::DATA_TYPE_SLOT: - $m .= self::writeLShort($d[1][0]); - $m .= self::writeByte($d[1][1]); - $m .= self::writeLShort($d[1][2]); + //TODO: change this implementation (use objects) + $stream->putSlot(Item::get($d[1][0], $d[1][2], $d[1][1])); //ID, damage, count break; case Entity::DATA_TYPE_POS: - $m .= self::writeLInt($d[1][0]); - $m .= self::writeLInt($d[1][1]); - $m .= self::writeLInt($d[1][2]); + //TODO: change this implementation (use objects) + $stream->putBlockCoords($d[1][0], $d[1][1], $d[1][2]); //x, y, z break; case Entity::DATA_TYPE_LONG: - $m .= self::writeLLong($d[1]); + $stream->putVarInt($d[1]); //TODO: varint64 support break; + case Entity::DATA_TYPE_VECTOR3F: + //TODO: change this implementation (use objects) + $stream->putVector3f($d[1][0], $d[1][1], $d[1][2]); //x, y, z } } - $m .= "\x7f"; - return $m; + return $stream->getBuffer(); } /** - * Reads a epilogos coded string + * Reads a metadata coded string * * @param $value * @param bool $types * * @return array */ - public static function readepilogos($value, $types = false){ - $offset = 0; - $m = []; - $b = ord($value{$offset}); - ++$offset; - while($b !== 127 and isset($value{$offset})){ - $bottom = $b & 0x1F; - $type = $b >> 5; + public static function readMetadata($value, $types = false){ + $stream = new BinaryStream(); + $stream->setBuffer($value); + $count = $stream->getUnsignedVarInt(); + $data = []; + for($i = 0; $i < $count; ++$i){ + $key = $stream->getUnsignedVarInt(); + $type = $stream->getUnsignedVarInt(); + $value = null; switch($type){ case Entity::DATA_TYPE_BYTE: - $r = self::readByte($value{$offset}); - ++$offset; + $value = $stream->getByte(); break; case Entity::DATA_TYPE_SHORT: - $r = self::readLShort(substr($value, $offset, 2)); - $offset += 2; + $value = $stream->getLShort(true); //signed break; case Entity::DATA_TYPE_INT: - $r = self::readLInt(substr($value, $offset, 4)); - $offset += 4; + $value = $stream->getVarInt(); break; case Entity::DATA_TYPE_FLOAT: - $r = self::readLFloat(substr($value, $offset, 4)); - $offset += 4; + $value = $stream->getLFloat(); break; case Entity::DATA_TYPE_STRING: - $len = self::readLShort(substr($value, $offset, 2)); - $offset += 2; - $r = substr($value, $offset, $len); - $offset += $len; + $value = $stream->getString(); break; case Entity::DATA_TYPE_SLOT: - $r = []; - $r[] = self::readLShort(substr($value, $offset, 2)); - $offset += 2; - $r[] = ord($value{$offset}); - ++$offset; - $r[] = self::readLShort(substr($value, $offset, 2)); - $offset += 2; + //TODO: use objects directly + $item = $stream->getSlot(); + $value[0] = $item->getId(); + $value[1] = $item->getCount(); + $value[2] = $item->getDamage(); break; case Entity::DATA_TYPE_POS: - $r = []; - for($i = 0; $i < 3; ++$i){ - $r[] = self::readLInt(substr($value, $offset, 4)); - $offset += 4; - } + $value = [0, 0, 0]; + $stream->getBlockCoords($value[0], $value[1], $value[2]); break; case Entity::DATA_TYPE_LONG: - $r = self::readLLong(substr($value, $offset, 4)); - $offset += 8; + $value = $stream->getVarInt(); //TODO: varint64 proper support + break; + case Entity::DATA_TYPE_VECTOR3F: + $value = [0.0, 0.0, 0.0]; + $stream->getVector3f($value[0], $value[1], $value[2]); break; default: - return []; - + $value = []; } if($types === true){ - $m[$bottom] = [$r, $type]; + $data[$key] = [$value, $type]; }else{ - $m[$bottom] = $r; + $data[$key] = $value; } - $b = ord($value{$offset}); - ++$offset; } - return $m; + return $data; } /** @@ -210,6 +209,7 @@ public static function writeBool($b){ * @return int */ public static function readByte($c, $signed = true){ + self::checkLength($c, 1); $b = ord($c{0}); if($signed){ @@ -242,6 +242,7 @@ public static function writeByte($c){ * @return int */ public static function readShort($str){ + self::checkLength($str, 2); return unpack("n", $str)[1]; } @@ -253,6 +254,7 @@ public static function readShort($str){ * @return int */ public static function readSignedShort($str){ + self::checkLength($str, 2); if(PHP_INT_SIZE === 8){ return unpack("n", $str)[1] << 48 >> 48; }else{ @@ -279,6 +281,7 @@ public static function writeShort($value){ * @return int */ public static function readLShort($str){ + self::checkLength($str, 2); return unpack("v", $str)[1]; } @@ -290,6 +293,7 @@ public static function readLShort($str){ * @return int */ public static function readSignedLShort($str){ + self::checkLength($str, 2); if(PHP_INT_SIZE === 8){ return unpack("v", $str)[1] << 48 >> 48; }else{ @@ -309,7 +313,7 @@ public static function writeLShort($value){ } public static function readInt($str){ - if(strlen($str) != 4) return 0; + self::checkLength($str, 4); if(PHP_INT_SIZE === 8){ return unpack("N", $str)[1] << 32 >> 32; }else{ @@ -322,6 +326,7 @@ public static function writeInt($value){ } public static function readLInt($str){ + self::checkLength($str, 4); if(PHP_INT_SIZE === 8){ return unpack("V", $str)[1] << 32 >> 32; }else{ @@ -334,6 +339,7 @@ public static function writeLInt($value){ } public static function readFloat($str){ + self::checkLength($str, 4); return ENDIANNESS === self::BIG_ENDIAN ? unpack("f", $str)[1] : unpack("f", strrev($str))[1]; } @@ -342,6 +348,7 @@ public static function writeFloat($value){ } public static function readLFloat($str){ + self::checkLength($str, 4); return ENDIANNESS === self::BIG_ENDIAN ? unpack("f", strrev($str))[1] : unpack("f", $str)[1]; } @@ -354,6 +361,7 @@ public static function printFloat($value){ } public static function readDouble($str){ + self::checkLength($str, 8); return ENDIANNESS === self::BIG_ENDIAN ? unpack("d", $str)[1] : unpack("d", strrev($str))[1]; } @@ -362,6 +370,7 @@ public static function writeDouble($value){ } public static function readLDouble($str){ + self::checkLength($str, 8); return ENDIANNESS === self::BIG_ENDIAN ? unpack("d", strrev($str))[1] : unpack("d", $str)[1]; } @@ -370,6 +379,7 @@ public static function writeLDouble($value){ } public static function readLong($x){ + self::checkLength($x, 8); if(PHP_INT_SIZE === 8){ $int = unpack("N*", $x); return ($int[1] << 32) | $int[2]; @@ -415,4 +425,44 @@ public static function writeLLong($value){ return strrev(self::writeLong($value)); } + //TODO: proper varlong support + + public static function readVarInt($stream){ + $shift = PHP_INT_SIZE === 8 ? 63 : 31; + $raw = self::readUnsignedVarInt($stream); + $temp = ((($raw << $shift) >> $shift) ^ $raw) >> 1; + return $temp ^ ($raw & (1 << $shift)); + } + + public static function readUnsignedVarInt($stream){ + $value = 0; + $i = 0; + do{ + if($i > 63){ + throw new \InvalidArgumentException("Varint did not terminate after 10 bytes!"); + } + $value |= ((($b = $stream->getByte()) & 0x7f) << $i); + $i += 7; + }while($b & 0x80); + + return $value; + } + + public static function writeVarInt($v){ + return self::writeUnsignedVarInt(($v << 1) ^ ($v >> (PHP_INT_SIZE === 8 ? 63 : 31))); + } + + public static function writeUnsignedVarInt($value){ + $buf = ""; + for($i = 0; $i < 10; ++$i){ + if(($value >> 7) !== 0){ + $buf .= chr($value | 0x80); //Let chr() take the last byte of this, it's faster than adding another & 0x7f. + }else{ + $buf .= chr($value & 0x7f); + return $buf; + } + $value = (($value >> 7) & (PHP_INT_MAX >> 6)); //PHP really needs a logical right-shift operator + } + throw new \InvalidArgumentException("Value too large to be encoded as a varint"); + } } diff --git a/src/devmine/utilities/main/BinaryStream.php b/src/devmine/utilities/main/BinaryStream.php index 58f2814..0745343 100644 --- a/src/devmine/utilities/main/BinaryStream.php +++ b/src/devmine/utilities/main/BinaryStream.php @@ -38,7 +38,9 @@ public function get($len){ $this->offset = strlen($this->buffer) - 1; return ""; }elseif($len === true){ - return substr($this->buffer, $this->offset); + $str = substr($this->buffer, $this->offset); + $this->offset = strlen($this->buffer); + return $str; } return $len === 1 ? $this->buffer{$this->offset++} : substr($this->buffer, ($this->offset += $len) - $len, $len); } @@ -47,6 +49,14 @@ public function put($str){ $this->buffer .= $str; } + public function getBool() : bool{ + return (bool) $this->getByte(); + } + + public function putBool($v){ + $this->putByte((bool) $v); + } + public function getLong(){ return Binary::readLong($this->get(8)); } @@ -167,18 +177,16 @@ public function putUUID(UUID $uuid){ } public function getSlot(){ - $id = $this->getSignedShort(); + $id = $this->getVarInt(); if($id <= 0){ return Item::get(0, 0, 0); } - - $cnt = $this->getByte(); - - $data = $this->getShort(); + $auxValue = $this->getVarInt(); + $data = $auxValue >> 8; + $cnt = $auxValue & 0xff; $nbtLen = $this->getLShort(); - $nbt = ""; if($nbtLen > 0){ @@ -192,31 +200,93 @@ public function getSlot(){ ); } + public function putSlot(Item $item){ if($item->getId() === 0){ - $this->putShort(0); + $this->putVarInt(0); return; } - $this->putShort($item->getId()); - $this->putByte($item->getCount()); - $this->putShort($item->getDamage() === null ? -1 : $item->getDamage()); + $this->putVarInt($item->getId()); + $auxValue = (($item->getDamage() ?? -1) << 8) | $item->getCount(); + $this->putVarInt($auxValue); $nbt = $item->getCompoundTag(); $this->putLShort(strlen($nbt)); $this->put($nbt); - } public function getString(){ - return $this->get($this->getShort()); + return $this->get($this->getUnsignedVarInt()); } public function putString($v){ - $this->putShort(strlen($v)); + $this->putUnsignedVarInt(strlen($v)); $this->put($v); } + //TODO: varint64 + + /** + * Reads an unsigned varint32 from the stream. + */ + public function getUnsignedVarInt(){ + return Binary::readUnsignedVarInt($this); + } + + /** + * Writes an unsigned varint32 to the stream. + */ + public function putUnsignedVarInt($v){ + $this->put(Binary::writeUnsignedVarInt($v)); + } + + /** + * Reads a signed varint32 from the stream. + */ + public function getVarInt(){ + return Binary::readVarInt($this); + } + + /** + * Writes a signed varint32 to the stream. + */ + public function putVarInt($v){ + $this->put(Binary::writeVarInt($v)); + } + + public function getEntityId(){ + return $this->getVarInt(); + } + + public function putEntityId($v){ + $this->putVarInt($v); + } + + public function getBlockCoords(&$x, &$y, &$z){ + $x = $this->getVarInt(); + $y = $this->getUnsignedVarInt(); + $z = $this->getVarInt(); + } + + public function putBlockCoords($x, $y, $z){ + $this->putVarInt($x); + $this->putUnsignedVarInt($y); + $this->putVarInt($z); + } + + public function getVector3f(&$x, &$y, &$z){ + $x = $this->getLFloat(); + $y = $this->getLFloat(); + $z = $this->getLFloat(); + } + + public function putVector3f($x, $y, $z){ + $this->putLFloat($x); + $this->putLFloat($y); + $this->putLFloat($z); + } + public function feof(){ return !isset($this->buffer{$this->offset}); } -} \ No newline at end of file +} diff --git a/src/devmine/utilities/main/BlockIterator.php b/src/devmine/utilities/main/BlockIterator.php index ffbeadd..9e2bfa6 100644 --- a/src/devmine/utilities/main/BlockIterator.php +++ b/src/devmine/utilities/main/BlockIterator.php @@ -5,7 +5,7 @@ namespace devmine\utilities\main; use devmine\inventory\blocks\Block; -use devmine\levels\Level; +use devmine\worlds\Level; use devmine\server\calculations\Vector3; /** diff --git a/src/devmine/utilities/main/Cache.php b/src/devmine/utilities/main/Cache.php deleted file mode 100644 index c5042fc..0000000 --- a/src/devmine/utilities/main/Cache.php +++ /dev/null @@ -1,69 +0,0 @@ - $data){ - if($data[1] < $time){ - unset(self::$cached[$index]); - } - } - } - -} \ No newline at end of file diff --git a/src/devmine/utilities/main/Color.php b/src/devmine/utilities/main/Color.php index bc11745..5931423 100644 --- a/src/devmine/utilities/main/Color.php +++ b/src/devmine/utilities/main/Color.php @@ -1,6 +1,23 @@ config = []; $this->nestedCache = []; $this->correct = false; - $this->load($this->file); $this->load($this->file, $this->type); } @@ -193,7 +192,7 @@ public function save($async = false){ }catch(\Throwable $e){ $logger = Server::getInstance()->getLogger(); $logger->critical("Could not save Config " . $this->file . ": " . $e->getMessage()); - if(\devmine\DEBUG > 1 and $logger instanceof MainLogger){ + if(\DevMine\DEBUG > 1 and $logger instanceof MainLogger){ $logger->logException($e); } } @@ -304,46 +303,6 @@ public function get($k, $default = false){ return ($this->correct and isset($this->config[$k])) ? $this->config[$k] : $default; } - /** - * @param string $path - * - * @deprecated - * - * @return mixed - */ - public function getPath($path){ - $currPath =& $this->config; - foreach(explode(".", $path) as $component){ - if(isset($currPath[$component])){ - $currPath =& $currPath[$component]; - }else{ - $currPath = null; - } - } - - return $currPath; - } - - /** - * - * @deprecated - * - * @param string $path - * @param mixed $value - */ - public function setPath($path, $value){ - $currPath =& $this->config; - $components = explode(".", $path); - $final = array_pop($components); - foreach($components as $component){ - if(!isset($currPath[$component])){ - $currPath[$component] = []; - } - $currPath =& $currPath[$component]; - } - $currPath[$final] = $value; - } - /** * @param string $k key to be set * @param mixed $v value to set key diff --git a/src/devmine/utilities/main/MainLogger.php b/src/devmine/utilities/main/MainLogger.php index 6436ee6..24bd5ac 100644 --- a/src/devmine/utilities/main/MainLogger.php +++ b/src/devmine/utilities/main/MainLogger.php @@ -5,8 +5,8 @@ namespace devmine\utilities\main; use LogLevel; -use devmine\Thread; -use devmine\Worker; +use devmine\server\Thread; +use devmine\server\Worker; class MainLogger extends \AttachableThreadedLogger{ protected $logFile; @@ -20,7 +20,7 @@ class MainLogger extends \AttachableThreadedLogger{ private $consoleCallback; /** Extra Settings */ - protected $write = true; + protected $write = false; public $shouldSendMsg = ""; public $shouldRecordMsg = false; @@ -84,7 +84,7 @@ public function warning($message, $name = "WARNING"){ } public function notice($message, $name = "NOTICE"){ - $this->send($message, \LogLevel::NOTICE, $name, TextFormat::AQUA); + $this->send(TextFormat::BOLD . $message, \LogLevel::NOTICE, $name, TextFormat::GOLD); } public function info($message, $name = "INFO"){ @@ -141,6 +141,11 @@ public function logException(\Throwable $e, $trace = null){ if(($pos = strpos($errstr, "\n")) !== false){ $errstr = substr($errstr, 0, $pos); } + $errfile = \DevMine\cleanPath($errfile); + $this->log($type, get_class($e) . ": \"$errstr\" ($errno) in \"$errfile\" at line $errline"); + foreach(@\DevMine\getTrace(1, $trace) as $i => $line){ + $this->debug($line); + } } public function log($level, $message){ @@ -196,7 +201,7 @@ protected function send($message, $level, $prefix, $color){ } } - $message = TextFormat::toANSI(TextFormat::AQUA . "[" . date("H:i:s", $now) . "] " . TextFormat::RESET . $color . "[" . $threadName . "/" . $prefix . "]:" . " " . $message . TextFormat::RESET); + $message = TextFormat::toANSI(TextFormat::BOLD . TextFormat::GREEN . "[DevMine] " . TextFormat::RESET . TextFormat::AQUA . "[" . date("H:i:s", $now) . "] " . $color . $prefix . "> " . $message . TextFormat::RESET); //$message = TextFormat::toANSI(TextFormat::AQUA . "[" . date("H:i:s") . "] ". TextFormat::RESET . $color ."<".$prefix . ">" . " " . $message . TextFormat::RESET); $cleanMessage = TextFormat::clean($message); @@ -258,24 +263,23 @@ protected function send($message, $level, $prefix, $color){ public function run(){ $this->shutdown = false; - if($this->write){ - //$this->logResource = file_put_contents($this->logFile, "a+b", FILE_APPEND); - - while($this->shutdown === false){ - if(!$this->write) break; - $this->synchronized(function(){ - while($this->logStream->count() > 0){ - $chunk = $this->logStream->shift(); + while($this->shutdown === false){ + $this->synchronized(function(){ + while($this->logStream->count() > 0){ + $chunk = $this->logStream->shift(); + if($this->write){ $this->logResource = file_put_contents($this->logFile, $chunk, FILE_APPEND); } + } - $this->wait(200000); - }); - } + $this->wait(200000); + }); + } - if($this->logStream->count() > 0){ - while($this->logStream->count() > 0){ - $chunk = $this->logStream->shift(); + if($this->logStream->count() > 0){ + while($this->logStream->count() > 0){ + $chunk = $this->logStream->shift(); + if($this->write){ $this->logResource = file_put_contents($this->logFile, $chunk, FILE_APPEND); } } diff --git a/src/devmine/utilities/main/MonkeyPatch.php b/src/devmine/utilities/main/MonkeyPatch.php deleted file mode 100644 index 3ca3d03..0000000 --- a/src/devmine/utilities/main/MonkeyPatch.php +++ /dev/null @@ -1,11 +0,0 @@ -seed = crc32(pack("N", $seed)); + $this->seed = $seed; + $this->x = self::X ^ $seed; + $this->y = self::Y ^ ($seed << 17) | (($seed >> 15) & 0x7fffffff) & 0xffffffff; + $this->z = self::Z ^ ($seed << 31) | (($seed >> 1) & 0x7fffffff) & 0xffffffff; + $this->w = self::W ^ ($seed << 18) | (($seed >> 14) & 0x7fffffff) & 0xffffffff; + } + public function getSeed(){ + return $this->seed; } /** @@ -45,13 +76,15 @@ public function nextInt(){ * @return int */ public function nextSignedInt(){ - $t = ((($this->seed * 65535) + 31337) >> 8) + 1337; - if(PHP_INT_SIZE === 8){ - $t = $t << 32 >> 32; - } - $this->seed ^= $t; + $t = ($this->x ^ ($this->x << 11)) & 0xffffffff; + + $this->x = $this->y; + $this->y = $this->z; + $this->z = $this->w; + $this->w = ($this->w ^ (($this->w >> 19) & 0x7fffffff) + ^ ($t ^ (($t >> 8) & 0x7fffffff))) & 0xffffffff; - return $t; + return $this->w; } /** diff --git a/src/devmine/utilities/main/Range.php b/src/devmine/utilities/main/Range.php index e835aa3..529d6cc 100644 --- a/src/devmine/utilities/main/Range.php +++ b/src/devmine/utilities/main/Range.php @@ -1,6 +1,23 @@ synchronized(function(){ $this->wait($this->time * 1000000); }); if(time() - $start >= $this->time){ echo "\nTook too long to stop, server was killed forcefully!\n"; - @\devmine\kill(getmypid()); + @\DevMine\kill(getmypid()); } } diff --git a/src/devmine/utilities/main/Utils.php b/src/devmine/utilities/main/Utils.php index ffb844e..a5388d8 100644 --- a/src/devmine/utilities/main/Utils.php +++ b/src/devmine/utilities/main/Utils.php @@ -6,7 +6,7 @@ * Various Utilities used around the code */ namespace devmine\utilities\main; -use devmine\ThreadManager; +use devmine\server\ThreadManager; /** * Big collection of functions @@ -32,34 +32,6 @@ public static function getCallableIdentifier(callable $variable){ } } - /** - * @deprecated - */ - public static function randomUUID(){ - return Utils::toUUID(Binary::writeInt(time()) . Binary::writeShort(getmypid()) . Binary::writeShort(getmyuid()) . Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)) . Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)), 2); - } - - /** - * @deprecated - */ - public static function dataToUUID(...$params){ - return Utils::toUUID(hash("md5", implode($params), true), 3); - } - - /** - * @deprecated - */ - public static function toUUID($data, $version = 2, $fixed = "8"){ - if(strlen($data) !== 16){ - throw new \InvalidArgumentException("Data must be 16 bytes"); - } - - $hex = bin2hex($data); - - //xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx 8-4-4-12 - return substr($hex, 0, 8) . "-" . substr($hex, 8, 4) . "-" . hexdec($version) . substr($hex, 13, 3) . "-" . $fixed{0} . substr($hex, 17, 3) . "-" . substr($hex, 20, 12); - } - /** * Gets this machine / server instance unique ID * Returns a hash, the first 32 characters (or 16 if raw) @@ -142,9 +114,9 @@ public static function getIP($force = false){ }elseif(Utils::$ip !== false and $force !== true){ return Utils::$ip; } - $ip = trim(strip_tags(Utils::getURL("http://checkip.dyndns.org/"))); - if(preg_match('#Current IP Address\: ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){ - Utils::$ip = $matches[1]; + $ip = trim(strip_tags(Utils::getURL("https://api.ipify.org"))); + if($ip){ + Utils::$ip = $ip; }else{ $ip = Utils::getURL("http://www.checkip.org/"); if(preg_match('#">([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){ @@ -345,6 +317,7 @@ public static function printable($str){ /** * This function tries to get all the entropy available in PHP, and distills it to get a good RNG. * + * This function simply forwards to the PHP random_bytes function. * * @param int $length default 16, Number of bytes to generate * @param bool $secure default true, Generate secure distilled bytes, slower @@ -353,109 +326,16 @@ public static function printable($str){ * @param int &$rounds Will be set to the number of rounds taken * @param int &$drop Will be set to the amount of dropped bytes * + * @deprecated prefer PHP 7 random_bytes() * @return string */ public static function getRandomBytes($length = 16, $secure = true, $raw = true, $startEntropy = "", &$rounds = 0, &$drop = 0){ - static $lastRandom = ""; - $output = ""; - $length = abs((int) $length); - $secureValue = ""; - $rounds = 0; - $drop = 0; - while(!isset($output{$length - 1})){ - //some entropy, but works ^^ - $weakEntropy = [ - is_array($startEntropy) ? implode($startEntropy) : $startEntropy, - __DIR__, - PHP_OS, - microtime(), - (string) lcg_value(), - (string) PHP_MAXPATHLEN, - PHP_SAPI, - (string) PHP_INT_MAX . "." . PHP_INT_SIZE, - serialize($_SERVER), - get_current_user(), - (string) memory_get_usage() . "." . memory_get_peak_usage(), - php_uname(), - phpversion(), - zend_version(), - (string) getmypid(), - (string) getmyuid(), - (string) mt_rand(), - (string) getmyinode(), - (string) getmygid(), - (string) rand(), - function_exists("zend_thread_id") ? ((string) zend_thread_id()) : microtime(), - function_exists("getrusage") ? implode(getrusage()) : microtime(), - function_exists("sys_getloadavg") ? implode(sys_getloadavg()) : microtime(), - serialize(get_loaded_extensions()), - sys_get_temp_dir(), - (string) disk_free_space("."), - (string) disk_total_space("."), - uniqid(microtime(), true), - file_exists("/proc/cpuinfo") ? file_get_contents("/proc/cpuinfo") : microtime(), - ]; - - shuffle($weakEntropy); - $value = hash("sha512", implode($weakEntropy), true); - $lastRandom .= $value; - foreach($weakEntropy as $k => $c){ //mixing entropy values with XOR and hash randomness extractor - $value ^= hash("sha256", $c . microtime() . $k, true) . hash("sha256", mt_rand() . microtime() . $k . $c, true); - $value ^= hash("sha512", ((string) lcg_value()) . $c . microtime() . $k, true); - } - unset($weakEntropy); - - if($secure === true){ - - if(file_exists("/dev/urandom")){ - $fp = fopen("/dev/urandom", "rb"); - $systemRandom = fread($fp, 64); - fclose($fp); - }else{ - $systemRandom = str_repeat("\x00", 64); - } - - $strongEntropyValues = [ - is_array($startEntropy) ? hash("sha512", $startEntropy[($rounds + $drop) % count($startEntropy)], true) : hash("sha512", $startEntropy, true), //Get a random index of the startEntropy, or just read it - $systemRandom, - function_exists("openssl_random_pseudo_bytes") ? openssl_random_pseudo_bytes(64) : str_repeat("\x00", 64), - function_exists("mcrypt_create_iv") ? mcrypt_create_iv(64, MCRYPT_DEV_URANDOM) : str_repeat("\x00", 64), - $value, - ]; - $strongEntropy = array_pop($strongEntropyValues); - foreach($strongEntropyValues as $value){ - $strongEntropy = $strongEntropy ^ $value; - } - $value = ""; - //Von Neumann randomness extractor, increases entropy - $bitcnt = 0; - for($j = 0; $j < 64; ++$j){ - $a = ord($strongEntropy{$j}); - for($i = 0; $i < 8; $i += 2){ - $b = ($a & (1 << $i)) > 0 ? 1 : 0; - if($b != (($a & (1 << ($i + 1))) > 0 ? 1 : 0)){ - $secureValue |= $b << $bitcnt; - if($bitcnt == 7){ - $value .= chr($secureValue); - $secureValue = 0; - $bitcnt = 0; - }else{ - ++$bitcnt; - } - ++$drop; - }else{ - $drop += 2; - } - } - } - } - $output .= substr($value, 0, min($length - strlen($output), $length)); - unset($value); - ++$rounds; + $raw_output = random_bytes($length); + if ($raw) { + return $raw_output; + } else { + return bin2hex($raw_output); } - $lastRandom = hash("sha512", $lastRandom, true); - - return $raw === false ? bin2hex($output) : $output; } /* @@ -485,7 +365,7 @@ public static function getURL($page, $timeout = 10, array $extraHeaders = []){ } $ch = curl_init($page); - curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 devmine-MP"], $extraHeaders)); + curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 DevMine-MP"], $extraHeaders)); curl_setopt($ch, CURLOPT_AUTOREFERER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); @@ -525,7 +405,7 @@ public static function postURL($page, $args, $timeout = 10, array $extraHeaders curl_setopt($ch, CURLOPT_POSTFIELDS, $args); curl_setopt($ch, CURLOPT_AUTOREFERER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 devmine-MP"], $extraHeaders)); + curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 DevMine-MP"], $extraHeaders)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (int) $timeout); curl_setopt($ch, CURLOPT_TIMEOUT, (int) $timeout); diff --git a/src/devmine/utilities/main/VectorIterator.php b/src/devmine/utilities/main/VectorIterator.php index e59ed7f..bf57846 100644 --- a/src/devmine/utilities/main/VectorIterator.php +++ b/src/devmine/utilities/main/VectorIterator.php @@ -5,8 +5,8 @@ namespace devmine\utilities\main; use devmine\inventory\blocks\Block; -use devmine\levels\ChunkManager; -use devmine\levels\Level; +use devmine\worlds\ChunkManager; +use devmine\worlds\Level; use devmine\server\calculations\Vector3; /** @@ -41,6 +41,11 @@ class VectorIterator implements \Iterator{ private $thirdFace; public function __construct(ChunkManager $level, Vector3 $from, Vector3 $to){ + if($from->equals($to)){ + $this->end = true; + $this->currentBlock = -1; + return; + } $direction = $to->subtract($from)->normalize(); $maxDistance = $from->distance($to); $this->level = $level; diff --git a/src/devmine/utilities/main/VersionString.php b/src/devmine/utilities/main/VersionString.php index 433dc03..ce001e5 100644 --- a/src/devmine/utilities/main/VersionString.php +++ b/src/devmine/utilities/main/VersionString.php @@ -6,7 +6,7 @@ /** - * Manages devmine-MP version strings, and compares them + * Manages DevMine-MP version strings, and compares them */ class VersionString{ private $major; @@ -14,7 +14,7 @@ class VersionString{ private $minor; private $development = false; - public function __construct($version = \devmine\VERSION){ + public function __construct($version = \DevMine\VERSION){ if(is_int($version)){ $this->minor = $version & 0x1F; $this->major = ($version >> 5) & 0x0F; diff --git a/src/devmine/levels/ChunkLoader.php b/src/devmine/worlds/ChunkLoader.php similarity index 81% rename from src/devmine/levels/ChunkLoader.php rename to src/devmine/worlds/ChunkLoader.php index f18a443..8fc624c 100644 --- a/src/devmine/levels/ChunkLoader.php +++ b/src/devmine/worlds/ChunkLoader.php @@ -2,10 +2,10 @@ -namespace devmine\levels; +namespace devmine\worlds; use devmine\inventory\blocks\Block; -use devmine\levels\format\FullChunk; +use devmine\worlds\format\Chunk; use devmine\server\calculations\Vector3; /** @@ -58,32 +58,32 @@ public function getLevel(); /** * This method will be called when a Chunk is replaced by a new one * - * @param FullChunk $chunk + * @param Chunk $chunk */ - public function onChunkChanged(FullChunk $chunk); + public function onChunkChanged(Chunk $chunk); /** * This method will be called when a registered chunk is loaded * - * @param FullChunk $chunk + * @param Chunk $chunk */ - public function onChunkLoaded(FullChunk $chunk); + public function onChunkLoaded(Chunk $chunk); /** * This method will be called when a registered chunk is unloaded * - * @param FullChunk $chunk + * @param Chunk $chunk */ - public function onChunkUnloaded(FullChunk $chunk); + public function onChunkUnloaded(Chunk $chunk); /** * This method will be called when a registered chunk is populated * Usually it'll be sent with another call to onChunkChanged() * - * @param FullChunk $chunk + * @param Chunk $chunk */ - public function onChunkPopulated(FullChunk $chunk); + public function onChunkPopulated(Chunk $chunk); /** * This method will be called when a block changes in a registered chunk diff --git a/src/devmine/levels/ChunkManager.php b/src/devmine/worlds/ChunkManager.php similarity index 52% rename from src/devmine/levels/ChunkManager.php rename to src/devmine/worlds/ChunkManager.php index 34b31b3..a3f026f 100644 --- a/src/devmine/levels/ChunkManager.php +++ b/src/devmine/worlds/ChunkManager.php @@ -2,11 +2,11 @@ -declare(strict_types=1); +declare(strict_types = 1); -namespace devmine\levels; +namespace devmine\worlds; -use devmine\levels\format\FullChunk; +use devmine\worlds\format\Chunk; interface ChunkManager{ /** @@ -31,7 +31,7 @@ public function getBlockIdAt(int $x, int $y, int $z) : int; public function setBlockIdAt(int $x, int $y, int $z, int $id); /** - * Gets the raw block epilogos + * Gets the raw block metadata * * @param int $x * @param int $y @@ -42,7 +42,7 @@ public function setBlockIdAt(int $x, int $y, int $z, int $id); public function getBlockDataAt(int $x, int $y, int $z) : int; /** - * Sets the raw block epilogos. + * Sets the raw block metadata. * * @param int $x * @param int $y @@ -51,50 +51,20 @@ public function getBlockDataAt(int $x, int $y, int $z) : int; */ public function setBlockDataAt(int $x, int $y, int $z, int $data); - /** - * Gets the raw block light level - * - * @param int $x - * @param int $y - * @param int $z - * - * @return int 0-15 - */ - public function getBlockLightAt($x, $y, $z); - - /** - * Updates the light around the block - * - * @param $x - * @param $y - * @param $z - */ - public function updateBlockLight($x, $y, $z); - - /** - * Sets the raw block light level. - * - * @param int $x - * @param int $y - * @param int $z - * @param int $level 0-15 - */ - public function setBlockLightAt($x, $y, $z, $level); - /** * @param int $chunkX * @param int $chunkZ * - * @return FullChunk|null + * @return Chunk|null */ public function getChunk(int $chunkX, int $chunkZ); /** - * @param int $chunkX - * @param int $chunkZ - * @param FullChunk $chunk + * @param int $chunkX + * @param int $chunkZ + * @param Chunk $chunk */ - public function setChunk(int $chunkX, int $chunkZ, FullChunk $chunk = null); + public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null); /** * Gets the level seed diff --git a/src/devmine/levels/Explosion.php b/src/devmine/worlds/Explosion.php similarity index 89% rename from src/devmine/levels/Explosion.php rename to src/devmine/worlds/Explosion.php index 0c61392..9549a17 100644 --- a/src/devmine/levels/Explosion.php +++ b/src/devmine/worlds/Explosion.php @@ -2,27 +2,26 @@ -namespace devmine\levels; +namespace devmine\worlds; use devmine\inventory\blocks\Block; use devmine\creatures\entities\Entity; -use devmine\server\events\entity\EntityDamageByBlockEvent; -use devmine\server\events\entity\EntityDamageByEntityEvent; -use devmine\server\events\entity\EntityDamageEvent; -use devmine\server\events\entity\EntityExplodeEvent; -use devmine\server\events\block\BlockUpdateEvent; +use devmine\events\block\BlockUpdateEvent; +use devmine\events\entity\EntityDamageByBlockEvent; +use devmine\events\entity\EntityDamageByEntityEvent; +use devmine\events\entity\EntityDamageEvent; +use devmine\events\entity\EntityExplodeEvent; use devmine\inventory\items\Item; +use devmine\worlds\particle\HugeExplodeSeedParticle; use devmine\server\calculations\AxisAlignedBB; use devmine\server\calculations\Math; use devmine\server\calculations\Vector3; use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\CompoundTag; use devmine\creatures\player\tag\DoubleTag; -use devmine\creatures\player\tag\ListTag; use devmine\creatures\player\tag\FloatTag; -use devmine\server\network\Network; +use devmine\creatures\player\tag\ListTag; use devmine\server\network\protocol\ExplodePacket; - use devmine\utilities\main\Random; class Explosion{ @@ -38,26 +37,12 @@ class Explosion{ public $stepLen = 0.3; /** @var Entity|Block */ private $what; - private $dropItem; - public function __construct(Position $center, $size, $what = null, bool $dropItem = true){ + public function __construct(Position $center, $size, $what = null){ $this->level = $center->getLevel(); $this->source = $center; $this->size = max($size, 0); $this->what = $what; - $this->dropItem = $dropItem; - } - - /** - * @deprecated - * @return bool - */ - public function explode(){ - if($this->explodeA()){ - return $this->explodeB(); - } - - return false; } /** @@ -89,7 +74,7 @@ public function explodeA(){ $vBlock->x = $pointerX >= $x ? $x : $x - 1; $vBlock->y = $pointerY >= $y ? $y : $y - 1; $vBlock->z = $pointerZ >= $z ? $z : $z - 1; - if($vBlock->y < 0 or $vBlock->y > 127){ + if($vBlock->y < 0 or $vBlock->y >= Level::Y_MAX){ break; } $block = $this->level->getBlock($vBlock); @@ -160,9 +145,7 @@ public function explodeB(){ $ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_BLOCK_EXPLOSION, $damage); } - if($entity->attack($ev->getFinalDamage(), $ev) === true){ - $ev->useArmors(); - } + $entity->attack($ev->getFinalDamage(), $ev); $entity->setMotion($motion->multiply($impact)); } } @@ -191,7 +174,7 @@ public function explodeB(){ "Fuse" => new ByteTag("Fuse", mt_rand(10, 30)) ])); $tnt->spawnToAll(); - }elseif($this->dropItem and mt_rand(0, 100) < $yield){ + }elseif(mt_rand(0, 100) < $yield){ foreach($block->getDrops($air) as $drop){ $this->level->dropItem($block->add(0.5, 0.5, 0.5), Item::get(...$drop)); } @@ -222,6 +205,8 @@ public function explodeB(){ $pk->records = $send; $this->level->addChunkPacket($source->x >> 4, $source->z >> 4, $pk); + $this->level->addParticle(new HugeExplodeSeedParticle($source)); + return true; } } diff --git a/src/devmine/levels/Level.php b/src/devmine/worlds/Level.php similarity index 73% rename from src/devmine/levels/Level.php rename to src/devmine/worlds/Level.php index 9a526ec..c0b9c5c 100644 --- a/src/devmine/levels/Level.php +++ b/src/devmine/worlds/Level.php @@ -2,10 +2,12 @@ +declare(strict_types = 1); + /** * All Level related classes are here, like Generators, Populators, Noise, ... */ -namespace devmine\levels; +namespace devmine\worlds; use devmine\inventory\blocks\Air; use devmine\inventory\blocks\Beetroot; @@ -14,11 +16,11 @@ use devmine\inventory\blocks\Cactus; use devmine\inventory\blocks\Carrot; use devmine\inventory\blocks\Farmland; +use devmine\inventory\blocks\Fire; use devmine\inventory\blocks\Grass; use devmine\inventory\blocks\Ice; use devmine\inventory\blocks\Leaves; use devmine\inventory\blocks\Leaves2; -use devmine\inventory\blocks\NetherWart; use devmine\inventory\blocks\MelonStem; use devmine\inventory\blocks\Mycelium; use devmine\inventory\blocks\Potato; @@ -28,53 +30,50 @@ use devmine\inventory\blocks\SnowLayer; use devmine\inventory\blocks\Sugarcane; use devmine\inventory\blocks\Wheat; -use devmine\inventory\blocks\CocoaBlock; use devmine\creatures\entities\Arrow; +use devmine\creatures\entities\Effect; use devmine\creatures\entities\Entity; use devmine\creatures\entities\Item as DroppedItem; -use devmine\server\events\block\BlockBreakEvent; -use devmine\server\events\block\BlockPlaceEvent; -use devmine\server\events\block\BlockUpdateEvent; -use devmine\server\events\level\ChunkLoadEvent; -use devmine\server\events\level\ChunkPopulateEvent; -use devmine\server\events\level\ChunkUnloadEvent; -use devmine\server\events\level\LevelSaveEvent; -use devmine\server\events\level\LevelUnloadEvent; -use devmine\server\events\level\SpawnChangeEvent; -use devmine\server\events\LevelTimings; -use devmine\server\events\player\PlayerInteractEvent; -use devmine\server\events\Timings; +use devmine\events\block\BlockBreakEvent; +use devmine\events\block\BlockPlaceEvent; +use devmine\events\block\BlockUpdateEvent; +use devmine\events\level\ChunkLoadEvent; +use devmine\events\level\ChunkPopulateEvent; +use devmine\events\level\ChunkUnloadEvent; +use devmine\events\level\LevelSaveEvent; +use devmine\events\level\LevelUnloadEvent; +use devmine\events\level\SpawnChangeEvent; +use devmine\events\LevelTimings; +use devmine\events\player\PlayerInteractEvent; +use devmine\events\Timings; use devmine\inventory\layout\InventoryHolder; use devmine\inventory\items\Item; -use devmine\inventory\items\enchantment\enchantment; -use devmine\levels\format\Chunk; -use devmine\levels\format\FullChunk; -use devmine\levels\format\generic\BaseLevelProvider; -use devmine\levels\format\generic\EmptyChunkSection; -use devmine\levels\format\LevelProvider; -use devmine\levels\generator\GenerationTask; -use devmine\levels\generator\Generator; -use devmine\levels\generator\GeneratorRegisterTask; -use devmine\levels\generator\GeneratorUnregisterTask; -use devmine\levels\generator\LightPopulationTask; -use devmine\levels\generator\PopulationTask; +use devmine\worlds\format\Chunk; +use devmine\worlds\format\generic\BaseLevelProvider; +use devmine\worlds\format\LevelProvider; +use devmine\worlds\generator\GenerationTask; +use devmine\worlds\generator\Generator; +use devmine\worlds\generator\GeneratorRegisterTask; +use devmine\worlds\generator\GeneratorUnregisterTask; +use devmine\worlds\generator\LightPopulationTask; +use devmine\worlds\generator\PopulationTask; +use devmine\worlds\particle\DestroyBlockParticle; +use devmine\worlds\particle\Particle; +use devmine\worlds\sound\Sound; use devmine\server\calculations\AxisAlignedBB; use devmine\server\calculations\Math; use devmine\server\calculations\Vector2; use devmine\server\calculations\Vector3; -use devmine\server\epilogos\BlockepilogosStore; -use devmine\server\epilogos\epilogosble; -use devmine\server\epilogos\epilogosValue; -use devmine\creatures\player\NBT; - +use devmine\server\meta\BlockMetadataStore; +use devmine\server\meta\Metadatable; +use devmine\server\meta\MetadataValue; use devmine\creatures\player\tag\CompoundTag; use devmine\creatures\player\tag\DoubleTag; -use devmine\creatures\player\tag\ListTag; use devmine\creatures\player\tag\FloatTag; -use devmine\creatures\player\tag\IntTag; +use devmine\creatures\player\tag\ListTag; use devmine\creatures\player\tag\ShortTag; use devmine\creatures\player\tag\StringTag; -use devmine\creatures\player\tag\LongTag; +use devmine\server\network\protocol\BatchPacket; use devmine\server\network\protocol\DataPacket; use devmine\server\network\protocol\FullChunkDataPacket; use devmine\server\network\protocol\LevelEventPacket; @@ -82,36 +81,29 @@ use devmine\server\network\protocol\SetEntityMotionPacket; use devmine\server\network\protocol\SetTimePacket; use devmine\server\network\protocol\UpdateBlockPacket; -use devmine\server\network\protocol\AddEntityPacket; -use devmine\Player; -use devmine\pluginfeatures\Plugin; - -use devmine\Server; +use devmine\creatures\player; +use devmine\consumer\plugin\Plugin; +use devmine\server\server; use devmine\inventory\solidentity\Chest; -use devmine\inventory\solidentity\solidentity; +use devmine\inventory\solidentity\Tile; +use devmine\utilities\main\Binary; use devmine\utilities\main\LevelException; -use devmine\utilities\main\MainLogger; use devmine\utilities\main\Random; use devmine\utilities\main\ReversePriorityQueue; -use devmine\levels\particle\Particle; -use devmine\levels\sound\Sound; -use devmine\levels\particle\DestroyBlockParticle; - -use devmine\levels\generator\biome\Biome; - -use devmine\creatures\entities\Lightning; +use devmine\inventory\items\enchantment\enchantment; +use devmine\creatures\player\NBT; use devmine\creatures\entities\XPOrb; -use devmine\levels\weather\Weather; -use devmine\levels\weather\WeatherManager; #include -class Level implements ChunkManager, epilogosble{ +class Level implements ChunkManager, Metadatable{ private static $levelIdCounter = 1; private static $chunkLoaderCounter = 1; public static $COMPRESSION_LEVEL = 8; + const Y_MASK = 0xFF; + const Y_MAX = 0x100; //256 const BLOCK_UPDATE_NORMAL = 1; const BLOCK_UPDATE_RANDOM = 2; @@ -126,11 +118,8 @@ class Level implements ChunkManager, epilogosble{ const TIME_FULL = 24000; - const DIMENSION_NORMAL = 0; - const DIMENSION_NETHER = 1; - - /** @var solidentity[] */ - private $solidentities = []; + /** @var Tile[] */ + private $tiles = []; private $motionToSend = []; private $moveToSend = []; @@ -143,8 +132,8 @@ class Level implements ChunkManager, epilogosble{ /** @var Entity[] */ public $updateEntities = []; - /** @var solidentity[] */ - public $updatesolidentities = []; + /** @var Tile[] */ + public $updateTiles = []; private $blockCache = []; @@ -153,8 +142,6 @@ class Level implements ChunkManager, epilogosble{ private $cacheChunks = false; - private $sendTimeTicker = 0; - /** @var Server */ private $server; @@ -184,7 +171,7 @@ class Level implements ChunkManager, epilogosble{ private $folderName; - /** @var FullChunk[]|Chunk[] */ + /** @var Chunk[] */ private $chunks = []; /** @var Vector3[][] */ @@ -206,11 +193,8 @@ class Level implements ChunkManager, epilogosble{ private $autoSave = true; - /** @var BlockepilogosStore */ - private $blockepilogos; - - private $useSections; - private $blockOrder; + /** @var BlockMetadataStore */ + private $blockMetadata; /** @var Position */ private $temporalPosition; @@ -231,7 +215,6 @@ class Level implements ChunkManager, epilogosble{ Block::SAPLING => Sapling::class, Block::LEAVES => Leaves::class, Block::WHEAT_BLOCK => Wheat::class, - Block::COCOA_BLOCK => CocoaBlock::class, Block::FARMLAND => Farmland::class, Block::SNOW_LAYER => SnowLayer::class, Block::ICE => Ice::class, @@ -240,7 +223,6 @@ class Level implements ChunkManager, epilogosble{ Block::RED_MUSHROOM => RedMushroom::class, Block::BROWN_MUSHROOM => BrownMushroom::class, Block::PUMPKIN_STEM => PumpkinStem::class, - Block::NETHER_WART_BLOCK => NetherWart::class, Block::MELON_STEM => MelonStem::class, //Block::VINE => true, Block::MYCELIUM => Mycelium::class, @@ -248,7 +230,7 @@ class Level implements ChunkManager, epilogosble{ Block::CARROT_BLOCK => Carrot::class, Block::POTATO_BLOCK => Potato::class, Block::LEAVES2 => Leaves2::class, - + Block::FIRE => Fire::class, Block::BEETROOT_BLOCK => Beetroot::class, ]; @@ -264,64 +246,18 @@ class Level implements ChunkManager, epilogosble{ /** @var Generator */ private $generatorInstance; - /** @var Weather */ - private $weather; - - private $blockTempData = []; - - private $dimension = self::DIMENSION_NORMAL; - - /** - * This method is internal use only. Do not use this in plugins - * - * @param Vector3 $pos - * @param $data - */ - public function setBlockTempData(Vector3 $pos, $data = null){ - if($data == null and isset($this->blockTempData[self::blockHash($pos->x, $pos->y, $pos->z)])){ - unset($this->blockTempData[self::blockHash($pos->x, $pos->y, $pos->z)]); - }else{ - $this->blockTempData[self::blockHash($pos->x, $pos->y, $pos->z)] = $data; - } - } - - /** - * This method is internal use only. Do not use this in plugins - * - * @param Vector3 $pos - * @return int - */ - public function getBlockTempData(Vector3 $pos){ - if(isset($this->blockTempData[self::blockHash($pos->x, $pos->y, $pos->z)])){ - return $this->blockTempData[self::blockHash($pos->x, $pos->y, $pos->z)]; - } - return 0; - } - - /** - * Returns the chunk unique hash/key - * - * @param int $x - * @param int $z - * - * @return string - */ - public static function chunkHash($x, $z){ + public static function chunkHash(int $x, int $z){ return PHP_INT_SIZE === 8 ? (($x & 0xFFFFFFFF) << 32) | ($z & 0xFFFFFFFF) : $x . ":" . $z; } - public static function blockHash($x, $y, $z){ - return PHP_INT_SIZE === 8 ? (($x & 0xFFFFFFF) << 35) | (($y & 0x7f) << 28) | ($z & 0xFFFFFFF) : $x . ":" . $y . ":" . $z; - } - - public static function chunkBlockHash($x, $y, $z){ - return ($x << 11) | ($z << 7) | $y; + public static function blockHash(int $x, int $y, int $z){ + return PHP_INT_SIZE === 8 ? (($x & 0xFFFFFFF) << 36) | (($y & Level::Y_MASK) << 28) | ($z & 0xFFFFFFF) : $x . ":" . $y . ":" . $z; } public static function getBlockXYZ($hash, &$x, &$y, &$z){ if(PHP_INT_SIZE === 8){ - $x = ($hash >> 35) << 36 >> 36; - $y = (($hash >> 28) & 0x7f);// << 57 >> 57; //it's always positive + $x = $hash >> 36; + $y = ($hash >> 28) & Level::Y_MASK; //it's always positive $z = ($hash & 0xFFFFFFF) << 36 >> 36; }else{ $hash = explode(":", $hash); @@ -331,9 +267,14 @@ public static function getBlockXYZ($hash, &$x, &$y, &$z){ } } + /** + * @param string|int $hash + * @param int|null $x + * @param int|null $z + */ public static function getXZ($hash, &$x, &$z){ if(PHP_INT_SIZE === 8){ - $x = ($hash >> 32) << 32 >> 32; + $x = $hash >> 32; $z = ($hash & 0xFFFFFFFF) << 32 >> 32; }else{ $hash = explode(":", $hash); @@ -342,7 +283,7 @@ public static function getXZ($hash, &$x, &$z){ } } - public static function generateChunkLoaderId(ChunkLoader $loader){ + public static function generateChunkLoaderId(ChunkLoader $loader) : int{ if($loader->getLoaderId() === 0 or $loader->getLoaderId() === null or $loader->getLoaderId() === null){ return self::$chunkLoaderCounter++; }else{ @@ -358,12 +299,12 @@ public static function generateChunkLoaderId(ChunkLoader $loader){ * @param string $path * @param string $provider Class that extends LevelProvider * - * @throws \Throwable + * @throws \Exception */ - public function __construct(Server $server, $name, $path, $provider){ + public function __construct(Server $server, string $name, string $path, string $provider){ $this->blockStates = Block::$fullList; $this->levelId = static::$levelIdCounter++; - $this->blockepilogos = new BlockepilogosStore($this); + $this->blockMetadata = new BlockMetadataStore($this); $this->server = $server; $this->autoSave = $server->getAutoSave(); @@ -374,12 +315,9 @@ public function __construct(Server $server, $name, $path, $provider){ }else{ throw new LevelException("Provider is not a subclass of LevelProvider"); } - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.level.preparing", [$this->provider->getName()])); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.level.preparing", [$this->provider->getName()])); $this->generator = Generator::getGenerator($this->provider->getGenerator()); - $this->blockOrder = $provider::getProviderOrder(); - $this->useSections = $provider::usesChunkSection(); - $this->folderName = $name; $this->updateQueue = new ReversePriorityQueue(); $this->updateQueue->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); @@ -397,41 +335,18 @@ public function __construct(Server $server, $name, $path, $provider){ $this->temporalPosition = new Position(0, 0, 0, $this); $this->temporalVector = new Vector3(0, 0, 0); $this->tickRate = 1; - - $this->weather = new Weather($this, 0); - if($this->server->netherEnabled and $this->server->netherName == $this->folderName) $this->setDimension(self::DIMENSION_NETHER); - else $this->setDimension(self::DIMENSION_NORMAL); - if($this->server->weatherEnabled and $this->getDimension() == self::DIMENSION_NORMAL){ - WeatherManager::registerLevel($this); - $this->weather->setCanCalculate(true); - }else $this->weather->setCanCalculate(false); - } - - public function setDimension(int $dimension){ - $this->dimension = $dimension; - } - - public function getDimension() : int{ - return $this->dimension; } - /** - * @return Weather - */ - public function getWeather(){ - return $this->weather; - } - - public function getTickRate(){ + public function getTickRate() : int{ return $this->tickRate; } - public function getTickRateTime(){ + public function getTickRateTime() : float{ return $this->tickRateTime; } - public function setTickRate($tickRate){ - $this->tickRate = (int) $tickRate; + public function setTickRate(int $tickRate){ + $this->tickRate = $tickRate; } public function initLevel(){ @@ -442,13 +357,6 @@ public function initLevel(){ $this->registerGenerator(); } - public function getWaterHeight() : int{ - if($this->generatorInstance instanceof Generator){ - return $this->generatorInstance->getWaterHeight(); - } - return 0; - } - public function registerGenerator(){ $size = $this->server->getScheduler()->getAsyncTaskPoolSize(); for($i = 0; $i < $size; ++$i){ @@ -463,33 +371,22 @@ public function unregisterGenerator(){ } } - /** - * @return BlockepilogosStore - */ - public function getBlockepilogos(){ - return $this->blockepilogos; + public function getBlockMetadata() : BlockMetadataStore{ + return $this->blockMetadata; } - /** - * @return Server - */ - public function getServer(){ + public function getServer() : Server{ return $this->server; } - /** - * @return LevelProvider - */ - final public function getProvider(){ + final public function getProvider() : LevelProvider{ return $this->provider; } /** * Returns the unique level identifier - * - * @return int */ - final public function getId(){ + final public function getId() : int{ return $this->levelId; } @@ -507,7 +404,7 @@ public function close(){ $this->provider->close(); $this->provider = null; - $this->blockepilogos = null; + $this->blockMetadata = null; $this->blockCache = []; $this->temporalPosition = null; } @@ -528,7 +425,7 @@ public function addSound(Sound $sound, array $players = null){ }else{ if($pk !== null){ if(!is_array($pk)){ - Server::broadcastPacket($players, $pk); + $this->server->broadcastPacket($players, $pk); }else{ $this->server->batchPackets($players, $pk, false); } @@ -552,7 +449,7 @@ public function addParticle(Particle $particle, array $players = null){ }else{ if($pk !== null){ if(!is_array($pk)){ - Server::broadcastPacket($players, $pk); + $this->server->broadcastPacket($players, $pk); }else{ $this->server->batchPackets($players, $pk, false); } @@ -560,17 +457,11 @@ public function addParticle(Particle $particle, array $players = null){ } } - /** - * @return bool - */ - public function getAutoSave(){ + public function getAutoSave() : bool{ return $this->autoSave; } - /** - * @param bool $value - */ - public function setAutoSave($value){ + public function setAutoSave(bool $value){ $this->autoSave = $value; } @@ -581,7 +472,7 @@ public function setAutoSave($value){ * * @return bool */ - public function unload($force = false){ + public function unload(bool $force = false) : bool{ $ev = new LevelUnloadEvent($this); @@ -595,7 +486,7 @@ public function unload($force = false){ return false; } - $this->server->getLogger()->info($this->server->getLanguage()->translateString("devmine.level.unloading", [$this->getName()])); + $this->server->getLogger()->info($this->server->getLanguage()->translateString("DevMine.level.unloading", [$this->getName()])); $defaultLevel = $this->server->getDefaultLevel(); foreach($this->getPlayers() as $player){ if($this === $defaultLevel or $defaultLevel === null){ @@ -609,20 +500,11 @@ public function unload($force = false){ $this->server->setDefaultLevel(null); } - if($this->weather != null) WeatherManager::unregisterLevel($this); - $this->close(); return true; } - /** - * @deprecated Use Level->getChunkPlayers($chunkX, $chunkZ) - */ - public function getUsingChunk($chunkX, $chunkZ){ - return $this->getChunkPlayers($chunkX, $chunkZ); - } - /** * Gets the players being used in a specific chunk * @@ -631,8 +513,8 @@ public function getUsingChunk($chunkX, $chunkZ){ * * @return Player[] */ - public function getChunkPlayers($chunkX, $chunkZ){ - return isset($this->playerLoaders[$index = Level::chunkHash($chunkX, $chunkZ)]) ? $this->playerLoaders[$index] : []; + public function getChunkPlayers(int $chunkX, int $chunkZ) : array{ + return $this->playerLoaders[Level::chunkHash($chunkX, $chunkZ)] ?? []; } /** @@ -643,11 +525,11 @@ public function getChunkPlayers($chunkX, $chunkZ){ * * @return ChunkLoader[] */ - public function getChunkLoaders($chunkX, $chunkZ){ - return isset($this->chunkLoaders[$index = Level::chunkHash($chunkX, $chunkZ)]) ? $this->chunkLoaders[$index] : []; + public function getChunkLoaders(int $chunkX, int $chunkZ) : array{ + return $this->chunkLoaders[Level::chunkHash($chunkX, $chunkZ)] ?? []; } - public function addChunkPacket($chunkX, $chunkZ, DataPacket $packet){ + public function addChunkPacket(int $chunkX, int $chunkZ, DataPacket $packet){ if(!isset($this->chunkPackets[$index = Level::chunkHash($chunkX, $chunkZ)])){ $this->chunkPackets[$index] = [$packet]; }else{ @@ -655,7 +537,7 @@ public function addChunkPacket($chunkX, $chunkZ, DataPacket $packet){ } } - public function registerChunkLoader(ChunkLoader $loader, $chunkX, $chunkZ, $autoLoad = true){ + public function registerChunkLoader(ChunkLoader $loader, int $chunkX, int $chunkZ, bool $autoLoad = true){ $hash = $loader->getLoaderId(); if(!isset($this->chunkLoaders[$index = Level::chunkHash($chunkX, $chunkZ)])){ @@ -684,7 +566,7 @@ public function registerChunkLoader(ChunkLoader $loader, $chunkX, $chunkZ, $auto } } - public function unregisterChunkLoader(ChunkLoader $loader, $chunkX, $chunkZ){ + public function unregisterChunkLoader(ChunkLoader $loader, int $chunkX, int $chunkZ){ if(isset($this->chunkLoaders[$index = Level::chunkHash($chunkX, $chunkZ)][$hash = $loader->getLoaderId()])){ unset($this->chunkLoaders[$index][$hash]); unset($this->playerLoaders[$index][$hash]); @@ -706,17 +588,10 @@ public function unregisterChunkLoader(ChunkLoader $loader, $chunkX, $chunkZ){ * Changes to this function won't be recorded on the version. */ public function checkTime(){ - if($this->stopTime == true){ + if($this->stopTime === true){ return; }else{ - $this->time += 1; - //The below code should not be necessary now that AIs for monsters which burn have been fixed - //Now can allow time to continue to day 2, day 3, day 4, etc. - /* - if($this->time > self::TIME_FULL){ - $this->time = 0; - } - */ + $this->time += $this->tickRate; } } @@ -729,7 +604,7 @@ public function sendTime(){ $pk->time = (int) $this->time; $pk->started = $this->stopTime == false; - Server::broadcastPacket($this->players, $pk); + $this->server->broadcastPacket($this->players, $pk); } /** @@ -738,26 +613,18 @@ public function sendTime(){ * * @param int $currentTick * - * @return bool */ - public function doTick($currentTick){ + public function doTick(int $currentTick){ $this->timings->doTick->startTiming(); $this->checkTime(); - if(++$this->sendTimeTicker === 280){ - $this->sendTime(); - $this->sendTimeTicker = 0; - } - - $this->weather->calcWeather($currentTick); - $this->unloadChunks(); //Do block updates $this->timings->doTickPending->startTiming(); - if($this->updateQueue->count() > 0 and $this->updateQueue->current()["priority"] <= $currentTick){ + while($this->updateQueue->count() > 0 and $this->updateQueue->current()["priority"] <= $currentTick){ $block = $this->getBlock($this->updateQueue->extract()["data"]); unset($this->updateQueueIndex[Level::blockHash($block->x, $block->y, $block->z)]); $block->onUpdate(self::BLOCK_UPDATE_SCHEDULED); @@ -775,22 +642,22 @@ public function doTick($currentTick){ Timings::$tickEntityTimer->stopTiming(); $this->timings->entityTick->stopTiming(); - $this->timings->solidentityEntityTick->startTiming(); - Timings::$ticksolidentityEntityTimer->startTiming(); - //Update solidentities that need update - if(count($this->updatesolidentities) > 0){ - foreach($this->updatesolidentities as $id => $solidentity){ - if($solidentity->onUpdate() !== true){ - unset($this->updatesolidentities[$id]); + $this->timings->tileEntityTick->startTiming(); + Timings::$tickTileEntityTimer->startTiming(); + //Update tiles that need update + if(count($this->updateTiles) > 0){ + foreach($this->updateTiles as $id => $tile){ + if($tile->onUpdate() !== true){ + unset($this->updateTiles[$id]); } } } - Timings::$ticksolidentityEntityTimer->stopTiming(); - $this->timings->solidentityEntityTick->stopTiming(); + Timings::$tickTileEntityTimer->stopTiming(); + $this->timings->tileEntityTick->stopTiming(); - $this->timings->doTicksolidentities->startTiming(); - if(($currentTick % 2) === 0) $this->tickChunks(); - $this->timings->doTicksolidentities->stopTiming(); + $this->timings->doTickTiles->startTiming(); + $this->tickChunks(); + $this->timings->doTickTiles->stopTiming(); if(count($this->changedBlocks) > 0){ if(count($this->players) > 0){ @@ -822,7 +689,7 @@ public function doTick($currentTick){ foreach($this->moveToSend as $index => $entry){ Level::getXZ($index, $chunkX, $chunkZ); - foreach($entry as $e) { + foreach($entry as $e){ $pk = new MoveEntityPacket(); $pk->eid = $e[0]; $pk->x = $e[1]; @@ -838,9 +705,14 @@ public function doTick($currentTick){ foreach($this->motionToSend as $index => $entry){ Level::getXZ($index, $chunkX, $chunkZ); - $pk = new SetEntityMotionPacket(); - $pk->entities = $entry; - $this->addChunkPacket($chunkX, $chunkZ, $pk); + foreach($entry as $entity){ + $pk = new SetEntityMotionPacket(); + $pk->eid = $entity[0]; + $pk->motionX = $entity[1]; + $pk->motionY = $entity[2]; + $pk->motionZ = $entity[3]; + $this->addChunkPacket($chunkX, $chunkZ, $pk); + } } $this->motionToSend = []; @@ -849,7 +721,7 @@ public function doTick($currentTick){ $chunkPlayers = $this->getChunkPlayers($chunkX, $chunkZ); if(count($chunkPlayers) > 0){ foreach($entries as $pk){ - Server::broadcastPacket($chunkPlayers, $pk); + $this->server->broadcastPacket($chunkPlayers, $pk); } } } @@ -885,7 +757,7 @@ public function checkSleep(){ } } - public function sendBlockExtraData($x, $y, $z, $id, $data, array $targets = null){ + public function sendBlockExtraData(int $x, int $y, int $z, int $id, int $data, array $targets = null){ $pk = new LevelEventPacket; $pk->evid = LevelEventPacket::EVENT_SET_DATA; $pk->x = $x + 0.5; @@ -893,7 +765,7 @@ public function sendBlockExtraData($x, $y, $z, $id, $data, array $targets = null $pk->z = $z + 0.5; $pk->data = ($data << 8) | $id; - Server::broadcastPacket($targets === null ? $this->getChunkPlayers($x >> 4, $z >> 4) : $targets, $pk); + $this->server->broadcastPacket($targets === null ? $this->getChunkPlayers($x >> 4, $z >> 4) : $targets, $pk); } /** @@ -902,17 +774,15 @@ public function sendBlockExtraData($x, $y, $z, $id, $data, array $targets = null * @param int $flags * @param bool $optimizeRebuilds */ - public function sendBlocks(array $target, array $blocks, $flags = UpdateBlockPacket::FLAG_NONE, $optimizeRebuilds = false){ - $batchPacketList = []; - $top = -1; + public function sendBlocks(array $target, array $blocks, $flags = UpdateBlockPacket::FLAG_NONE, bool $optimizeRebuilds = false){ if($optimizeRebuilds){ $chunks = []; foreach($blocks as $b){ + $pk = new UpdateBlockPacket(); if($b === null){ continue; } - ++$top; - $batchPacketList[$top] = new UpdateBlockPacket(); + $first = false; if(!isset($chunks[$index = Level::chunkHash($b->x >> 4, $b->z >> 4)])){ $chunks[$index] = true; @@ -920,32 +790,51 @@ public function sendBlocks(array $target, array $blocks, $flags = UpdateBlockPac } if($b instanceof Block){ - $batchPacketList[$top]->records[] = [$b->x, $b->z, $b->y, $b->getId(), $b->getDamage(), $first ? $flags : UpdateBlockPacket::FLAG_NONE]; + $pk->x = $b->x; + $pk->z = $b->z; + $pk->y = $b->y; + $pk->blockId = $b->getId(); + $pk->blockData = $b->getDamage(); + $pk->flags = $first ? $flags : UpdateBlockPacket::FLAG_NONE; }else{ $fullBlock = $this->getFullBlock($b->x, $b->y, $b->z); - $batchPacketList[$top]->records[] = [$b->x, $b->z, $b->y, $fullBlock >> 4, $fullBlock & 0xf, $first ? $flags : UpdateBlockPacket::FLAG_NONE]; + $pk->x = $b->x; + $pk->z = $b->z; + $pk->y = $b->y; + $pk->blockId = $fullBlock >> 4; + $pk->blockData = $fullBlock & 0xf; + $pk->flags = $first ? $flags : UpdateBlockPacket::FLAG_NONE; } + $this->server->broadcastPacket($target, $pk); } }else{ foreach($blocks as $b){ + $pk = new UpdateBlockPacket(); if($b === null){ continue; } - ++$top; - $batchPacketList[$top] = new UpdateBlockPacket(); if($b instanceof Block){ - $batchPacketList[$top]->records[] = [$b->x, $b->z, $b->y, $b->getId(), $b->getDamage(), $flags]; + $pk->x = $b->x; + $pk->z = $b->z; + $pk->y = $b->y; + $pk->blockId = $b->getId(); + $pk->blockData = $b->getDamage(); + $pk->flags = $flags; }else{ $fullBlock = $this->getFullBlock($b->x, $b->y, $b->z); - $batchPacketList[$top]->records[] = [$b->x, $b->z, $b->y, $fullBlock >> 4, $fullBlock & 0xf, $flags]; + $pk->x = $b->x; + $pk->z = $b->z; + $pk->y = $b->y; + $pk->blockId = $fullBlock >> 4; + $pk->blockData = $fullBlock & 0xf; + $pk->flags = $flags; } + $this->server->broadcastPacket($target, $pk); } } - - $this->server->batchPackets($target, $batchPacketList); } - public function clearCache($full = false){ + public function clearCache(bool $full = false){ if($full){ $this->chunkCache = []; $this->blockCache = []; @@ -962,7 +851,7 @@ public function clearCache($full = false){ } - public function clearChunkCache($chunkX, $chunkZ){ + public function clearChunkCache(int $chunkX, int $chunkZ){ unset($this->chunkCache[Level::chunkHash($chunkX, $chunkZ)]); } @@ -981,7 +870,7 @@ private function tickChunks(){ $chunkZ = $loader->getZ() >> 4; $index = Level::chunkHash($chunkX, $chunkZ); - $existingLoaders = max(0, isset($this->chunkTickList[$index]) ? $this->chunkTickList[$index] : 0); + $existingLoaders = max(0, $this->chunkTickList[$index] ?? 0); $this->chunkTickList[$index] = $existingLoaders + 1; for($chunk = 0; $chunk < $chunksPerLoader; ++$chunk){ $dx = mt_rand(-$randRange, $randRange); @@ -993,8 +882,6 @@ private function tickChunks(){ } } - $blockTest = 0; - foreach($this->chunkTickList as $index => $loaders){ Level::getXZ($index, $chunkX, $chunkZ); @@ -1011,44 +898,19 @@ private function tickChunks(){ } - if($this->useSections){ - foreach($chunk->getSections() as $section){ - if(!($section instanceof EmptyChunkSection)){ - $Y = $section->getY(); - $k = mt_rand(0, 0x7fffffff); - for($i = 0; $i < 3; ++$i, $k >>= 10){ - $x = $k & 0x0f; - $y = ($k >> 8) & 0x0f; - $z = ($k >> 16) & 0x0f; - - $blockId = $section->getBlockId($x, $y, $z); - if(isset($this->randomTickBlocks[$blockId])){ - $class = $this->randomTickBlocks[$blockId]; - /** @var Block $block */ - $block = new $class($section->getBlockData($x, $y, $z)); - $block->x = $chunkX * 16 + $x; - $block->y = ($Y << 4) + $y; - $block->z = $chunkZ * 16 + $z; - $block->level = $this; - $block->onUpdate(self::BLOCK_UPDATE_RANDOM); - } - } - } - } - }else{ - for($Y = 0; $Y < 8 and ($Y < 3 or $blockTest !== 0); ++$Y){ - $blockTest = 0; + foreach($chunk->getSubChunks() as $Y => $subChunk){ + if(!$subChunk->isEmpty()){ $k = mt_rand(0, 0x7fffffff); for($i = 0; $i < 3; ++$i, $k >>= 10){ $x = $k & 0x0f; $y = ($k >> 8) & 0x0f; $z = ($k >> 16) & 0x0f; - $blockTest |= $blockId = $chunk->getBlockId($x, $y + ($Y << 4), $z); + $blockId = $subChunk->getBlockId($x, $y, $z); if(isset($this->randomTickBlocks[$blockId])){ $class = $this->randomTickBlocks[$blockId]; /** @var Block $block */ - $block = new $class($chunk->getBlockData($x, $y + ($Y << 4), $z)); + $block = new $class($subChunk->getBlockData($x, $y, $z)); $block->x = $chunkX * 16 + $x; $block->y = ($Y << 4) + $y; $block->z = $chunkZ * 16 + $z; @@ -1065,7 +927,7 @@ private function tickChunks(){ } } - public function __debugInfo(){ + public function __debugInfo() : array{ return []; } @@ -1074,7 +936,7 @@ public function __debugInfo(){ * * @return bool */ - public function save($force = false){ + public function save(bool $force = false){ if(!$this->getAutoSave() and !$force){ return false; @@ -1105,6 +967,7 @@ public function saveChunks(){ * @param Vector3 $pos */ public function updateAround(Vector3 $pos){ + $pos = $pos->floor(); $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlock($this->temporalVector->setComponents($pos->x, $pos->y - 1, $pos->z)))); if(!$ev->isCancelled()){ $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); @@ -1140,7 +1003,7 @@ public function updateAround(Vector3 $pos){ * @param Vector3 $pos * @param int $delay */ - public function scheduleUpdate(Vector3 $pos, $delay){ + public function scheduleUpdate(Vector3 $pos, int $delay){ if(isset($this->updateQueueIndex[$index = Level::blockHash($pos->x, $pos->y, $pos->z)]) and $this->updateQueueIndex[$index] <= $delay){ return; } @@ -1154,7 +1017,7 @@ public function scheduleUpdate(Vector3 $pos, $delay){ * * @return Block[] */ - public function getCollisionBlocks(AxisAlignedBB $bb, $targetFirst = false){ + public function getCollisionBlocks(AxisAlignedBB $bb, bool $targetFirst = false) : array{ $minX = Math::floorFloat($bb->minX); $minY = Math::floorFloat($bb->minY); $minZ = Math::floorFloat($bb->minZ); @@ -1197,7 +1060,7 @@ public function getCollisionBlocks(AxisAlignedBB $bb, $targetFirst = false){ * * @return bool */ - public function isFullBlock(Vector3 $pos){ + public function isFullBlock(Vector3 $pos) : bool{ if($pos instanceof Block){ if($pos->isSolid()){ return true; @@ -1217,7 +1080,7 @@ public function isFullBlock(Vector3 $pos){ * * @return AxisAlignedBB[] */ - public function getCollisionCubes(Entity $entity, AxisAlignedBB $bb, $entities = true){ + public function getCollisionCubes(Entity $entity, AxisAlignedBB $bb, bool $entities = true) : array{ $minX = Math::floorFloat($bb->minX); $minY = Math::floorFloat($bb->minY); $minZ = Math::floorFloat($bb->minZ); @@ -1319,14 +1182,14 @@ public function rayTraceBlocks(Vector3 $pos1, Vector3 $pos2, $flag = false, $fla } */ - public function getFullLight(Vector3 $pos){ + public function getFullLight(Vector3 $pos) : int{ $chunk = $this->getChunk($pos->x >> 4, $pos->z >> 4, false); $level = 0; - if($chunk instanceof FullChunk){ - $level = $chunk->getBlockSkyLight($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f); + if($chunk !== null){ + $level = $chunk->getBlockSkyLight($pos->x & 0x0f, $pos->y & Level::Y_MASK, $pos->z & 0x0f); //TODO: decrease light level by time of day if($level < 15){ - $level = max($chunk->getBlockLight($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f)); + $level = max($chunk->getBlockLight($pos->x & 0x0f, $pos->y & Level::Y_MASK, $pos->z & 0x0f)); } } @@ -1340,8 +1203,8 @@ public function getFullLight(Vector3 $pos){ * * @return int bitmap, (id << 4) | data */ - public function getFullBlock($x, $y, $z){ - return $this->getChunk($x >> 4, $z >> 4, false)->getFullBlock($x & 0x0f, $y & 0x7f, $z & 0x0f); + public function getFullBlock(int $x, int $y, int $z) : int{ + return $this->getChunk($x >> 4, $z >> 4, false)->getFullBlock($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f); } /** @@ -1352,13 +1215,13 @@ public function getFullBlock($x, $y, $z){ * * @return Block */ - public function getBlock(Vector3 $pos, $cached = true){ + public function getBlock(Vector3 $pos, $cached = true) : Block{ $pos = $pos->floor(); $index = Level::blockHash($pos->x, $pos->y, $pos->z); if($cached and isset($this->blockCache[$index])){ return $this->blockCache[$index]; - }elseif($pos->y >= 0 and $pos->y < 128 and isset($this->chunks[$chunkIndex = Level::chunkHash($pos->x >> 4, $pos->z >> 4)])){ - $fullState = $this->chunks[$chunkIndex]->getFullBlock($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f); + }elseif($pos->y >= 0 and $pos->y < $this->provider->getWorldHeight() and isset($this->chunks[$chunkIndex = Level::chunkHash($pos->x >> 4, $pos->z >> 4)])){ + $fullState = $this->chunks[$chunkIndex]->getFullBlock($pos->x & 0x0f, $pos->y & Level::Y_MASK, $pos->z & 0x0f); }else{ $fullState = 0; } @@ -1378,11 +1241,11 @@ public function updateAllLight(Vector3 $pos){ $this->updateBlockLight($pos->x, $pos->y, $pos->z); } - public function updateBlockSkyLight($x, $y, $z){ + public function updateBlockSkyLight(int $x, int $y, int $z){ //TODO } - public function updateBlockLight($x, $y, $z){ + public function updateBlockLight(int $x, int $y, int $z){ $lightPropagationQueue = new \SplQueue(); $lightRemovalQueue = new \SplQueue(); $visited = []; @@ -1434,7 +1297,8 @@ public function updateBlockLight($x, $y, $z){ } } - private function computeRemoveBlockLight($x, $y, $z, $currentLight, \SplQueue $queue, \SplQueue $spreadQueue, array &$visited, array &$spreadVisited){ + private function computeRemoveBlockLight(int $x, int $y, int $z, int $currentLight, \SplQueue $queue, \SplQueue $spreadQueue, array &$visited, array &$spreadVisited){ + if($y < 0) return; $current = $this->getBlockLightAt($x, $y, $z); if($current !== 0 and $current < $currentLight){ @@ -1454,7 +1318,8 @@ private function computeRemoveBlockLight($x, $y, $z, $currentLight, \SplQueue $q } } - private function computeSpreadBlockLight($x, $y, $z, $currentLight, \SplQueue $queue, array &$visited){ + private function computeSpreadBlockLight(int $x, int $y, int $z, int $currentLight, \SplQueue $queue, array &$visited){ + if($y < 0) return; $current = $this->getBlockLightAt($x, $y, $z); if($current < $currentLight){ @@ -1487,13 +1352,13 @@ private function computeSpreadBlockLight($x, $y, $z, $currentLight, \SplQueue $q * * @return bool Whether the block has been updated or not */ - public function setBlock(Vector3 $pos, Block $block, $direct = false, $update = true){ + public function setBlock(Vector3 $pos, Block $block, bool $direct = false, bool $update = true) : bool{ $pos = $pos->floor(); - if($pos->y < 0 or $pos->y >= 128){ + if($pos->y < 0 or $pos->y >= $this->provider->getWorldHeight()){ return false; } - if($this->getChunk($pos->x >> 4, $pos->z >> 4, true)->setBlock($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f, $block->getId(), $block->getDamage())){ + if($this->getChunk($pos->x >> 4, $pos->z >> 4, true)->setBlock($pos->x & 0x0f, $pos->y & Level::Y_MASK, $pos->z & 0x0f, $block->getId(), $block->getDamage())){ if(!($pos instanceof Position)){ $pos = $this->temporalPosition->setComponents($pos->x, $pos->y, $pos->z); } @@ -1544,10 +1409,8 @@ public function setBlock(Vector3 $pos, Block $block, $direct = false, $update = * @param Vector3 $motion * @param int $delay */ - public function dropItem(Vector3 $source, Item $item, Vector3 $motion = null, $delay = 10){ + public function dropItem(Vector3 $source, Item $item, Vector3 $motion = null, int $delay = 10){ $motion = $motion === null ? new Vector3(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1) : $motion; - $itemTag = NBT::putItemHelper($item); - $itemTag->setName("Item"); if($item->getId() > 0 and $item->getCount() > 0){ $itemEntity = Entity::createEntity("Item", $this->getChunk($source->getX() >> 4, $source->getZ() >> 4, true), new CompoundTag("", [ @@ -1567,7 +1430,7 @@ public function dropItem(Vector3 $source, Item $item, Vector3 $motion = null, $d new FloatTag("", 0) ]), "Health" => new ShortTag("Health", 5), - "Item" => $itemTag, + "Item" => $item->nbtSerialize(-1, "Item"), "PickupDelay" => new ShortTag("PickupDelay", $delay) ])); @@ -1584,10 +1447,11 @@ public function dropItem(Vector3 $source, Item $item, Vector3 $motion = null, $d * @param Player $player * @param bool $createParticles * - * @return boolean + * @return bool */ - public function useBreakOn(Vector3 $vector, Item &$item = null, Player $player = null, $createParticles = false){ + public function useBreakOn(Vector3 $vector, Item &$item = null, Player $player = null, bool $createParticles = false) : bool{ $target = $this->getBlock($vector); + //TODO: Adventure mode checks if($item === null){ $item = Item::get(Item::AIR, 0, 0); @@ -1596,7 +1460,7 @@ public function useBreakOn(Vector3 $vector, Item &$item = null, Player $player = if($player !== null){ $ev = new BlockBreakEvent($player, $target, $item, $player->isCreative() ? true : false); - if($player->isAdventure() or $player->isSpectator() or ($player->isSurvival() and $item instanceof Item and !$target->isBreakable($item))){ + if($player->isSurvival() and $item instanceof Item and !$target->isBreakable($item)){ $ev->setCancelled(); }elseif(!$player->isOp() and ($distance = $this->server->getSpawnRadius()) > -1){ $t = new Vector2($target->x, $target->z); @@ -1610,7 +1474,7 @@ public function useBreakOn(Vector3 $vector, Item &$item = null, Player $player = return false; } - /*$breakTime = $target->getBreakTime($item); + $breakTime = $target->getBreakTime($item); if($player->isCreative() and $breakTime > 0.15){ $breakTime = 0.15; @@ -1628,12 +1492,12 @@ public function useBreakOn(Vector3 $vector, Item &$item = null, Player $player = if(!$ev->getInstaBreak() and ($player->lastBreak + $breakTime) > microtime(true)){ return false; - }*/ + } $player->lastBreak = microtime(true); $drops = $ev->getDrops(); - + if($player->isSurvival() and $this->getServer()->expEnabled){ $exp = 0; if($item->getEnchantmentLevel(Enchantment::TYPE_MINING_SILK_TOUCH) === 0){ @@ -1666,9 +1530,9 @@ public function useBreakOn(Vector3 $vector, Item &$item = null, Player $player = }elseif($item !== null and !$target->isBreakable($item)){ return false; }else{ - $drops = $target->getDrops($item); //Fixes solidentity entities being deleted before getting drops + $drops = $target->getDrops($item); //Fixes tile entities being deleted before getting drops foreach($drops as $k => $i){ - if((isset ($i[0])) && (isset ($i[1])) && (isset ($i[2]))) $drops[$k] = Item::get($i[0], $i[1], $i[2]); + $drops[$k] = Item::get($i[0], $i[1], $i[2]); } } @@ -1699,28 +1563,28 @@ public function useBreakOn(Vector3 $vector, Item &$item = null, Player $player = if($createParticles){ $players = $this->getChunkPlayers($target->x >> 4, $target->z >> 4); - /*if($player !== null){ + if($player !== null){ unset($players[$player->getLoaderId()]); - }*/ + } $this->addParticle(new DestroyBlockParticle($target->add(0.5), $target), $players); } $target->onBreak($item); - $solidentity = $this->getsolidentity($target); - if($solidentity !== null){ - if($solidentity instanceof InventoryHolder){ - if($solidentity instanceof Chest){ - $solidentity->unpair(); + $tile = $this->getTile($target); + if($tile !== null){ + if($tile instanceof InventoryHolder){ + if($tile instanceof Chest){ + $tile->unpair(); } - foreach($solidentity->getInventory()->getContents() as $chestItem){ + foreach($tile->getInventory()->getContents() as $chestItem){ $this->dropItem($target, $chestItem); } } - $solidentity->close(); + $tile->close(); } if($item !== null){ @@ -1752,13 +1616,14 @@ public function useBreakOn(Vector3 $vector, Item &$item = null, Player $player = * @param float $fz default 0.0 * @param Player $player default null * - * @return boolean + * @return bool */ - public function useItemOn(Vector3 $vector, Item &$item, $face, $fx = 0.0, $fy = 0.0, $fz = 0.0, Player $player = null){ + public function useItemOn(Vector3 $vector, Item &$item, int $face, float $fx = 0.0, float $fy = 0.0, float $fz = 0.0, Player $player = null) : bool{ $target = $this->getBlock($vector); $block = $target->getSide($face); - if($block->y > 127 or $block->y < 0){ + if($block->y >= $this->provider->getWorldHeight() or $block->y < 0){ + //TODO: build height limit messages for custom world heights and mcregion cap return false; } @@ -1775,32 +1640,10 @@ public function useItemOn(Vector3 $vector, Item &$item, $face, $fx = 0.0, $fy = $ev->setCancelled(); } } - if($player->isSpectator()){ - $ev->setCancelled(); - } $this->server->getPluginManager()->callEvent($ev); if(!$ev->isCancelled()){ $target->onUpdate(self::BLOCK_UPDATE_TOUCH); - if(!$player->isSneaking()){ - if($target->canBeActivated() === true and $target->onActivate($item, $player) === true){ - if($item->getCount() <= 0){ - $item = Item::get(Item::AIR, 0, 0); - }elseif($item->isTool() and $item->getDamage() >= $item->getMaxDurability()){ - $item = Item::get(Item::AIR, 0, 0); - } - return true; - } - if($item->canBeActivated() and $item->onActivate($this, $player, $block, $target, $face, $fx, $fy, $fz)){ - if($item->getCount() <= 0){ - $item = Item::get(Item::AIR, 0, 0); - return true; - }elseif($item->isTool() and $item->getDamage() >= $item->getMaxDurability()){ - $item = Item::get(Item::AIR, 0, 0); - return true; - } - } - } - /*if(!$player->isSneaking() and $target->canBeActivated() === true and $target->onActivate($item, $player) === true){ + if(!$player->isSneaking() and $target->canBeActivated() === true and $target->onActivate($item, $player) === true){ return true; } @@ -1810,7 +1653,7 @@ public function useItemOn(Vector3 $vector, Item &$item, $face, $fx = 0.0, $fy = return true; } - }*/ + } }else{ return false; } @@ -1825,7 +1668,7 @@ public function useItemOn(Vector3 $vector, Item &$item, $face, $fx = 0.0, $fy = return false; } - if(!($block->canBeReplaced() === true or ($hand->getId() === Item::SLAB and $block->getId() === Item::SLAB))){ + if(!($block->canBeReplaced() === true or ($hand->getId() === Item::WOOD_SLAB and $block->getId() === Item::WOOD_SLAB) or ($hand->getId() === Item::SLAB and $block->getId() === Item::SLAB))){ return false; } @@ -1897,36 +1740,7 @@ public function useItemOn(Vector3 $vector, Item &$item, $face, $fx = 0.0, $fy = return false; } - if($hand->getId() === Item::SIGN_POST or $hand->getId() === Item::WALL_SIGN){ - - $nbt = new CompoundTag("", [ - "id" => new StringTag("id", solidentity::SIGN), - "x" => new IntTag("x", $block->x), - "y" => new IntTag("y", $block->y), - "z" => new IntTag("z", $block->z), - "Text1" => new StringTag("Text1", ""), - "Text2" => new StringTag("Text2", ""), - "Text3" => new StringTag("Text3", ""), - "Text4" => new StringTag("Text4", "") - ]); - - if($player !== null){ - $nbt->Creator = new StringTag("Creator", $player->getRawUniqueId()); - } - - if($item->hasCustomBlockData()){ - foreach($item->getCustomBlockData() as $key => $v){ - $nbt->{$key} = $v; - } - } - - solidentity::createsolidentity("Sign", $this->getChunk($block->x >> 4, $block->z >> 4), $nbt); - } - if ($player != null && $player->isCreative()) { - $item->setCount($item->getCount()); - } else { - $item->setCount($item->getCount() - 1); - } + $item->setCount($item->getCount() - 1); if($item->getCount() <= 0){ $item = Item::get(Item::AIR, 0, 0); } @@ -1939,8 +1753,8 @@ public function useItemOn(Vector3 $vector, Item &$item, $face, $fx = 0.0, $fy = * * @return Entity */ - public function getEntity($entityId){ - return isset($this->entities[$entityId]) ? $this->entities[$entityId] : null; + public function getEntity(int $entityId){ + return $this->entities[$entityId] ?? null; } /** @@ -1948,7 +1762,7 @@ public function getEntity($entityId){ * * @return Entity[] */ - public function getEntities(){ + public function getEntities() : array{ return $this->entities; } @@ -1956,11 +1770,11 @@ public function getEntities(){ * Returns the entities colliding the current one inside the AxisAlignedBB * * @param AxisAlignedBB $bb - * @param Entity $entity + * @param Entity|null $entity * * @return Entity[] */ - public function getCollidingEntities(AxisAlignedBB $bb, Entity $entity = null){ + public function getCollidingEntities(AxisAlignedBB $bb, Entity $entity = null) : array{ $nearby = []; if($entity === null or $entity->canCollide){ @@ -1972,14 +1786,8 @@ public function getCollidingEntities(AxisAlignedBB $bb, Entity $entity = null){ for($x = $minX; $x <= $maxX; ++$x){ for($z = $minZ; $z <= $maxZ; ++$z){ foreach($this->getChunkEntities($x, $z) as $ent){ - if($entity == null){ - if($ent->boundingBox->intersectsWith($bb)){ - $nearby[] = $ent; - } - }elseif($entity instanceof Entity and $ent !== $entity and $entity->canCollideWith($ent)){ - if($ent->boundingBox->intersectsWith($bb)){ - $nearby[] = $ent; - } + if(($entity === null or ($ent !== $entity and $entity->canCollideWith($ent))) and $ent->boundingBox->intersectsWith($bb)){ + $nearby[] = $ent; } } } @@ -1988,6 +1796,18 @@ public function getCollidingEntities(AxisAlignedBB $bb, Entity $entity = null){ return $nearby; } + + public function getNearbyExperienceOrb(AxisAlignedBB $bb) : array{ + $nearby = []; + + foreach($this->getNearbyEntities($bb) as $entity){ + if($entity instanceof XPOrb){ + $nearby[] = $entity; + } + } + + return $nearby; + } /** * Returns the entities near the current one inside the AxisAlignedBB @@ -1997,7 +1817,7 @@ public function getCollidingEntities(AxisAlignedBB $bb, Entity $entity = null){ * * @return Entity[] */ - public function getNearbyEntities(AxisAlignedBB $bb, Entity $entity = null){ + public function getNearbyEntities(AxisAlignedBB $bb, Entity $entity = null) : array{ $nearby = []; $minX = Math::floorFloat(($bb->minX - 2) / 16); @@ -2018,7 +1838,7 @@ public function getNearbyEntities(AxisAlignedBB $bb, Entity $entity = null){ return $nearby; } - public function getNearbyExperienceOrb(AxisAlignedBB $bb){ + /*public function getNearbyExperienceOrb(AxisAlignedBB $bb) : array{ $nearby = []; foreach($this->getNearbyEntities($bb) as $entity){ @@ -2028,24 +1848,24 @@ public function getNearbyExperienceOrb(AxisAlignedBB $bb){ } return $nearby; - } + }*/ /** - * Returns a list of the solidentity entities in this level + * Returns a list of the Tile entities in this level * - * @return solidentity[] + * @return Tile[] */ - public function getsolidentities(){ - return $this->solidentities; + public function getTiles() : array{ + return $this->tiles; } /** - * @param $solidentityId + * @param $tileId * - * @return solidentity + * @return Tile */ - public function getsolidentityById($solidentityId){ - return isset($this->solidentities[$solidentityId]) ? $this->solidentities[$solidentityId] : null; + public function getTileById(int $tileId){ + return $this->tiles[$tileId] ?? null; } /** @@ -2053,29 +1873,29 @@ public function getsolidentityById($solidentityId){ * * @return Player[] */ - public function getPlayers(){ + public function getPlayers() : array{ return $this->players; } /** * @return ChunkLoader[] */ - public function getLoaders(){ + public function getLoaders() : array{ return $this->loaders; } /** - * Returns the solidentity in a position, or null if not found + * Returns the Tile in a position, or null if not found * * @param Vector3 $pos * - * @return solidentity + * @return Tile */ - public function getsolidentity(Vector3 $pos){ + public function getTile(Vector3 $pos){ $chunk = $this->getChunk($pos->x >> 4, $pos->z >> 4, false); if($chunk !== null){ - return $chunk->getsolidentity($pos->x & 0x0f, $pos->y & 0xff, $pos->z & 0x0f); + return $chunk->getTile($pos->x & 0x0f, $pos->y & Level::Y_MASK, $pos->z & 0x0f); } return null; @@ -2089,20 +1909,20 @@ public function getsolidentity(Vector3 $pos){ * * @return Entity[] */ - public function getChunkEntities($X, $Z){ + public function getChunkEntities($X, $Z) : array{ return ($chunk = $this->getChunk($X, $Z)) !== null ? $chunk->getEntities() : []; } /** - * Gives a list of the solidentity entities on a given chunk + * Gives a list of the Tile entities on a given chunk * * @param int $X * @param int $Z * - * @return solidentity[] + * @return Tile[] */ - public function getChunksolidentities($X, $Z){ - return ($chunk = $this->getChunk($X, $Z)) !== null ? $chunk->getsolidentities() : []; + public function getChunkTiles($X, $Z) : array{ + return ($chunk = $this->getChunk($X, $Z)) !== null ? $chunk->getTiles() : []; } /** @@ -2114,8 +1934,8 @@ public function getChunksolidentities($X, $Z){ * * @return int 0-255 */ - public function getBlockIdAt(int $x, int $y, int $z) :int{ - return $this->getChunk($x >> 4, $z >> 4, true)->getBlockId($x & 0x0f, $y & 0x7f, $z & 0x0f); + public function getBlockIdAt(int $x, int $y, int $z) : int{ + return $this->getChunk($x >> 4, $z >> 4, true)->getBlockId($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f); } /** @@ -2128,7 +1948,7 @@ public function getBlockIdAt(int $x, int $y, int $z) :int{ */ public function setBlockIdAt(int $x, int $y, int $z, int $id){ unset($this->blockCache[Level::blockHash($x, $y, $z)]); - $this->getChunk($x >> 4, $z >> 4, true)->setBlockId($x & 0x0f, $y & 0x7f, $z & 0x0f, $id & 0xff); + $this->getChunk($x >> 4, $z >> 4, true)->setBlockId($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f, $id & 0xff); if(!isset($this->changedBlocks[$index = Level::chunkHash($x >> 4, $z >> 4)])){ $this->changedBlocks[$index] = []; @@ -2148,12 +1968,12 @@ public function setBlockIdAt(int $x, int $y, int $z, int $id){ * * @return int 16-bit */ - public function getBlockExtraDataAt($x, $y, $z){ - return $this->getChunk($x >> 4, $z >> 4, true)->getBlockExtraData($x & 0x0f, $y & 0x7f, $z & 0x0f); + public function getBlockExtraDataAt(int $x, int $y, int $z) : int{ + return $this->getChunk($x >> 4, $z >> 4, true)->getBlockExtraData($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f); } /** - * Sets the raw block epilogos. + * Sets the raw block metadata. * * @param int $x * @param int $y @@ -2161,14 +1981,14 @@ public function getBlockExtraDataAt($x, $y, $z){ * @param int $id * @param int $data */ - public function setBlockExtraDataAt($x, $y, $z, $id, $data){ - $this->getChunk($x >> 4, $z >> 4, true)->setBlockExtraData($x & 0x0f, $y & 0x7f, $z & 0x0f, ($data << 8) | $id); + public function setBlockExtraDataAt(int $x, int $y, int $z, int $id, int $data){ + $this->getChunk($x >> 4, $z >> 4, true)->setBlockExtraData($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f, ($data << 8) | $id); $this->sendBlockExtraData($x, $y, $z, $id, $data); } /** - * Gets the raw block epilogos + * Gets the raw block metadata * * @param int $x * @param int $y @@ -2177,11 +1997,11 @@ public function setBlockExtraDataAt($x, $y, $z, $id, $data){ * @return int 0-15 */ public function getBlockDataAt(int $x, int $y, int $z) : int{ - return $this->getChunk($x >> 4, $z >> 4, true)->getBlockData($x & 0x0f, $y & 0x7f, $z & 0x0f); + return $this->getChunk($x >> 4, $z >> 4, true)->getBlockData($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f); } /** - * Sets the raw block epilogos. + * Sets the raw block metadata. * * @param int $x * @param int $y @@ -2190,7 +2010,7 @@ public function getBlockDataAt(int $x, int $y, int $z) : int{ */ public function setBlockDataAt(int $x, int $y, int $z, int $data){ unset($this->blockCache[Level::blockHash($x, $y, $z)]); - $this->getChunk($x >> 4, $z >> 4, true)->setBlockData($x & 0x0f, $y & 0x7f, $z & 0x0f, $data & 0x0f); + $this->getChunk($x >> 4, $z >> 4, true)->setBlockData($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f, $data & 0x0f); if(!isset($this->changedBlocks[$index = Level::chunkHash($x >> 4, $z >> 4)])){ $this->changedBlocks[$index] = []; @@ -2210,8 +2030,8 @@ public function setBlockDataAt(int $x, int $y, int $z, int $data){ * * @return int 0-15 */ - public function getBlockSkyLightAt($x, $y, $z){ - return $this->getChunk($x >> 4, $z >> 4, true)->getBlockSkyLight($x & 0x0f, $y & 0x7f, $z & 0x0f); + public function getBlockSkyLightAt(int $x, int $y, int $z) : int{ + return $this->getChunk($x >> 4, $z >> 4, true)->getBlockSkyLight($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f); } /** @@ -2222,8 +2042,8 @@ public function getBlockSkyLightAt($x, $y, $z){ * @param int $z * @param int $level 0-15 */ - public function setBlockSkyLightAt($x, $y, $z, $level){ - $this->getChunk($x >> 4, $z >> 4, true)->setBlockSkyLight($x & 0x0f, $y & 0x7f, $z & 0x0f, $level & 0x0f); + public function setBlockSkyLightAt(int $x, int $y, int $z, int $level){ + $this->getChunk($x >> 4, $z >> 4, true)->setBlockSkyLight($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f, $level & 0x0f); } /** @@ -2235,8 +2055,8 @@ public function setBlockSkyLightAt($x, $y, $z, $level){ * * @return int 0-15 */ - public function getBlockLightAt($x, $y, $z){ - return $this->getChunk($x >> 4, $z >> 4, true)->getBlockLight($x & 0x0f, $y & 0x7f, $z & 0x0f); + public function getBlockLightAt(int $x, int $y, int $z) : int{ + return $this->getChunk($x >> 4, $z >> 4, true)->getBlockLight($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f); } /** @@ -2247,8 +2067,8 @@ public function getBlockLightAt($x, $y, $z){ * @param int $z * @param int $level 0-15 */ - public function setBlockLightAt($x, $y, $z, $level){ - $this->getChunk($x >> 4, $z >> 4, true)->setBlockLight($x & 0x0f, $y & 0x7f, $z & 0x0f, $level & 0x0f); + public function setBlockLightAt(int $x, int $y, int $z, int $level){ + $this->getChunk($x >> 4, $z >> 4, true)->setBlockLight($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f, $level & 0x0f); } /** @@ -2257,27 +2077,17 @@ public function setBlockLightAt($x, $y, $z, $level){ * * @return int */ - public function getBiomeId($x, $z){ + public function getBiomeId(int $x, int $z) : int{ return $this->getChunk($x >> 4, $z >> 4, true)->getBiomeId($x & 0x0f, $z & 0x0f); } - /** - * @param int $x - * @param int $z - * - * @return int[] - */ - public function getBiomeColor($x, $z){ - return $this->getChunk($x >> 4, $z >> 4, true)->getBiomeColor($x & 0x0f, $z & 0x0f); - } - /** * @param int $x * @param int $z * * @return int */ - public function getHeightMap($x, $z){ + public function getHeightMap(int $x, int $z) : int{ return $this->getChunk($x >> 4, $z >> 4, true)->getHeightMap($x & 0x0f, $z & 0x0f); } @@ -2286,34 +2096,23 @@ public function getHeightMap($x, $z){ * @param int $z * @param int $biomeId */ - public function setBiomeId($x, $z, $biomeId){ + public function setBiomeId(int $x, int $z, int $biomeId){ $this->getChunk($x >> 4, $z >> 4, true)->setBiomeId($x & 0x0f, $z & 0x0f, $biomeId); } - /** - * @param int $x - * @param int $z - * @param int $R - * @param int $G - * @param int $B - */ - public function setBiomeColor($x, $z, $R, $G, $B){ - $this->getChunk($x >> 4, $z >> 4, true)->setBiomeColor($x & 0x0f, $z & 0x0f, $R, $G, $B); - } - /** * @param int $x * @param int $z * @param int $value */ - public function setHeightMap($x, $z, $value){ + public function setHeightMap(int $x, int $z, int $value){ $this->getChunk($x >> 4, $z >> 4, true)->setHeightMap($x & 0x0f, $z & 0x0f, $value); } /** - * @return FullChunk[]|Chunk[] + * @return Chunk[] */ - public function getChunks(){ + public function getChunks() : array{ return $this->chunks; } @@ -2324,7 +2123,7 @@ public function getChunks(){ * @param int $z * @param bool $create Whether to generate the chunk if it does not exist * - * @return FullChunk|Chunk + * @return Chunk */ public function getChunk(int $x, int $z, bool $create = false){ if(isset($this->chunks[$index = Level::chunkHash($x, $z)])){ @@ -2336,20 +2135,7 @@ public function getChunk(int $x, int $z, bool $create = false){ return null; } - /** - * @param int $x - * @param int $z - * @param bool $create - * - * @return FullChunk|Chunk - * - * @deprecated - */ - public function getChunkAt($x, $z, $create = false){ - return $this->getChunk($x, $z, $create); - } - - public function generateChunkCallback($x, $z, FullChunk $chunk){ + public function generateChunkCallback(int $x, int $z, Chunk $chunk){ Timings::$generationCallbackTimer->startTiming(); if(isset($this->chunkPopulationQueue[$index = Level::chunkHash($x, $z)])){ $oldChunk = $this->getChunk($x, $z, false); @@ -2382,12 +2168,12 @@ public function generateChunkCallback($x, $z, FullChunk $chunk){ } /** - * @param int $chunkX - * @param int $chunkZ - * @param FullChunk $chunk - * @param bool $unload + * @param int $chunkX + * @param int $chunkZ + * @param Chunk $chunk + * @param bool $unload */ - public function setChunk(int $chunkX, int $chunkZ, FullChunk $chunk = null, bool $unload = true){ + public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null, bool $unload = true){ if($chunk === null){ return; } @@ -2400,7 +2186,7 @@ public function setChunk(int $chunkX, int $chunkZ, FullChunk $chunk = null, bool $this->chunks[$index] = $chunk; }else{ $oldEntities = $oldChunk !== null ? $oldChunk->getEntities() : []; - $oldsolidentities = $oldChunk !== null ? $oldChunk->getsolidentities() : []; + $oldTiles = $oldChunk !== null ? $oldChunk->getTiles() : []; $this->provider->setChunk($chunkX, $chunkZ, $chunk); $this->chunks[$index] = $chunk; @@ -2410,9 +2196,9 @@ public function setChunk(int $chunkX, int $chunkZ, FullChunk $chunk = null, bool $entity->chunk = $chunk; } - foreach($oldsolidentities as $solidentity){ - $chunk->addsolidentity($solidentity); - $solidentity->chunk = $chunk; + foreach($oldTiles as $tile){ + $chunk->addTile($tile); + $tile->chunk = $chunk; } } @@ -2427,60 +2213,7 @@ public function setChunk(int $chunkX, int $chunkZ, FullChunk $chunk = null, bool } } } - - /** - * Directly send a lightning to a player - * - * @deprecated - * - * @param int $x - * @param int $y - * @param int $z - * @param Player $p - */ - public function sendLighting(int $x, int $y, int $z, Player $p){ - $pk = new AddEntityPacket(); - $pk->type = Lightning::NETWORK_ID; - $pk->eid = mt_rand(10000000, 100000000); - $pk->x = $x; - $pk->y = $y; - $pk->z = $z; - $pk->epilogos = array(3, 3, 3, 3); - $p->dataPacket($pk); - } - - /** - * Add a lightning - * - * @param Vector3 $pos - * @return Lightning - */ - public function spawnLightning(Vector3 $pos){ - $nbt = new CompoundTag("", [ - "Pos" => new ListTag("Pos", [ - new DoubleTag("", $pos->getX()), - new DoubleTag("", $pos->getY()), - new DoubleTag("", $pos->getZ()) - ]), - "Motion" => new ListTag("Motion", [ - new DoubleTag("", 0), - new DoubleTag("", 0), - new DoubleTag("", 0) - ]), - "Rotation" => new ListTag("Rotation", [ - new FloatTag("", 0), - new FloatTag("", 0) - ]), - ]); - - $chunk = $this->getChunk($pos->x >> 4, $pos->z >> 4, false); - - $lightning = new Lightning($chunk, $nbt); - $lightning->spawnToAll(); - - return $lightning; - } - + /** * Add an experience orb * @@ -2488,7 +2221,7 @@ public function spawnLightning(Vector3 $pos){ * @param int $exp * @return bool|XPOrb */ - public function spawnXPOrb(Vector3 $pos, int $exp = 1){ + public function spawnXPOrb(Vector3 $pos, int $exp = 1){ if($exp > 0){ $nbt = new CompoundTag("", [ "Pos" => new ListTag("Pos", [ @@ -2518,29 +2251,26 @@ public function spawnXPOrb(Vector3 $pos, int $exp = 1){ return false; } + /** * Gets the highest block Y value at a specific $x and $z * * @param int $x * @param int $z * - * @return int 0-127 + * @return int 0-255 */ - public function getHighestBlockAt($x, $z){ + public function getHighestBlockAt(int $x, int $z) : int{ return $this->getChunk($x >> 4, $z >> 4, true)->getHighestBlockAt($x & 0x0f, $z & 0x0f); } - public function canBlockSeeSky(Vector3 $pos){ - return $this->getHighestBlockAt($pos->getFloorX(), $pos->getFloorZ()) < $pos->getY(); - } - /** * @param int $x * @param int $z * * @return bool */ - public function isChunkLoaded($x, $z){ + public function isChunkLoaded(int $x, int $z) : bool{ return isset($this->chunks[Level::chunkHash($x, $z)]) or $this->provider->isChunkLoaded($x, $z); } @@ -2550,7 +2280,7 @@ public function isChunkLoaded($x, $z){ * * @return bool */ - public function isChunkGenerated($x, $z){ + public function isChunkGenerated(int $x, int $z) : bool{ $chunk = $this->getChunk($x, $z); return $chunk !== null ? $chunk->isGenerated() : false; } @@ -2561,7 +2291,7 @@ public function isChunkGenerated($x, $z){ * * @return bool */ - public function isChunkPopulated($x, $z){ + public function isChunkPopulated(int $x, int $z) : bool{ $chunk = $this->getChunk($x, $z); return $chunk !== null ? $chunk->isPopulated() : false; } @@ -2571,7 +2301,7 @@ public function isChunkPopulated($x, $z){ * * @return Position */ - public function getSpawnLocation(){ + public function getSpawnLocation() : Position{ return Position::fromObject($this->provider->getSpawn(), $this); } @@ -2586,7 +2316,7 @@ public function setSpawnLocation(Vector3 $pos){ $this->server->getPluginManager()->callEvent(new SpawnChangeEvent($this, $previousSpawn)); } - public function requestChunk($x, $z, Player $player){ + public function requestChunk(int $x, int $z, Player $player){ $index = Level::chunkHash($x, $z); if(!isset($this->chunkSendQueue[$index])){ $this->chunkSendQueue[$index] = []; @@ -2595,7 +2325,7 @@ public function requestChunk($x, $z, Player $player){ $this->chunkSendQueue[$index][$player->getLoaderId()] = $player; } - private function sendChunkFromCache($x, $z){ + private function sendChunkFromCache(int $x, int $z){ if(isset($this->chunkSendTasks[$index = Level::chunkHash($x, $z)])){ foreach($this->chunkSendQueue[$index] as $player){ /** @var Player $player */ @@ -2612,8 +2342,6 @@ private function processChunkRequest(){ if(count($this->chunkSendQueue) > 0){ $this->timings->syncChunkSendTimer->startTiming(); - $x = null; - $z = null; foreach($this->chunkSendQueue as $index => $players){ if(isset($this->chunkSendTasks[$index])){ continue; @@ -2636,13 +2364,13 @@ private function processChunkRequest(){ } } - public function chunkRequestCallback($x, $z, $payload, $ordering = FullChunkDataPacket::ORDER_COLUMNS){ + public function chunkRequestCallback(int $x, int $z, string $payload){ $this->timings->syncChunkSendTimer->startTiming(); $index = Level::chunkHash($x, $z); if(!isset($this->chunkCache[$index]) and $this->cacheChunks and $this->server->getMemoryManager()->canUseChunkCache()){ - $this->chunkCache[$index] = Player::getChunkCacheFromData($x, $z, $payload, $ordering); + $this->chunkCache[$index] = Level::getChunkCacheFromData($x, $z, $payload); $this->sendChunkFromCache($x, $z); $this->timings->syncChunkSendTimer->stopTiming(); return; @@ -2652,7 +2380,7 @@ public function chunkRequestCallback($x, $z, $payload, $ordering = FullChunkData foreach($this->chunkSendQueue[$index] as $player){ /** @var Player $player */ if($player->isConnected() and isset($player->usedChunks[$index])){ - $player->sendChunk($x, $z, $payload, $ordering); + $player->sendChunk($x, $z, $payload); } } unset($this->chunkSendQueue[$index]); @@ -2700,31 +2428,31 @@ public function addEntity(Entity $entity){ } /** - * @param solidentity $solidentity + * @param Tile $tile * * @throws LevelException */ - public function addsolidentity(solidentity $solidentity){ - if($solidentity->getLevel() !== $this){ - throw new LevelException("Invalid solidentity level"); + public function addTile(Tile $tile){ + if($tile->getLevel() !== $this){ + throw new LevelException("Invalid Tile level"); } - $this->solidentities[$solidentity->getId()] = $solidentity; - $this->clearChunkCache($solidentity->getX() >> 4, $solidentity->getZ() >> 4); + $this->tiles[$tile->getId()] = $tile; + $this->clearChunkCache($tile->getX() >> 4, $tile->getZ() >> 4); } /** - * @param solidentity $solidentity + * @param Tile $tile * * @throws LevelException */ - public function removesolidentity(solidentity $solidentity){ - if($solidentity->getLevel() !== $this){ - throw new LevelException("Invalid solidentity level"); + public function removeTile(Tile $tile){ + if($tile->getLevel() !== $this){ + throw new LevelException("Invalid Tile level"); } - unset($this->solidentities[$solidentity->getId()]); - unset($this->updatesolidentities[$solidentity->getId()]); - $this->clearChunkCache($solidentity->getX() >> 4, $solidentity->getZ() >> 4); + unset($this->tiles[$tile->getId()]); + unset($this->updateTiles[$tile->getId()]); + $this->clearChunkCache($tile->getX() >> 4, $tile->getZ() >> 4); } /** @@ -2733,7 +2461,7 @@ public function removesolidentity(solidentity $solidentity){ * * @return bool */ - public function isChunkInUse($x, $z){ + public function isChunkInUse(int $x, int $z) : bool{ return isset($this->chunkLoaders[$index = Level::chunkHash($x, $z)]) and count($this->chunkLoaders[$index]) > 0; } @@ -2743,8 +2471,10 @@ public function isChunkInUse($x, $z){ * @param bool $generate * * @return bool + * + * @throws \InvalidStateException */ - public function loadChunk($x, $z, $generate = true){ + public function loadChunk(int $x, int $z, bool $generate = true) : bool{ if(isset($this->chunks[$index = Level::chunkHash($x, $z)])){ return true; } @@ -2761,19 +2491,6 @@ public function loadChunk($x, $z, $generate = true){ return false; } - if($this->provider->getProviderName() == "mcregion"){ - if($chunk->getBiomeColor(0, 0) == [0, 0, 0]){ - for($x = 0; $x < 16; ++$x){ - for($z = 0; $z < 16; ++$z){ - $biome = Biome::getBiome(Biome::PLAINS); - $chunk->setBiomeId($x, $z, $biome->getId()); - $c = $biome->getColor(); - $chunk->setBiomeColor($x, $z, $c >> 16, ($c >> 8) & 0xff, $c & 0xff); - } - } - } - } - $this->chunks[$index] = $chunk; $chunk->initChunk(); @@ -2802,12 +2519,12 @@ public function loadChunk($x, $z, $generate = true){ return true; } - private function queueUnloadChunk($x, $z){ + private function queueUnloadChunk(int $x, int $z){ $this->unloadQueue[$index = Level::chunkHash($x, $z)] = microtime(true); unset($this->chunkTickList[$index]); } - public function unloadChunkRequest($x, $z, $safe = true){ + public function unloadChunkRequest(int $x, int $z, bool $safe = true){ if(($safe === true and $this->isChunkInUse($x, $z)) or $this->isSpawnChunk($x, $z)){ return false; } @@ -2817,11 +2534,11 @@ public function unloadChunkRequest($x, $z, $safe = true){ return true; } - public function cancelUnloadChunkRequest($x, $z){ + public function cancelUnloadChunkRequest(int $x, int $z){ unset($this->unloadQueue[Level::chunkHash($x, $z)]); } - public function unloadChunk($x, $z, $safe = true, $trySave = true){ + public function unloadChunk(int $x, int $z, bool $safe = true, bool $trySave = true) : bool{ if(($safe === true and $this->isChunkInUse($x, $z))){ return false; } @@ -2855,7 +2572,7 @@ public function unloadChunk($x, $z, $safe = true, $trySave = true){ ++$entities; } - if($chunk->hasChanged() or count($chunk->getsolidentities()) > 0 or $entities > 0){ + if($chunk->hasChanged() or count($chunk->getTiles()) > 0 or $entities > 0){ $this->provider->setChunk($x, $z, $chunk); $this->provider->saveChunk($x, $z); } @@ -2868,10 +2585,8 @@ public function unloadChunk($x, $z, $safe = true, $trySave = true){ $this->provider->unloadChunk($x, $z, $safe); }catch(\Throwable $e){ $logger = $this->server->getLogger(); - $logger->error($this->server->getLanguage()->translateString("devmine.level.chunkUnloadError", [$e->getMessage()])); - if($logger instanceof MainLogger){ - $logger->logException($e); - } + $logger->error($this->server->getLanguage()->translateString("DevMine.level.chunkUnloadError", [$e->getMessage()])); + $logger->logException($e); } unset($this->chunks[$index]); @@ -2891,23 +2606,13 @@ public function unloadChunk($x, $z, $safe = true, $trySave = true){ * * @return bool */ - public function isSpawnChunk($X, $Z){ + public function isSpawnChunk(int $X, int $Z) : bool{ $spawnX = $this->provider->getSpawn()->getX() >> 4; $spawnZ = $this->provider->getSpawn()->getZ() >> 4; return abs($X - $spawnX) <= 1 and abs($Z - $spawnZ) <= 1; } - /** - * Returns the raw spawnpoint - * - * @deprecated - * @return Position - */ - public function getSpawn(){ - return $this->getSpawnLocation(); - } - /** * @param Vector3 $spawn default null * @@ -2918,12 +2623,13 @@ public function getSafeSpawn($spawn = null){ $spawn = $this->getSpawnLocation(); } if($spawn instanceof Vector3){ + $max = $this->provider->getWorldHeight(); $v = $spawn->floor(); $chunk = $this->getChunk($v->x >> 4, $v->z >> 4, false); $x = $v->x & 0x0f; $z = $v->z & 0x0f; if($chunk !== null){ - $y = (int) min(126, $v->y); + $y = (int) min($max - 2, $v->y); $wasAir = ($chunk->getBlockId($x, $y - 1, $z) === 0); for(; $y > 0; --$y){ $b = $chunk->getFullBlock($x, $y, $z); @@ -2938,7 +2644,7 @@ public function getSafeSpawn($spawn = null){ } } - for(; $y >= 0 and $y < 128; ++$y){ + for(; $y >= 0 and $y < $max; ++$y){ $b = $chunk->getFullBlock($x, $y + 1, $z); $block = Block::get($b >> 4, $b & 0x0f); if(!$this->isFullBlock($block)){ @@ -2961,23 +2667,12 @@ public function getSafeSpawn($spawn = null){ return false; } - /** - * Sets the spawnpoint - * - * @param Vector3 $pos - * - * @deprecated - */ - public function setSpawn(Vector3 $pos){ - $this->setSpawnLocation($pos); - } - /** * Gets the current time * * @return int */ - public function getTime(){ + public function getTime() : int{ return (int) $this->time; } @@ -2995,7 +2690,7 @@ public function getName() : string{ * * @return string */ - public function getFolderName(){ + public function getFolderName() : string{ return $this->folderName; } @@ -3004,8 +2699,8 @@ public function getFolderName(){ * * @param int $time */ - public function setTime($time){ - $this->time = (int) $time; + public function setTime(int $time){ + $this->time = $time; $this->sendTime(); } @@ -3028,7 +2723,7 @@ public function startTime(){ /** * Gets the level seed * - * @return int + * @return int|string int value of seed, or the string numeric representation of a long in 32-bit systems */ public function getSeed(){ return $this->provider->getSeed(); @@ -3039,11 +2734,12 @@ public function getSeed(){ * * @param int $seed */ - public function setSeed($seed){ + public function setSeed(int $seed){ $this->provider->setSeed($seed); } - public function populateChunk($x, $z, $force = false){ + + public function populateChunk(int $x, int $z, bool $force = false) : bool{ if(isset($this->chunkPopulationQueue[$index = Level::chunkHash($x, $z)]) or (count($this->chunkPopulationQueue) >= $this->chunkPopulationQueueSize and !$force)){ return false; } @@ -3081,7 +2777,7 @@ public function populateChunk($x, $z, $force = false){ return true; } - public function generateChunk($x, $z, $force = false){ + public function generateChunk(int $x, int $z, bool $force = false){ if(count($this->chunkGenerationQueue) >= $this->chunkGenerationQueueSize and !$force){ return; } @@ -3095,7 +2791,7 @@ public function generateChunk($x, $z, $force = false){ } } - public function regenerateChunk($x, $z){ + public function regenerateChunk(int $x, int $z){ $this->unloadChunk($x, $z, false); $this->cancelUnloadChunkRequest($x, $z); @@ -3107,9 +2803,6 @@ public function regenerateChunk($x, $z){ public function doChunkGarbageCollection(){ $this->timings->doChunkGC->startTiming(); - $X = null; - $Z = null; - foreach($this->chunks as $index => $chunk){ if(!isset($this->unloadQueue[$index])){ Level::getXZ($index, $X, $Z); @@ -3130,7 +2823,7 @@ public function doChunkGarbageCollection(){ $this->timings->doChunkGC->stopTiming(); } - public function unloadChunks($force = false){ + public function unloadChunks(bool $force = false){ if(count($this->unloadQueue) > 0){ $maxUnload = 96; $now = microtime(true); @@ -3154,30 +2847,52 @@ public function unloadChunks($force = false){ } } - public function setepilogos($epilogosKey, epilogosValue $epilogosValue){ - $this->server->getLevelepilogos()->setepilogos($this, $epilogosKey, $epilogosValue); + /** + * @param int $chunkX + * @param int $chunkZ + * @param string $payload + * + * @return DataPacket + */ + public static function getChunkCacheFromData($chunkX, $chunkZ, $payload){ + $pk = new FullChunkDataPacket(); + $pk->chunkX = $chunkX; + $pk->chunkZ = $chunkZ; + $pk->data = $payload; + $pk->encode(); + + $batch = new BatchPacket(); + $batch->payload = zlib_encode(Binary::writeUnsignedVarInt(strlen($pk->getBuffer())) . $pk->getBuffer(), ZLIB_ENCODING_DEFLATE, Server::getInstance()->networkCompressionLevel); + + $batch->encode(); + $batch->isEncoded = true; + return $batch; + } + + public function setMetadata($metadataKey, MetadataValue $metadataValue){ + $this->server->getLevelMetadata()->setMetadata($this, $metadataKey, $metadataValue); } - public function getepilogos($epilogosKey){ - return $this->server->getLevelepilogos()->getepilogos($this, $epilogosKey); + public function getMetadata($metadataKey){ + return $this->server->getLevelMetadata()->getMetadata($this, $metadataKey); } - public function hasepilogos($epilogosKey){ - return $this->server->getLevelepilogos()->hasepilogos($this, $epilogosKey); + public function hasMetadata($metadataKey){ + return $this->server->getLevelMetadata()->hasMetadata($this, $metadataKey); } - public function removeepilogos($epilogosKey, Plugin $plugin){ - $this->server->getLevelepilogos()->removeepilogos($this, $epilogosKey, $plugin); + public function removeMetadata($metadataKey, Plugin $plugin){ + $this->server->getLevelMetadata()->removeMetadata($this, $metadataKey, $plugin); } - public function addEntityMotion($chunkX, $chunkZ, $entityId, $x, $y, $z){ + public function addEntityMotion(int $chunkX, int $chunkZ, int $entityId, float $x, float $y, float $z){ if(!isset($this->motionToSend[$index = Level::chunkHash($chunkX, $chunkZ)])){ $this->motionToSend[$index] = []; } $this->motionToSend[$index][$entityId] = [$entityId, $x, $y, $z]; } - public function addEntityMovement($chunkX, $chunkZ, $entityId, $x, $y, $z, $yaw, $pitch, $headYaw = null){ + public function addEntityMovement(int $chunkX, int $chunkZ, int $entityId, float $x, float $y, float $z, float $yaw, float $pitch, $headYaw = null){ if(!isset($this->moveToSend[$index = Level::chunkHash($chunkX, $chunkZ)])){ $this->moveToSend[$index] = []; } diff --git a/src/devmine/levels/Location.php b/src/devmine/worlds/Location.php similarity index 58% rename from src/devmine/levels/Location.php rename to src/devmine/worlds/Location.php index 9c6f77b..09a3687 100644 --- a/src/devmine/levels/Location.php +++ b/src/devmine/worlds/Location.php @@ -2,7 +2,7 @@ -namespace devmine\levels; +namespace devmine\worlds; use devmine\server\calculations\Vector3; @@ -37,15 +37,7 @@ public function __construct($x = 0, $y = 0, $z = 0, $yaw = 0.0, $pitch = 0.0, Le * @return Location */ public static function fromObject(Vector3 $pos, Level $level = null, $yaw = 0.0, $pitch = 0.0){ - return new Location($pos->x, $pos->y, $pos->z, $yaw, $pitch, ($level === null) ? (($pos instanceof Position) ? $pos->level : null) : $level); - } - - public function add($x, $y = 0, $z = 0, $yaw = 0, $pitch = 0){ - if($x instanceof Location){ - return new Location($this->x + $x->x, $this->y + $x->y, $this->z + $x->z, $this->yaw + $x->yaw, $this->pitch + $x->pitch, $this->level); - }else{ - return new Location($this->x + $x, $this->y + $y, $this->z + $z, $this->yaw + $yaw, $this->pitch + $pitch, $this->level); - } + return new Location($pos->x, $pos->y, $pos->z, $yaw, $pitch, $level ?? (($pos instanceof Position) ? $pos->level : null)); } public function getYaw(){ @@ -56,15 +48,6 @@ public function getPitch(){ return $this->pitch; } - public function fromObjectAdd(Vector3 $pos, $x, $y, $z){ - if($pos instanceof Location){ - $this->yaw = $pos->yaw; - $this->pitch = $pos->pitch; - } - parent::fromObjectAdd($pos, $x, $y, $z); - return $this; - } - public function __toString(){ return "Location (level=" . ($this->isValid() ? $this->getLevel()->getName() : "null") . ", x=$this->x, y=$this->y, z=$this->z, yaw=$this->yaw, pitch=$this->pitch)"; } diff --git a/src/devmine/levels/MovingObjectPosition.php b/src/devmine/worlds/MovingObjectPosition.php similarity index 98% rename from src/devmine/levels/MovingObjectPosition.php rename to src/devmine/worlds/MovingObjectPosition.php index 7f2d408..76913f5 100644 --- a/src/devmine/levels/MovingObjectPosition.php +++ b/src/devmine/worlds/MovingObjectPosition.php @@ -2,7 +2,7 @@ -namespace devmine\levels; +namespace devmine\worlds; use devmine\creatures\entities\Entity; use devmine\server\calculations\Vector3; diff --git a/src/devmine/levels/Position.php b/src/devmine/worlds/Position.php similarity index 59% rename from src/devmine/levels/Position.php rename to src/devmine/worlds/Position.php index f9a9cae..a550d7a 100644 --- a/src/devmine/levels/Position.php +++ b/src/devmine/worlds/Position.php @@ -2,7 +2,7 @@ -namespace devmine\levels; +namespace devmine\worlds; use devmine\server\calculations\Vector3; use devmine\utilities\main\LevelException; @@ -28,14 +28,6 @@ public function __construct($x = 0, $y = 0, $z = 0, Level $level = null){ public static function fromObject(Vector3 $pos, Level $level = null){ return new Position($pos->x, $pos->y, $pos->z, $level); } - - public function add($x, $y = 0, $z = 0){ - if($x instanceof Vector3){ - return new Position($this->x + $x->x, $this->y + $x->y, $this->z + $x->z, $this->level); - }else{ - return new Position($this->x + $x, $this->y + $y, $this->z + $z, $this->level); - } - } /** * @return Level @@ -55,31 +47,7 @@ public function setLevel(Level $level){ * @return bool */ public function isValid(){ - return $this->level !== null; - } - - /** - * Marks the level reference as strong so it won't be collected - * by the garbage collector. - * - * @deprecated - * - * @return bool - */ - public function setStrong(){ - return false; - } - - /** - * Marks the level reference as weak so it won't have effect against - * the garbage collector decision. - * - * @deprecated - * - * @return bool - */ - public function setWeak(){ - return false; + return $this->getLevel() instanceof Level; } /** @@ -93,9 +61,7 @@ public function setWeak(){ * @throws LevelException */ public function getSide($side, $step = 1){ - if(!$this->isValid()){ - throw new LevelException("Undefined Level reference"); - } + assert($this->isValid()); return Position::fromObject(parent::getSide($side, $step), $this->level); } @@ -118,12 +84,4 @@ public function setComponents($x, $y, $z){ return $this; } - public function fromObjectAdd(Vector3 $pos, $x, $y, $z){ - if($pos instanceof Position){ - $this->level = $pos->level; - } - parent::fromObjectAdd($pos, $x, $y, $z); - return $this; - } - } diff --git a/src/devmine/worlds/SimpleChunkManager.php b/src/devmine/worlds/SimpleChunkManager.php new file mode 100644 index 0000000..61d348f --- /dev/null +++ b/src/devmine/worlds/SimpleChunkManager.php @@ -0,0 +1,117 @@ +seed = $seed; + } + + /** + * Gets the raw block id. + * + * @param int $x + * @param int $y + * @param int $z + * + * @return int 0-255 + */ + public function getBlockIdAt(int $x, int $y, int $z) : int{ + if($chunk = $this->getChunk($x >> 4, $z >> 4)){ + return $chunk->getBlockId($x & 0xf, $y & Level::Y_MASK, $z & 0xf); + } + return 0; + } + + /** + * Sets the raw block id. + * + * @param int $x + * @param int $y + * @param int $z + * @param int $id 0-255 + */ + public function setBlockIdAt(int $x, int $y, int $z, int $id){ + if($chunk = $this->getChunk($x >> 4, $z >> 4)){ + $chunk->setBlockId($x & 0xf, $y & Level::Y_MASK, $z & 0xf, $id); + } + } + + /** + * Gets the raw block metadata + * + * @param int $x + * @param int $y + * @param int $z + * + * @return int 0-15 + */ + public function getBlockDataAt(int $x, int $y, int $z) : int{ + if($chunk = $this->getChunk($x >> 4, $z >> 4)){ + return $chunk->getBlockData($x & 0xf, $y & Level::Y_MASK, $z & 0xf); + } + return 0; + } + + /** + * Sets the raw block metadata. + * + * @param int $x + * @param int $y + * @param int $z + * @param int $data 0-15 + */ + public function setBlockDataAt(int $x, int $y, int $z, int $data){ + if($chunk = $this->getChunk($x >> 4, $z >> 4)){ + $chunk->setBlockData($x & 0xf, $y & Level::Y_MASK, $z & 0xf, $data); + } + } + + /** + * @param int $chunkX + * @param int $chunkZ + * + * @return Chunk|null + */ + public function getChunk(int $chunkX, int $chunkZ){ + return $this->chunks[Level::chunkHash($chunkX, $chunkZ)] ?? null; + } + + /** + * @param int $chunkX + * @param int $chunkZ + * @param Chunk $chunk + */ + public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk = null){ + if($chunk === null){ + unset($this->chunks[Level::chunkHash($chunkX, $chunkZ)]); + return; + } + $this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk; + } + + public function cleanChunks(){ + $this->chunks = []; + } + + /** + * Gets the level seed + * + * @return int + */ + public function getSeed(){ + return $this->seed; + } +} \ No newline at end of file diff --git a/src/devmine/worlds/WeakPosition.php b/src/devmine/worlds/WeakPosition.php new file mode 100644 index 0000000..71d3d12 --- /dev/null +++ b/src/devmine/worlds/WeakPosition.php @@ -0,0 +1,63 @@ +x = $x; + $this->y = $y; + $this->z = $z; + $this->levelId = ($level !== null ? $level->getId() : -1); + } + + public static function fromObject(Vector3 $pos, Level $level = null){ + return new WeakPosition($pos->x, $pos->y, $pos->z, $level); + } + + /** + * @return Level|null + */ + public function getLevel(){ + return Server::getInstance()->getLevel($this->levelId); + } + + public function setLevel(Level $level){ + $this->levelId = ($level !== null ? $level->getId() : -1); + return $this; + } + + /** + * Returns a side Vector + * + * @param int $side + * @param int $step + * + * @return WeakPosition + * + * @throws LevelException + */ + public function getSide($side, $step = 1){ + assert($this->isValid()); + + return WeakPosition::fromObject(parent::getSide($side, $step), $this->level); + } + + public function __toString(){ + return "Weak" . parent::__toString(); + } +} \ No newline at end of file diff --git a/src/devmine/worlds/format/Chunk.php b/src/devmine/worlds/format/Chunk.php new file mode 100644 index 0000000..0f04581 --- /dev/null +++ b/src/devmine/worlds/format/Chunk.php @@ -0,0 +1,376 @@ +level = $level; $this->path = $path; if(!file_exists($this->path)){ @@ -47,7 +50,7 @@ public function __construct(Level $level, $path){ } } - public function getPath(){ + public function getPath() : string{ return $this->path; } @@ -68,7 +71,7 @@ public function getTime(){ } public function setTime($value){ - $this->levelData->Time = new IntTag("Time", (int) $value); + $this->levelData->Time = new LongTag("Time", $value); } public function getSeed(){ @@ -76,10 +79,10 @@ public function getSeed(){ } public function setSeed($value){ - $this->levelData->RandomSeed = new LongTag("RandomSeed", (int) $value); + $this->levelData->RandomSeed = new LongTag("RandomSeed", $value); } - public function getSpawn(){ + public function getSpawn() : Vector3{ return new Vector3((float) $this->levelData["SpawnX"], (float) $this->levelData["SpawnY"], (float) $this->levelData["SpawnZ"]); } @@ -96,7 +99,7 @@ public function doGarbageCollection(){ /** * @return CompoundTag */ - public function getLevelData(){ + public function getLevelData() : CompoundTag{ return $this->levelData; } @@ -109,5 +112,12 @@ public function saveLevelData(){ file_put_contents($this->getPath() . "level.dat", $buffer); } + public function requestChunkTask(int $x, int $z){ + $chunk = $this->getChunk($x, $z, false); + if(!($chunk instanceof GenericChunk)){ + throw new ChunkException("Invalid Chunk sent"); + } -} \ No newline at end of file + $this->getLevel()->chunkRequestCallback($x, $z, $chunk->networkSerialize()); + } +} diff --git a/src/devmine/worlds/format/generic/ChunkRequestTask.php b/src/devmine/worlds/format/generic/ChunkRequestTask.php new file mode 100644 index 0000000..dca60c2 --- /dev/null +++ b/src/devmine/worlds/format/generic/ChunkRequestTask.php @@ -0,0 +1,59 @@ +levelId = $level->getId(); + + $this->chunk = $chunk->fastSerialize(); + $this->chunkX = $chunk->getX(); + $this->chunkZ = $chunk->getZ(); + + //TODO: serialize tiles with chunks + $tiles = ""; + $nbt = new NBT(NBT::LITTLE_ENDIAN); + foreach($chunk->getTiles() as $tile){ + if($tile instanceof Spawnable){ + $nbt->setData($tile->getSpawnCompound()); + $tiles .= $nbt->write(true); + } + } + + $this->tiles = $tiles; + } + + public function onRun(){ + $chunk = GenericChunk::fastDeserialize($this->chunk); + + $ordered = $chunk->networkSerialize(); + + $this->setResult($ordered, false); + } + + public function onCompletion(Server $server){ + $level = $server->getLevel($this->levelId); + if($level instanceof Level and $this->hasResult()){ + $level->chunkRequestCallback($this->chunkX, $this->chunkZ, $this->getResult()); + } + } + +} \ No newline at end of file diff --git a/src/devmine/worlds/format/generic/EmptySubChunk.php b/src/devmine/worlds/format/generic/EmptySubChunk.php new file mode 100644 index 0000000..2ddab72 --- /dev/null +++ b/src/devmine/worlds/format/generic/EmptySubChunk.php @@ -0,0 +1,98 @@ +provider = $provider; + $this->x = $chunkX; + $this->z = $chunkZ; + + $this->height = $provider !== null ? ($provider->getWorldHeight() >> 4) : 16; + + $this->emptySubChunk = new EmptySubChunk(); + + foreach($subChunks as $y => $subChunk){ + if($y < 0 or $y >= $this->height){ + throw new ChunkException("Invalid subchunk index $y!"); + } + if($subChunk->isEmpty()){ + $this->subChunks[$y] = $this->emptySubChunk; + }else{ + $this->subChunks[$y] = $subChunk; + } + } + + for($i = 0; $i < $this->height; ++$i){ + if(!isset($this->subChunks[$i])){ + $this->subChunks[$i] = $this->emptySubChunk; + } + } + + if(count($heightMap) === 256){ + $this->heightMap = $heightMap; + }else{ + assert(count($heightMap) === 0, "Wrong HeightMap value count, expected 256, got " . count($heightMap)); + $val = ($this->height * 16) - 1; + $this->heightMap = array_fill(0, 256, $val); + } + + if(strlen($biomeIds) === 256){ + $this->biomeIds = $biomeIds; + }else{ + assert(strlen($biomeIds) === 0, "Wrong BiomeIds value count, expected 256, got " . strlen($biomeIds)); + $this->biomeIds = str_repeat("\x00", 256); + } + + $this->NBTtiles = $tiles; + $this->NBTentities = $entities; + } + + public function getX() : int{ + return $this->x; + } + + public function getZ() : int{ + return $this->z; + } + + public function setX(int $x){ + $this->x = $x; + } + + public function setZ(int $z){ + $this->z = $z; + } + + public function getProvider(){ + return $this->provider; + } + + public function setProvider(LevelProvider $provider){ + $this->provider = $provider; + } + + public function getHeight() : int{ + return $this->height; + } + + public function getFullBlock(int $x, int $y, int $z) : int{ + return $this->getSubChunk($y >> 4)->getFullBlock($x, $y & 0x0f, $z); + } + + public function setBlock(int $x, int $y, int $z, $blockId = null, $meta = null) : bool{ + if($this->getSubChunk($y >> 4, true)->setBlock($x, $y & 0x0f, $z, $blockId !== null ? ($blockId & 0xff) : null, $meta !== null ? ($meta & 0x0f) : null)){ + $this->hasChanged = true; + return true; + } + return false; + } + + public function getBlockId(int $x, int $y, int $z) : int{ + return $this->getSubChunk($y >> 4)->getBlockId($x, $y & 0x0f, $z); + } + + public function setBlockId(int $x, int $y, int $z, int $id){ + if($this->getSubChunk($y >> 4, true)->setBlockId($x, $y & 0x0f, $z, $id)){ + $this->hasChanged = true; + } + } + + public function getBlockData(int $x, int $y, int $z) : int{ + return $this->getSubChunk($y >> 4)->getBlockData($x, $y & 0x0f, $z); + } + + public function setBlockData(int $x, int $y, int $z, int $data){ + if($this->getSubChunk($y >> 4)->setBlockData($x, $y & 0x0f, $z, $data)){ + $this->hasChanged = true; + } + } + + public function getBlockExtraData(int $x, int $y, int $z) : int{ + return $this->extraData[GenericChunk::chunkBlockHash($x, $y, $z)] ?? 0; + } + + public function setBlockExtraData(int $x, int $y, int $z, int $data){ + if($data === 0){ + unset($this->extraData[GenericChunk::chunkBlockHash($x, $y, $z)]); + }else{ + $this->extraData[GenericChunk::chunkBlockHash($x, $y, $z)] = $data; + } + + $this->hasChanged = true; + } + + public function getBlockSkyLight(int $x, int $y, int $z) : int{ + return $this->getSubChunk($y >> 4)->getBlockSkyLight($x, $y & 0x0f, $z); + } + + public function setBlockSkyLight(int $x, int $y, int $z, int $level){ + if($this->getSubChunk($y >> 4)->setBlockSkyLight($x, $y & 0x0f, $z, $level)){ + $this->hasChanged = true; + } + } + + public function getBlockLight(int $x, int $y, int $z) : int{ + return $this->getSubChunk($y >> 4)->getBlockLight($x, $y & 0x0f, $z); + } + + public function setBlockLight(int $x, int $y, int $z, int $level){ + if($this->getSubChunk($y >> 4)->setBlockLight($x, $y & 0x0f, $z, $level)){ + $this->hasChanged = true; + } + } + + public function getHighestBlockAt(int $x, int $z, bool $useHeightMap = true) : int{ + if($useHeightMap){ + $height = $this->getHeightMap($x, $z); + + if($height !== 0 and $height !== 255){ + return $height; + } + } + + $index = $this->getHighestSubChunkIndex(); + if($index < 0){ + return 0; + } + + $height = $index << 4; + + for($y = $index; $y >= 0; --$y){ + $height = $this->getSubChunk($y)->getHighestBlockAt($x, $z) | ($y << 4); + if($height !== -1){ + break; + } + } + + $this->setHeightMap($x, $z, $height); + return $height; + } + + public function getHeightMap(int $x, int $z) : int{ + return $this->heightMap[($z << 4) | $x]; + } + + public function setHeightMap(int $x, int $z, int $value){ + $this->heightMap[($z << 4) | $x] = $value; + } + + public function recalculateHeightMap(){ + for($z = 0; $z < 16; ++$z){ + for($x = 0; $x < 16; ++$x){ + $this->setHeightMap($x, $z, $this->getHighestBlockAt($x, $z, false)); + } + } + } + + public function populateSkyLight(){ + //TODO: rewrite this, use block light filters and diffusion, actual proper sky light population + for($x = 0; $x < 16; ++$x){ + for($z = 0; $z < 16; ++$z){ + $heightMap = $this->getHeightMap($x, $z); + + $y = min(($this->getHighestSubChunkIndex() + 1) << 4, $heightMap); + + for(; $y > $heightMap; --$y){ + $this->setBlockSkyLight($x, $y, $z, 15); + } + + for(; $y > 0; --$y){ + if($this->getBlockId($x, $y, $z) !== Block::AIR){ + break; + } + + $this->setBlockSkyLight($x, $y, $z, 15); + } + + $this->setHeightMap($x, $z, $y); + } + } + } + + public function getBiomeId(int $x, int $z) : int{ + return ord($this->biomeIds{($z << 4) | $x}); + } + + public function setBiomeId(int $x, int $z, int $biomeId){ + $this->hasChanged = true; + $this->biomeIds{($z << 4) | $x} = chr($biomeId & 0xff); + } + + public function getBlockIdColumn(int $x, int $z) : string{ + $result = ""; + foreach($this->subChunks as $subChunk){ + $result .= $subChunk->getBlockIdColumn($x, $z); + } + return $result; + } + + public function getBlockDataColumn(int $x, int $z) : string{ + $result = ""; + foreach($this->subChunks as $subChunk){ + $result .= $subChunk->getBlockDataColumn($x, $z); + } + return $result; + } + + public function getBlockSkyLightColumn(int $x, int $z) : string{ + $result = ""; + foreach($this->subChunks as $subChunk){ + $result .= $subChunk->getSkyLightColumn($x, $z); + } + return $result; + } + + public function getBlockLightColumn(int $x, int $z) : string{ + $result = ""; + foreach($this->subChunks as $subChunk){ + $result .= $subChunk->getBlockLightColumn($x, $z); + } + return $result; + } + + public function isLightPopulated() : bool{ + return $this->lightPopulated; + } + + public function setLightPopulated(bool $value = true){ + $this->lightPopulated = $value; + } + + public function isPopulated() : bool{ + return $this->terrainPopulated; + } + + public function setPopulated(bool $value = true){ + $this->terrainPopulated = $value; + } + + public function isGenerated() : bool{ + return $this->terrainGenerated; + } + + public function setGenerated(bool $value = true){ + $this->terrainGenerated = $value; + } + + public function addEntity(Entity $entity){ + $this->entities[$entity->getId()] = $entity; + if(!($entity instanceof Player) and $this->isInit){ + $this->hasChanged = true; + } + } + + public function removeEntity(Entity $entity){ + unset($this->entities[$entity->getId()]); + if(!($entity instanceof Player) and $this->isInit){ + $this->hasChanged = true; + } + } + + public function addTile(Tile $tile){ + $this->tiles[$tile->getId()] = $tile; + if(isset($this->tileList[$index = (($tile->x & 0x0f) << 12) | (($tile->z & 0x0f) << 8) | ($tile->y & 0xff)]) and $this->tileList[$index] !== $tile){ + $this->tileList[$index]->close(); + } + $this->tileList[$index] = $tile; + if($this->isInit){ + $this->hasChanged = true; + } + } + + public function removeTile(Tile $tile){ + unset($this->tiles[$tile->getId()]); + unset($this->tileList[(($tile->x & 0x0f) << 12) | (($tile->z & 0x0f) << 8) | ($tile->y & 0xff)]); + if($this->isInit){ + $this->hasChanged = true; + } + } + + public function getEntities() : array{ + return $this->entities; + } + + public function getTiles() : array{ + return $this->tiles; + } + + public function getTile(int $x, int $y, int $z){ + $index = ($x << 12) | ($z << 8) | $y; + return $this->tileList[$index] ?? null; + } + + public function isLoaded() : bool{ + return $this->getProvider() === null ? false : $this->getProvider()->isChunkLoaded($this->getX(), $this->getZ()); + } + + public function load(bool $generate = true) : bool{ + return $this->getProvider() === null ? false : $this->getProvider()->getChunk($this->getX(), $this->getZ(), true) instanceof GenericChunk; + } + + public function unload(bool $save = true, bool $safe = true) : bool{ + $level = $this->getProvider(); + if($level === null){ + return true; + } + if($save === true and $this->hasChanged){ + $level->saveChunk($this->getX(), $this->getZ()); + } + if($safe === true){ + foreach($this->getEntities() as $entity){ + if($entity instanceof Player){ + return false; + } + } + } + + foreach($this->getEntities() as $entity){ + if($entity instanceof Player){ + continue; + } + $entity->close(); + } + foreach($this->getTiles() as $tile){ + $tile->close(); + } + $this->provider = null; + return true; + } + + public function initChunk(){ + if($this->getProvider() instanceof LevelProvider and !$this->isInit){ + $changed = false; + if($this->NBTentities !== null){ + $this->getProvider()->getLevel()->timings->syncChunkLoadEntitiesTimer->startTiming(); + foreach($this->NBTentities as $nbt){ + if($nbt instanceof CompoundTag){ + if(!isset($nbt->id)){ + $changed = true; + continue; + } + + if(($nbt["Pos"][0] >> 4) !== $this->x or ($nbt["Pos"][2] >> 4) !== $this->z){ + $changed = true; + continue; //Fixes entities allocated in wrong chunks. + } + + if(($entity = Entity::createEntity($nbt["id"], $this, $nbt)) instanceof Entity){ + $entity->spawnToAll(); + }else{ + $changed = true; + continue; + } + } + } + $this->getProvider()->getLevel()->timings->syncChunkLoadEntitiesTimer->stopTiming(); + + $this->getProvider()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->startTiming(); + foreach($this->NBTtiles as $nbt){ + if($nbt instanceof CompoundTag){ + if(!isset($nbt->id)){ + $changed = true; + continue; + } + + if(($nbt["x"] >> 4) !== $this->x or ($nbt["z"] >> 4) !== $this->z){ + $changed = true; + continue; //Fixes tiles allocated in wrong chunks. + } + + if(Tile::createTile($nbt["id"], $this, $nbt) === null){ + $changed = true; + continue; + } + } + } + + $this->getProvider()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->stopTiming(); + + $this->NBTentities = null; + $this->NBTtiles = null; + } + + $this->hasChanged = $changed; + + $this->isInit = true; + } + } + + public function getBiomeIdArray() : string{ + return $this->biomeIds; + } + + public function getHeightMapArray() : array{ + return $this->heightMap; + } + + public function getBlockExtraDataArray() : array{ + return $this->extraData; + } + + public function hasChanged() : bool{ + return $this->hasChanged; + } + + public function setChanged(bool $value = true){ + $this->hasChanged = $value; + } + + public function getSubChunk(int $y, bool $generateNew = false) : SubChunk{ + if($y < 0 or $y >= $this->height){ + return $this->emptySubChunk; + }elseif($generateNew and $this->subChunks[$y] instanceof EmptySubChunk){ + $this->subChunks[$y] = new SubChunk(); + } + assert($this->subChunks[$y] !== null, "Somehow something broke, no such subchunk at index $y"); + return $this->subChunks[$y]; + } + + public function setSubChunk(int $y, SubChunk $subChunk = null, bool $allowEmpty = false) : bool{ + if($y < 0 or $y >= $this->height){ + return false; + } + if($subChunk === null or ($subChunk->isEmpty() and !$allowEmpty)){ + $this->subChunks[$y] = $this->emptySubChunk; + }else{ + $this->subChunks[$y] = $subChunk; + } + $this->hasChanged = true; + return true; + } + + public function getSubChunks() : array{ + return $this->subChunks; + } + + public function getHighestSubChunkIndex() : int{ + for($y = count($this->subChunks) - 1; $y >= 0; --$y){ + if($this->subChunks[$y] === null or $this->subChunks[$y] instanceof EmptySubChunk){ + //No need to thoroughly prune empties at runtime, this will just reduce performance. + continue; + } + break; + } + + return $y; + } + + public function getSubChunkSendCount() : int{ + return $this->getHighestSubChunkIndex() + 1; + } + + public function pruneEmptySubChunks(){ + foreach($this->subChunks as $y => $subChunk){ + if($y < 0 or $y >= $this->height){ + assert(false, "Invalid subchunk index"); + unset($this->subChunks[$y]); + }elseif($subChunk instanceof EmptySubChunk){ + continue; + }elseif($subChunk->isEmpty()){ //normal subchunk full of air, remove it and replace it with an empty stub + $this->subChunks[$y] = $this->emptySubChunk; + }else{ + continue; //do not set changed + } + $this->hasChanged = true; + } + } + + public function networkSerialize() : string{ + $result = ""; + $subChunkCount = $this->getSubChunkSendCount(); + $result .= chr($subChunkCount); + for($y = 0; $y < $subChunkCount; ++$y){ + $result .= $this->subChunks[$y]->networkSerialize(); + } + $result .= pack("v*", ...$this->heightMap) + . $this->biomeIds + . chr(0); //border block array count + //Border block entry format: 1 byte (4 bits X, 4 bits Z). These are however useless since they crash the regular client. + + $extraData = new BinaryStream(); + $extraData->putVarInt(count($this->extraData)); //WHY, Mojang, WHY + foreach($this->extraData as $key => $value){ + $extraData->putVarInt($key); + $extraData->putLShort($value); + } + $result .= $extraData->getBuffer(); + + if(count($this->tiles) > 0){ + $nbt = new NBT(NBT::LITTLE_ENDIAN); + $list = []; + foreach($this->tiles as $tile){ + if($tile instanceof Spawnable){ + $list[] = $tile->getSpawnCompound(); + } + } + $nbt->setData($list); + $result .= $nbt->write(true); + } + + return $result; + } + + public function fastSerialize() : string{ + $stream = new BinaryStream(); + $stream->putInt($this->x); + $stream->putInt($this->z); + $count = 0; + $subChunks = ""; + foreach($this->subChunks as $y => $subChunk){ + if($subChunk instanceof EmptySubChunk){ + continue; + } + ++$count; + $subChunks .= chr($y) . $subChunk->fastSerialize(); + } + $stream->putByte($count); + $stream->put($subChunks); + $stream->put(pack("C*", ...$this->heightMap) . + $this->biomeIds . + chr(($this->lightPopulated ? 1 << 2 : 0) | ($this->terrainPopulated ? 1 << 1 : 0) | ($this->terrainGenerated ? 1 : 0))); + //TODO: tiles and entities + return $stream->getBuffer(); + } + + public static function fastDeserialize(string $data, LevelProvider $provider = null){ + $stream = new BinaryStream(); + $stream->setBuffer($data); + $data = null; + $x = $stream->getInt(); + $z = $stream->getInt(); + $subChunks = []; + $count = $stream->getByte(); + for($y = 0; $y < $count; ++$y){ + $subChunks[$stream->getByte()] = SubChunk::fastDeserialize($stream->get(10240)); + } + $heightMap = array_values(unpack("C*", $stream->get(256))); + $biomeIds = $stream->get(256); + + $chunk = new GenericChunk($provider, $x, $z, $subChunks, [], [], $biomeIds, $heightMap); + $flags = $stream->getByte(); + $chunk->lightPopulated = (bool) ($flags & 4); + $chunk->terrainPopulated = (bool) ($flags & 2); + $chunk->terrainGenerated = (bool) ($flags & 1); + return $chunk; + } + + //TODO: get rid of this + public static function getEmptyChunk(int $x, int $z, LevelProvider $provider = null) : Chunk{ + return new GenericChunk($provider, $x, $z); + } + + /** + * Creates a block hash from chunk block coordinates. Used for extra data keys in chunk packets. + * @internal + * + * @param int $x 0-15 + * @param int $y 0-255 + * @param int $z 0-15 + * + * @return int + */ + public static function chunkBlockHash(int $x, int $y, int $z) : int{ + return ($x << 12) | ($z << 8) | $y; + } + + /** + * Re-orders a byte array (YZX -> XZY and vice versa) + * + * @param string $array length 4096 + * + * @return string length 4096 + */ + public static final function reorderByteArray(string $array) : string{ + $result = str_repeat("\x00", 4096); + $i = 0; + for($x = 0; $x < 16; ++$x){ + for($z = 0; $z < 256; $z += 16){ + $zx = ($z + $x); + for($y = 0; $y < 4096; $y += 256){ + $result{$i} = $array{$y + $zx}; + ++$i; + } + } + } + return $result; + } + + /** + * Re-orders a nibble array (YZX -> XZY and vice versa) + * + * @param string $array length 2048 + * + * @return string length 2048 + */ + public static final function reorderNibbleArray(string $array) : string{ + $result = str_repeat("\x00", 2048); + $i = 0; + for($x = 0; $x < 8; ++$x){ + for($z = 0; $z < 16; ++$z){ + $zx = (($z << 3) | $x); + for($y = 0; $y < 8; ++$y){ + $j = (($y << 8) | $zx); + $i1 = ord($array{$j}); + $i2 = ord($array{$j | 0x80}); + $result{$i} = chr(($i2 << 4) | ($i1 & 0x0f)); + $result{$i | 0x80} = chr(($i1 >> 4) | ($i2 & 0xf0)); + $i++; + } + } + $i += 128; + } + return $result; + } + + /** + * Converts pre-MCPE-1.0 biome colour array to biome ID array. RIP BiomeColors :( + * + * @param int[] $array of biome colour values + * + * @return string + */ + public static function convertBiomeColours(array $array) : string{ + $result = str_repeat("\x00", 256); + foreach($array as $i => $colour){ + $result{$i} = chr(($array[$i] >> 24) & 0xff); + } + return $result; + } + +} diff --git a/src/devmine/worlds/format/generic/SubChunk.php b/src/devmine/worlds/format/generic/SubChunk.php new file mode 100644 index 0000000..fed52f6 --- /dev/null +++ b/src/devmine/worlds/format/generic/SubChunk.php @@ -0,0 +1,208 @@ +ids, $ids, 4096); + self::assignData($this->data, $data, 2048); + self::assignData($this->skyLight, $skyLight, 2048); + self::assignData($this->blockLight, $blockLight, 2048); + } + + public function isEmpty() : bool{ + assert(strlen($this->ids) === 4096, "Wrong length of ID array, expecting 4096 bytes, got " . strlen($this->ids)); + return substr_count($this->ids, "\x00") === 4096; + } + + public function getBlockId(int $x, int $y, int $z) : int{ + return ord($this->ids{($x << 8) | ($z << 4) | $y}); + } + + public function setBlockId(int $x, int $y, int $z, int $id) : bool{ + $this->ids{($x << 8) | ($z << 4) | $y} = chr($id); + return true; + } + + public function getBlockData(int $x, int $y, int $z) : int{ + $m = ord($this->data{($x << 7) + ($z << 3) + ($y >> 1)}); + if(($y & 1) === 0){ + return $m & 0x0f; + }else{ + return $m >> 4; + } + } + + public function setBlockData(int $x, int $y, int $z, int $data) : bool{ + $i = ($x << 7) | ($z << 3) | ($y >> 1); + if(($y & 1) === 0){ + $this->data{$i} = chr((ord($this->data{$i}) & 0xf0) | ($data & 0x0f)); + }else{ + $this->data{$i} = chr((($data & 0x0f) << 4) | (ord($this->data{$i}) & 0x0f)); + } + return true; + } + + public function getFullBlock(int $x, int $y, int $z) : int{ + $i = ($x << 8) | ($z << 4) | $y; + if(($y & 1) === 0){ + return (ord($this->ids{$i}) << 4) | (ord($this->data{$i >> 1}) & 0x0f); + }else{ + return (ord($this->ids{$i}) << 4) | (ord($this->data{$i >> 1}) >> 4); + } + } + + public function setBlock(int $x, int $y, int $z, $id = null, $data = null) : bool{ + $i = ($x << 8) | ($z << 4) | $y; + $changed = false; + if($id !== null){ + $block = chr($id); + if($this->ids{$i} !== $block){ + $this->ids{$i} = $block; + $changed = true; + } + } + + if($data !== null){ + $i >>= 1; + $byte = ord($this->data{$i}); + if(($y & 1) === 0){ + $this->data{$i} = chr(($byte & 0xf0) | ($data & 0x0f)); + }else{ + $this->data{$i} = chr((($data & 0x0f) << 4) | ($byte & 0x0f)); + } + if($this->data{$i} !== $byte){ + $changed = true; + } + } + + return $changed; + } + + public function getBlockLight(int $x, int $y, int $z) : int{ + $byte = ord($this->blockLight{($x << 7) + ($z << 3) + ($y >> 1)}); + if(($y & 1) === 0){ + return $byte & 0x0f; + }else{ + return $byte >> 4; + } + } + + public function setBlockLight(int $x, int $y, int $z, int $level) : bool{ + $i = ($x << 7) + ($z << 3) + ($y >> 1); + $byte = ord($this->blockLight{$i}); + if(($y & 1) === 0){ + $this->blockLight{$i} = chr(($byte & 0xf0) | ($level & 0x0f)); + }else{ + $this->blockLight{$i} = chr((($level & 0x0f) << 4) | ($byte & 0x0f)); + } + return true; + } + + public function getBlockSkyLight(int $x, int $y, int $z) : int{ + $byte = ord($this->skyLight{($x << 7) + ($z << 3) + ($y >> 1)}); + if(($y & 1) === 0){ + return $byte & 0x0f; + }else{ + return $byte >> 4; + } + } + + public function setBlockSkyLight(int $x, int $y, int $z, int $level) : bool{ + $i = ($x << 7) + ($z << 3) + ($y >> 1); + $byte = ord($this->skyLight{$i}); + if(($y & 1) === 0){ + $this->skyLight{$i} = chr(($byte & 0xf0) | ($level & 0x0f)); + }else{ + $this->skyLight{$i} = chr((($level & 0x0f) << 4) | ($byte & 0x0f)); + } + return true; + } + + public function getHighestBlockAt(int $x, int $z) : int{ + for($y = 15; $y >= 0; --$y){ + if($this->ids{($x << 8) | ($z << 4) | $y} !== "\x00"){ + return $y; + } + } + + return -1; //highest block not in this subchunk + } + + public function getBlockIdColumn(int $x, int $z) : string{ + return substr($this->ids, (($x << 8) | ($z << 4)), 16); + } + + public function getBlockDataColumn(int $x, int $z) : string{ + return substr($this->data, (($x << 7) | ($z << 3)), 8); + } + + public function getBlockLightColumn(int $x, int $z) : string{ + return substr($this->blockLight, (($x << 7) | ($z << 3)), 8); + } + + public function getSkyLightColumn(int $x, int $z) : string{ + return substr($this->skyLight, (($x << 7) | ($z << 3)), 8); + } + + public function getBlockIdArray() : string{ + assert(strlen($this->ids) === 4096, "Wrong length of ID array, expecting 4096 bytes, got " . strlen($this->ids)); + return $this->ids; + } + + public function getBlockDataArray() : string{ + assert(strlen($this->data) === 2048, "Wrong length of data array, expecting 2048 bytes, got " . strlen($this->data)); + return $this->data; + } + + public function getSkyLightArray() : string{ + assert(strlen($this->skyLight) === 2048, "Wrong length of skylight array, expecting 2048 bytes, got " . strlen($this->skyLight)); + return $this->skyLight; + } + + public function getBlockLightArray() : string{ + assert(strlen($this->blockLight) === 2048, "Wrong length of light array, expecting 2048 bytes, got " . strlen($this->blockLight)); + return $this->blockLight; + } + + public function networkSerialize() : string{ + // storage version, ids, data, skylight, blocklight + return "\x00" . $this->ids . $this->data . $this->skyLight . $this->blockLight; + } + + public function fastSerialize() : string{ + return + $this->ids . + $this->data . + $this->skyLight . + $this->blockLight; + } + + public static function fastDeserialize(string $data) : SubChunk{ + return new SubChunk( + substr($data, 0, 4096), //ids + substr($data, 4096, 2048), //data + substr($data, 6144, 2048), //sky light + substr($data, 8192, 2048) //block light + ); + } +} \ No newline at end of file diff --git a/src/devmine/levels/format/leveldb/Chunk.php b/src/devmine/worlds/format/leveldb/Chunk.php similarity index 85% rename from src/devmine/levels/format/leveldb/Chunk.php rename to src/devmine/worlds/format/leveldb/Chunk.php index 44ae377..90ced33 100644 --- a/src/devmine/levels/format/leveldb/Chunk.php +++ b/src/devmine/worlds/format/leveldb/Chunk.php @@ -2,16 +2,16 @@ -namespace devmine\levels\format\leveldb; +namespace devmine\worlds\format\leveldb; -use devmine\levels\format\generic\BaseFullChunk; -use devmine\levels\format\LevelProvider; +use devmine\worlds\format\generic\BaseChunk; +use devmine\worlds\format\LevelProvider; use devmine\creatures\player\NBT; -use devmine\Player; +use devmine\creatures\player; use devmine\utilities\main\Binary; use devmine\utilities\main\BinaryStream; -class Chunk extends BaseFullChunk{ +class Chunk extends BaseChunk{ const DATA_LENGTH = 16384 * (2 + 1 + 1 + 1) + 256 + 1024; @@ -19,7 +19,7 @@ class Chunk extends BaseFullChunk{ protected $isPopulated = false; protected $isGenerated = false; - public function __construct($level, $chunkX, $chunkZ, $terrain, array $entityData = null, array $solidentityData = null){ + public function __construct($level, $chunkX, $chunkZ, $terrain, array $entityData = null, array $tileData = null){ $offset = 0; $blocks = substr($terrain, $offset, 32768); @@ -43,7 +43,7 @@ public function __construct($level, $chunkX, $chunkZ, $terrain, array $entityDat } $offset += 1024; - parent::__construct($level, $chunkX, $chunkZ, $blocks, $data, $skyLight, $blockLight, $biomeColors, $heightMap, $entityData === null ? [] : $entityData, $solidentityData === null ? [] : $solidentityData); + parent::__construct($level, $chunkX, $chunkZ, $blocks, $data, $skyLight, $blockLight, $biomeColors, $heightMap, $entityData === null ? [] : $entityData, $tileData === null ? [] : $tileData); } public function getBlockId($x, $y, $z){ @@ -84,12 +84,6 @@ public function getFullBlock($x, $y, $z){ } } - public function getBlock($x, $y, $z, &$blockId, &$meta = null){ - $full = $this->getFullBlock($x, $y, $z); - $blockId = $full >> 4; - $meta = $full & 0x0f; - } - public function setBlock($x, $y, $z, $blockId = null, $meta = null){ $i = ($x << 11) | ($z << 7) | $y; @@ -243,7 +237,7 @@ public static function fromBinary($data, LevelProvider $provider = null){ $flags = ord(substr($data, -1)); $entities = null; - $solidentities = null; + $tiles = null; $extraData = []; if($provider instanceof LevelDB){ @@ -257,17 +251,17 @@ public static function fromBinary($data, LevelProvider $provider = null){ $entities = [$entities]; } } - $solidentityData = $provider->getDatabase()->get(substr($data, 0, 8) . LevelDB::ENTRY_solidentities); - if($solidentityData !== false and strlen($solidentityData) > 0){ - $nbt->read($solidentityData, true); - $solidentities = $nbt->getData(); - if(!is_array($solidentities)){ - $solidentities = [$solidentities]; + $tileData = $provider->getDatabase()->get(substr($data, 0, 8) . LevelDB::ENTRY_TILES); + if($tileData !== false and strlen($tileData) > 0){ + $nbt->read($tileData, true); + $tiles = $nbt->getData(); + if(!is_array($tiles)){ + $tiles = [$tiles]; } } - $solidentityData = $provider->getDatabase()->get(substr($data, 0, 8) . LevelDB::ENTRY_EXTRA_DATA); - if($solidentityData !== false and strlen($solidentityData) > 0){ - $stream = new BinaryStream($solidentityData); + $tileData = $provider->getDatabase()->get(substr($data, 0, 8) . LevelDB::ENTRY_EXTRA_DATA); + if($tileData !== false and strlen($tileData) > 0){ + $stream = new BinaryStream($tileData); $count = $stream->getInt(); for($i = 0; $i < $count; ++$i){ $key = $stream->getInt(); @@ -277,7 +271,7 @@ public static function fromBinary($data, LevelProvider $provider = null){ } } - $chunk = new Chunk($provider instanceof LevelProvider ? $provider : LevelDB::class, $chunkX, $chunkZ, $chunkData, $entities, $solidentities); + $chunk = new Chunk($provider instanceof LevelProvider ? $provider : LevelDB::class, $chunkX, $chunkZ, $chunkData, $entities, $tiles); if($flags & 0x01){ $chunk->setGenerated(); } @@ -320,20 +314,20 @@ public function toBinary($saveExtra = false){ } - $solidentities = []; + $tiles = []; - foreach($this->getsolidentities() as $solidentity){ - if(!$solidentity->closed){ - $solidentity->saveNBT(); - $solidentities[] = $solidentity->namedtag; + foreach($this->getTiles() as $tile){ + if(!$tile->closed){ + $tile->saveNBT(); + $tiles[] = $tile->namedtag; } } - if(count($solidentities) > 0){ - $nbt->setData($solidentities); - $provider->getDatabase()->put($chunkIndex . LevelDB::ENTRY_solidentities, $nbt->write()); + if(count($tiles) > 0){ + $nbt->setData($tiles); + $provider->getDatabase()->put($chunkIndex . LevelDB::ENTRY_TILES, $nbt->write()); }else{ - $provider->getDatabase()->delete($chunkIndex . LevelDB::ENTRY_solidentities); + $provider->getDatabase()->delete($chunkIndex . LevelDB::ENTRY_TILES); } if(count($this->getBlockExtraDataArray()) > 0){ diff --git a/src/devmine/levels/format/leveldb/LevelDB.php b/src/devmine/worlds/format/leveldb/LevelDB.php similarity index 92% rename from src/devmine/levels/format/leveldb/LevelDB.php rename to src/devmine/worlds/format/leveldb/LevelDB.php index 92dfa29..25000d2 100644 --- a/src/devmine/levels/format/leveldb/LevelDB.php +++ b/src/devmine/worlds/format/leveldb/LevelDB.php @@ -2,12 +2,12 @@ -namespace devmine\levels\format\leveldb; +namespace devmine\worlds\format\leveldb; -use devmine\levels\format\FullChunk; -use devmine\levels\format\generic\BaseLevelProvider; -use devmine\levels\generator\Generator; -use devmine\levels\Level; +use devmine\worlds\format\Chunk; +use devmine\worlds\format\generic\BaseLevelProvider; +use devmine\worlds\generator\Generator; +use devmine\worlds\Level; use devmine\creatures\player\NBT; use devmine\creatures\player\tag\ByteTag; use devmine\creatures\player\tag\CompoundTag; @@ -27,7 +27,7 @@ class LevelDB extends BaseLevelProvider{ const ENTRY_EXTRA_DATA = "4"; const ENTRY_TICKS = "3"; const ENTRY_ENTITIES = "2"; - const ENTRY_solidentities = "1"; + const ENTRY_TILES = "1"; const ENTRY_TERRAIN = "0"; /** @var Chunk[] */ @@ -129,12 +129,12 @@ public function requestChunkTask($x, $z){ throw new ChunkException("Invalid Chunk sent"); } - $solidentities = ""; + $tiles = ""; $nbt = new NBT(NBT::LITTLE_ENDIAN); - foreach($chunk->getsolidentities() as $solidentity){ - if($solidentity instanceof Spawnable){ - $nbt->setData($solidentity->getSpawnCompound()); - $solidentities .= $nbt->write(); + foreach($chunk->getTiles() as $tile){ + if($tile instanceof Spawnable){ + $nbt->setData($tile->getSpawnCompound()); + $tiles .= $nbt->write(); } } @@ -155,7 +155,7 @@ public function requestChunkTask($x, $z){ $heightmap . $biomeColors . $extraData->getBuffer() . - $solidentities; + $tiles; $this->getLevel()->chunkRequestCallback($x, $z, $ordered); @@ -197,7 +197,7 @@ public function loadChunk($chunkX, $chunkZ, $create = false){ } $this->level->timings->syncChunkLoadDataTimer->startTiming(); - $chunk = $this->readChunk($chunkX, $chunkZ); + $chunk = $this->readChunk($chunkX, $chunkZ, $create); if($chunk === null and $create){ $chunk = Chunk::getEmptyChunk($chunkX, $chunkZ, $this); } @@ -242,7 +242,7 @@ private function writeChunk(Chunk $chunk){ public function unloadChunk($x, $z, $safe = true){ $chunk = isset($this->chunks[$index = Level::chunkHash($x, $z)]) ? $this->chunks[$index] : null; - if($chunk instanceof FullChunk and $chunk->unload(false, $safe)){ + if($chunk instanceof Chunk and $chunk->unload(false, $safe)){ unset($this->chunks[$index]); return true; } @@ -285,7 +285,7 @@ public function getDatabase(){ return $this->db; } - public function setChunk($chunkX, $chunkZ, FullChunk $chunk){ + public function setChunk($chunkX, $chunkZ, Chunk $chunk){ if(!($chunk instanceof Chunk)){ throw new ChunkException("Invalid Chunk class"); } @@ -324,7 +324,7 @@ public function isChunkGenerated($chunkX, $chunkZ){ public function isChunkPopulated($chunkX, $chunkZ){ $chunk = $this->getChunk($chunkX, $chunkZ); - if($chunk instanceof FullChunk){ + if($chunk instanceof Chunk){ return $chunk->isPopulated(); }else{ return false; diff --git a/src/devmine/worlds/format/region/Anvil.php b/src/devmine/worlds/format/region/Anvil.php new file mode 100644 index 0000000..7ef9839 --- /dev/null +++ b/src/devmine/worlds/format/region/Anvil.php @@ -0,0 +1,153 @@ +xPos = new IntTag("xPos", $chunk->getX()); + $nbt->zPos = new IntTag("zPos", $chunk->getZ()); + + $nbt->V = new ByteTag("V", 1); + $nbt->LastUpdate = new LongTag("LastUpdate", 0); //TODO + $nbt->InhabitedTime = new LongTag("InhabitedTime", 0); //TODO + $nbt->TerrainPopulated = new ByteTag("TerrainPopulated", $chunk->isPopulated()); + $nbt->LightPopulated = new ByteTag("LightPopulated", $chunk->isLightPopulated()); + + $nbt->Sections = new ListTag("Sections", []); + $nbt->Sections->setTagType(NBT::TAG_Compound); + $subChunks = -1; + foreach($chunk->getSubChunks() as $y => $subChunk){ + if($subChunk->isEmpty()){ + continue; + } + $nbt->Sections[++$subChunks] = new CompoundTag(null, [ + "Y" => new ByteTag("Y", $y), + "Blocks" => new ByteArrayTag("Blocks", GenericChunk::reorderByteArray($subChunk->getBlockIdArray())), //Generic in-memory chunks are currently always XZY + "Data" => new ByteArrayTag("Data", GenericChunk::reorderNibbleArray($subChunk->getBlockDataArray())), + "SkyLight" => new ByteArrayTag("SkyLight", GenericChunk::reorderNibbleArray($subChunk->getSkyLightArray())), + "BlockLight" => new ByteArrayTag("BlockLight", GenericChunk::reorderNibbleArray($subChunk->getBlockLightArray())) + ]); + } + + $nbt->Biomes = new ByteArrayTag("Biomes", $chunk->getBiomeIdArray()); + $nbt->HeightMap = new IntArrayTag("HeightMap", $chunk->getHeightMapArray()); + + $entities = []; + + foreach($chunk->getEntities() as $entity){ + if(!($entity instanceof Player) and !$entity->closed){ + $entity->saveNBT(); + $entities[] = $entity->namedtag; + } + } + + $nbt->Entities = new ListTag("Entities", $entities); + $nbt->Entities->setTagType(NBT::TAG_Compound); + + $tiles = []; + foreach($chunk->getTiles() as $tile){ + $tile->saveNBT(); + $tiles[] = $tile->namedtag; + } + + $nbt->TileEntities = new ListTag("TileEntities", $tiles); + $nbt->TileEntities->setTagType(NBT::TAG_Compound); + + //TODO: TileTicks + + $writer = new NBT(NBT::BIG_ENDIAN); + $nbt->setName("Level"); + $writer->setData(new CompoundTag("", ["Level" => $nbt])); + + return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL); + } + + public function nbtDeserialize(string $data){ + $nbt = new NBT(NBT::BIG_ENDIAN); + try{ + $nbt->readCompressed($data, ZLIB_ENCODING_DEFLATE); + + $chunk = $nbt->getData(); + + if(!isset($chunk->Level) or !($chunk->Level instanceof CompoundTag)){ + throw new ChunkException("Invalid NBT format"); + } + + $chunk = $chunk->Level; + + $subChunks = []; + if($chunk->Sections instanceof ListTag){ + foreach($chunk->Sections as $subChunk){ + if($subChunk instanceof CompoundTag){ + $subChunks[$subChunk->Y->getValue()] = new SubChunk( + GenericChunk::reorderByteArray($subChunk->Blocks->getValue()), + GenericChunk::reorderNibbleArray($subChunk->Data->getValue()), + GenericChunk::reorderNibbleArray($subChunk->SkyLight->getValue()), + GenericChunk::reorderNibbleArray($subChunk->BlockLight->getValue()) + ); + } + } + } + + if(isset($chunk->BiomeColors)){ + $biomeIds = GenericChunk::convertBiomeColours($chunk->BiomeColors->getValue()); //Convert back to PC format (RIP colours D:) + }elseif(isset($chunk->Biomes)){ + $biomeIds = $chunk->Biomes->getValue(); + }else{ + $biomeIds = ""; + } + + $result = new GenericChunk( + $this, + $chunk["xPos"], + $chunk["zPos"], + $subChunks, + isset($chunk->Entities) ? $chunk->Entities->getValue() : [], + isset($chunk->TileEntities) ? $chunk->TileEntities->getValue() : [], + $biomeIds, + isset($chunk->HeightMap) ? $chunk->HeightMap->getValue() : [] + ); + $result->setLightPopulated(isset($chunk->LightPopulated) ? ((bool) $chunk->LightPopulated->getValue()) : false); + $result->setPopulated(isset($chunk->TerrainPopulated) ? ((bool) $chunk->TerrainPopulated->getValue()) : false); + $result->setGenerated(true); + return $result; + }catch(\Throwable $e){ + MainLogger::getLogger()->logException($e); + return null; + } + } + + public static function getProviderName() : string{ + return "anvil"; + } + + public function getWorldHeight() : int{ + //TODO: add world height options + return 256; + } + +} \ No newline at end of file diff --git a/src/devmine/worlds/format/region/McRegion.php b/src/devmine/worlds/format/region/McRegion.php new file mode 100644 index 0000000..89a80dd --- /dev/null +++ b/src/devmine/worlds/format/region/McRegion.php @@ -0,0 +1,434 @@ +xPos = new IntTag("xPos", $chunk->getX()); + $nbt->zPos = new IntTag("zPos", $chunk->getZ()); + + $nbt->V = new ByteTag("V", 0); //guess + $nbt->LastUpdate = new LongTag("LastUpdate", 0); //TODO + $nbt->InhabitedTime = new LongTag("InhabitedTime", 0); //TODO + $nbt->TerrainPopulated = new ByteTag("TerrainPopulated", $chunk->isPopulated()); + $nbt->LightPopulated = new ByteTag("LightPopulated", $chunk->isLightPopulated()); + + $ids = ""; + $data = ""; + $skyLight = ""; + $blockLight = ""; + $subChunks = $chunk->getSubChunks(); + for($x = 0; $x < 16; ++$x){ + for($z = 0; $z < 16; ++$z){ + for($y = 0; $y < 8; ++$y){ + $subChunk = $subChunks[$y]; + $ids .= $subChunk->getBlockIdColumn($x, $z); + $data .= $subChunk->getBlockDataColumn($x, $z); + $skyLight .= $subChunk->getSkyLightColumn($x, $z); + $blockLight .= $subChunk->getBlockLightColumn($x, $z); + } + } + } + + $nbt->Blocks = new ByteArrayTag("Blocks", $ids); + $nbt->Data = new ByteArrayTag("Data", $data); + $nbt->SkyLight = new ByteArrayTag("SkyLight", $skyLight); + $nbt->BlockLight = new ByteArrayTag("BlockLight", $blockLight); + + $nbt->Biomes = new ByteArrayTag("Biomes", $chunk->getBiomeIdArray()); + $nbt->HeightMap = new IntArrayTag("HeightMap", $chunk->getHeightMapArray()); + + $entities = []; + + foreach($chunk->getEntities() as $entity){ + if(!($entity instanceof Player) and !$entity->closed){ + $entity->saveNBT(); + $entities[] = $entity->namedtag; + } + } + + $nbt->Entities = new ListTag("Entities", $entities); + $nbt->Entities->setTagType(NBT::TAG_Compound); + + $tiles = []; + foreach($chunk->getTiles() as $tile){ + $tile->saveNBT(); + $tiles[] = $tile->namedtag; + } + + $nbt->TileEntities = new ListTag("TileEntities", $tiles); + $nbt->TileEntities->setTagType(NBT::TAG_Compound); + + //TODO: TileTicks + + $writer = new NBT(NBT::BIG_ENDIAN); + $nbt->setName("Level"); + $writer->setData(new CompoundTag("", ["Level" => $nbt])); + + return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL); + } + + /** + * @param string $data + * + * @return GenericChunk|null + */ + public function nbtDeserialize(string $data){ + $nbt = new NBT(NBT::BIG_ENDIAN); + try{ + $nbt->readCompressed($data, ZLIB_ENCODING_DEFLATE); + + $chunk = $nbt->getData(); + + if(!isset($chunk->Level) or !($chunk->Level instanceof CompoundTag)){ + return null; + } + + $chunk = $chunk->Level; + + $subChunks = []; + $fullIds = isset($chunk->Blocks) ? $chunk->Blocks->getValue() : str_repeat("\x00", 32768); + $fullData = isset($chunk->Data) ? $chunk->Data->getValue() : (str_repeat("\x00", 16384)); + $fullSkyLight = isset($chunk->SkyLight) ? $chunk->SkyLight->getValue() : str_repeat("\xff", 16384); + $fullBlockLight = isset($chunk->BlockLight) ? $chunk->BlockLight->getValue() : (str_repeat("\x00", 16384)); + + for($y = 0; $y < 8; ++$y){ + $offset = ($y << 4); + $ids = ""; + for($i = 0; $i < 256; ++$i){ + $ids .= substr($fullIds, $offset, 16); + $offset += 128; + } + $data = ""; + $offset = ($y << 3); + for($i = 0; $i < 256; ++$i){ + $data .= substr($fullData, $offset, 8); + $offset += 64; + } + $skyLight = ""; + $offset = ($y << 3); + for($i = 0; $i < 256; ++$i){ + $skyLight .= substr($fullSkyLight, $offset, 8); + $offset += 64; + } + $blockLight = ""; + $offset = ($y << 3); + for($i = 0; $i < 256; ++$i){ + $blockLight .= substr($fullBlockLight, $offset, 8); + $offset += 64; + } + $subChunks[$y] = new SubChunk($ids, $data, $skyLight, $blockLight); + } + + if(isset($chunk->BiomeColors)){ + $biomeIds = GenericChunk::convertBiomeColours($chunk->BiomeColors->getValue()); //Convert back to PC format (RIP colours D:) + }elseif(isset($chunk->Biomes)){ + $biomeIds = $chunk->Biomes->getValue(); + }else{ + $biomeIds = ""; + } + + $result = new GenericChunk( + $this, + $chunk["xPos"], + $chunk["zPos"], + $subChunks, + isset($chunk->Entities) ? $chunk->Entities->getValue() : [], + isset($chunk->TileEntities) ? $chunk->TileEntities->getValue() : [], + $biomeIds, + isset($chunk->HeightMap) ? $chunk->HeightMap->getValue() : [] //this shouldn't exist in normal mcregion worlds anyway... + ); + $result->setLightPopulated(isset($chunk->LightPopulated) ? ((bool) $chunk->LightPopulated->getValue()) : false); + $result->setPopulated(isset($chunk->TerrainPopulated) ? ((bool) $chunk->TerrainPopulated->getValue()) : false); + $result->setGenerated(true); + return $result; + }catch(\Throwable $e){ + MainLogger::getLogger()->logException($e); + return null; + } + } + + public static function getProviderName() : string{ + return "mcregion"; + } + + public function getWorldHeight() : int{ + //TODO: add world height options + return 128; + } + + public static function isValid(string $path) : bool{ + $isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/")); + + if($isValid){ + $files = glob($path . "/region/*.mc*"); + if(empty($files)){ //possible glob() issue on some systems + $files = array_filter(scandir($path . "/region/"), function($file){ + return substr($file, strrpos($file, ".") + 1, 2) === "mc"; //region file + }); + } + + foreach($files as $f){ + if(substr($f, strrpos($f, ".") + 1) !== static::REGION_FILE_EXTENSION){ + $isValid = false; + break; + } + } + } + + return $isValid; + } + + public static function generate(string $path, string $name, $seed, string $generator, array $options = []){ + if(!file_exists($path)){ + mkdir($path, 0777, true); + } + + if(!file_exists($path . "/region")){ + mkdir($path . "/region", 0777); + } + //TODO, add extra details + $levelData = new CompoundTag("Data", [ + "hardcore" => new ByteTag("hardcore", 0), + "initialized" => new ByteTag("initialized", 1), + "GameType" => new IntTag("GameType", 0), + "generatorVersion" => new IntTag("generatorVersion", 1), //2 in MCPE + "SpawnX" => new IntTag("SpawnX", 256), + "SpawnY" => new IntTag("SpawnY", 70), + "SpawnZ" => new IntTag("SpawnZ", 256), + "version" => new IntTag("version", 19133), + "DayTime" => new IntTag("DayTime", 0), + "LastPlayed" => new LongTag("LastPlayed", microtime(true) * 1000), + "RandomSeed" => new LongTag("RandomSeed", $seed), + "SizeOnDisk" => new LongTag("SizeOnDisk", 0), + "Time" => new LongTag("Time", 0), + "generatorName" => new StringTag("generatorName", Generator::getGeneratorName($generator)), + "generatorOptions" => new StringTag("generatorOptions", isset($options["preset"]) ? $options["preset"] : ""), + "LevelName" => new StringTag("LevelName", $name), + "GameRules" => new CompoundTag("GameRules", []) + ]); + $nbt = new NBT(NBT::BIG_ENDIAN); + $nbt->setData(new CompoundTag("", [ + "Data" => $levelData + ])); + $buffer = $nbt->writeCompressed(); + file_put_contents($path . "level.dat", $buffer); + } + + public function getGenerator() : string{ + return $this->levelData["generatorName"]; + } + + public function getGeneratorOptions() : array{ + return ["preset" => $this->levelData["generatorOptions"]]; + } + + public function getChunk(int $chunkX, int $chunkZ, bool $create = false){ + $index = Level::chunkHash($chunkX, $chunkZ); + if(isset($this->chunks[$index])){ + return $this->chunks[$index]; + }else{ + $this->loadChunk($chunkX, $chunkZ, $create); + + return $this->chunks[$index] ?? null; + } + } + + public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk){ + + $chunk->setProvider($this); + + self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); + $this->loadRegion($regionX, $regionZ); + + $chunk->setX($chunkX); + $chunk->setZ($chunkZ); + + + if(isset($this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)]) and $this->chunks[$index] !== $chunk){ + $this->unloadChunk($chunkX, $chunkZ, false); + } + + $this->chunks[$index] = $chunk; + } + + public function saveChunk(int $chunkX, int $chunkZ) : bool{ + if($this->isChunkLoaded($chunkX, $chunkZ)){ + $this->getRegion($chunkX >> 5, $chunkZ >> 5)->writeChunk($this->getChunk($chunkX, $chunkZ)); + + return true; + } + + return false; + } + + public function saveChunks(){ + foreach($this->chunks as $chunk){ + $this->saveChunk($chunk->getX(), $chunk->getZ()); + } + } + + public function loadChunk(int $chunkX, int $chunkZ, bool $create = false) : bool{ + $index = Level::chunkHash($chunkX, $chunkZ); + if(isset($this->chunks[$index])){ + return true; + } + $regionX = $regionZ = null; + self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); + $this->loadRegion($regionX, $regionZ); + $this->level->timings->syncChunkLoadDataTimer->startTiming(); + $chunk = $this->getRegion($regionX, $regionZ)->readChunk($chunkX - $regionX * 32, $chunkZ - $regionZ * 32); + if($chunk === null and $create){ + $chunk = $this->getEmptyChunk($chunkX, $chunkZ); + } + $this->level->timings->syncChunkLoadDataTimer->stopTiming(); + + if($chunk !== null){ + $this->chunks[$index] = $chunk; + return true; + }else{ + return false; + } + } + + public function unloadChunk(int $chunkX, int $chunkZ, bool $safe = true) : bool{ + $chunk = $this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)] ?? null; + if($chunk instanceof Chunk and $chunk->unload(false, $safe)){ + unset($this->chunks[$index]); + return true; + } + + return false; + } + + public function unloadChunks(){ + foreach($this->chunks as $chunk){ + $this->unloadChunk($chunk->getX(), $chunk->getZ(), false); + } + $this->chunks = []; + } + + public function isChunkLoaded(int $chunkX, int $chunkZ) : bool{ + return isset($this->chunks[Level::chunkHash($chunkX, $chunkZ)]); + } + + public function isChunkGenerated(int $chunkX, int $chunkZ) : bool{ + if(($region = $this->getRegion($chunkX >> 5, $chunkZ >> 5)) !== null){ + return $region->chunkExists($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32) and $this->getChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32, true)->isGenerated(); + } + + return false; + } + + public function isChunkPopulated(int $chunkX, int $chunkZ) : bool{ + $chunk = $this->getChunk($chunkX, $chunkZ); + if($chunk !== null){ + return $chunk->isPopulated(); + }else{ + return false; + } + } + + public function getLoadedChunks() : array{ + return $this->chunks; + } + + public function doGarbageCollection(){ + $limit = time() - 300; + foreach($this->regions as $index => $region){ + if($region->lastUsed <= $limit){ + $region->close(); + unset($this->regions[$index]); + } + } + } + + /** + * @param int $chunkX + * @param int $chunkZ + * @param int &$x + * @param int &$z + */ + public static function getRegionIndex(int $chunkX, int $chunkZ, &$x, &$z){ + $x = $chunkX >> 5; + $z = $chunkZ >> 5; + } + + /** + * @param int $chunkX + * @param int $chunkZ + * + * @return GenericChunk + */ + public function getEmptyChunk(int $chunkX, int $chunkZ){ + return GenericChunk::getEmptyChunk($chunkX, $chunkZ, $this); + } + + /** + * @param int $x + * @param int $z + * + * @return RegionLoader + */ + protected function getRegion(int $x, int $z){ + return $this->regions[Level::chunkHash($x, $z)] ?? null; + } + + /** + * @param int $x + * @param int $z + */ + protected function loadRegion(int $x, int $z){ + if(!isset($this->regions[$index = Level::chunkHash($x, $z)])){ + $this->regions[$index] = new RegionLoader($this, $x, $z, static::REGION_FILE_EXTENSION); + } + } + + public function close(){ + $this->unloadChunks(); + foreach($this->regions as $index => $region){ + $region->close(); + unset($this->regions[$index]); + } + $this->level = null; + } +} diff --git a/src/devmine/worlds/format/region/PMAnvil.php b/src/devmine/worlds/format/region/PMAnvil.php new file mode 100644 index 0000000..979cd45 --- /dev/null +++ b/src/devmine/worlds/format/region/PMAnvil.php @@ -0,0 +1,143 @@ +xPos = new IntTag("xPos", $chunk->getX()); + $nbt->zPos = new IntTag("zPos", $chunk->getZ()); + + $nbt->V = new ByteTag("V", 1); + $nbt->LastUpdate = new LongTag("LastUpdate", 0); //TODO + $nbt->InhabitedTime = new LongTag("InhabitedTime", 0); //TODO + $nbt->TerrainPopulated = new ByteTag("TerrainPopulated", $chunk->isPopulated()); + $nbt->LightPopulated = new ByteTag("LightPopulated", $chunk->isLightPopulated()); + + $nbt->Sections = new ListTag("Sections", []); + $nbt->Sections->setTagType(NBT::TAG_Compound); + $subChunks = -1; + foreach($chunk->getSubChunks() as $y => $subChunk){ + if($subChunk->isEmpty()){ + continue; + } + $nbt->Sections[++$subChunks] = new CompoundTag(null, [ + "Y" => new ByteTag("Y", $y), + "Blocks" => new ByteArrayTag("Blocks", $subChunk->getBlockIdArray()), + "Data" => new ByteArrayTag("Data", $subChunk->getBlockDataArray()), + "SkyLight" => new ByteArrayTag("SkyLight", $subChunk->getSkyLightArray()), + "BlockLight" => new ByteArrayTag("BlockLight", $subChunk->getBlockLightArray()) + ]); + } + + $nbt->Biomes = new ByteArrayTag("Biomes", $chunk->getBiomeIdArray()); + $nbt->HeightMap = new IntArrayTag("HeightMap", $chunk->getHeightMapArray()); + + $entities = []; + + foreach($chunk->getEntities() as $entity){ + if(!($entity instanceof Player) and !$entity->closed){ + $entity->saveNBT(); + $entities[] = $entity->namedtag; + } + } + + $nbt->Entities = new ListTag("Entities", $entities); + $nbt->Entities->setTagType(NBT::TAG_Compound); + + $tiles = []; + foreach($chunk->getTiles() as $tile){ + $tile->saveNBT(); + $tiles[] = $tile->namedtag; + } + + $nbt->TileEntities = new ListTag("TileEntities", $tiles); + $nbt->TileEntities->setTagType(NBT::TAG_Compound); + + //TODO: TileTicks + + $writer = new NBT(NBT::BIG_ENDIAN); + $nbt->setName("Level"); + $writer->setData(new CompoundTag("", ["Level" => $nbt])); + + return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL); + } + + public function nbtDeserialize(string $data){ + $nbt = new NBT(NBT::BIG_ENDIAN); + try{ + $nbt->readCompressed($data, ZLIB_ENCODING_DEFLATE); + + $chunk = $nbt->getData(); + + if(!isset($chunk->Level) or !($chunk->Level instanceof CompoundTag)){ + throw new ChunkException("Invalid NBT format"); + } + + $chunk = $chunk->Level; + + $subChunks = []; + if($chunk->Sections instanceof ListTag){ + foreach($chunk->Sections as $subChunk){ + if($subChunk instanceof CompoundTag){ + $subChunks[$subChunk->Y->getValue()] = new SubChunk( + $subChunk->Blocks->getValue(), + $subChunk->Data->getValue(), + $subChunk->SkyLight->getValue(), + $subChunk->BlockLight->getValue() + ); + } + } + } + + $result = new GenericChunk( + $this, + $chunk["xPos"], + $chunk["zPos"], + $subChunks, + isset($chunk->Entities) ? $chunk->Entities->getValue() : [], + isset($chunk->TileEntities) ? $chunk->TileEntities->getValue() : [], + isset($chunk->Biomes) ? $chunk->Biomes->getValue() : "", + isset($chunk->HeightMap) ? $chunk->HeightMap->getValue() : [] + ); + $result->setLightPopulated(isset($chunk->LightPopulated) ? ((bool) $chunk->LightPopulated->getValue()) : false); + $result->setPopulated(isset($chunk->TerrainPopulated) ? ((bool) $chunk->TerrainPopulated->getValue()) : false); + $result->setGenerated(true); + return $result; + }catch(\Throwable $e){ + MainLogger::getLogger()->logException($e); + return null; + } + } + + public static function getProviderName() : string{ + return "pmanvil"; + } +} \ No newline at end of file diff --git a/src/devmine/levels/format/mcregion/RegionLoader.php b/src/devmine/worlds/format/region/RegionLoader.php similarity index 85% rename from src/devmine/levels/format/mcregion/RegionLoader.php rename to src/devmine/worlds/format/region/RegionLoader.php index 73e6b4b..a897241 100644 --- a/src/devmine/levels/format/mcregion/RegionLoader.php +++ b/src/devmine/worlds/format/region/RegionLoader.php @@ -2,12 +2,12 @@ -namespace devmine\levels\format\mcregion; - -use devmine\levels\format\FullChunk; -use devmine\levels\format\LevelProvider; +declare(strict_types = 1); +namespace devmine\worlds\format\region; +use devmine\worlds\format\generic\GenericChunk; +use devmine\worlds\format\LevelProvider; use devmine\utilities\main\Binary; use devmine\utilities\main\ChunkException; use devmine\utilities\main\MainLogger; @@ -30,11 +30,11 @@ class RegionLoader{ public $lastUsed; - public function __construct(LevelProvider $level, $regionX, $regionZ){ + public function __construct(LevelProvider $level, int $regionX, int $regionZ, string $fileExtension = McRegion::REGION_FILE_EXTENSION){ $this->x = $regionX; $this->z = $regionZ; $this->levelProvider = $level; - $this->filePath = $this->levelProvider->getPath() . "region/r.$regionX.$regionZ.mcr"; + $this->filePath = $this->levelProvider->getPath() . "region/r.$regionX.$regionZ.$fileExtension"; $exists = file_exists($this->filePath); if(!$exists){ touch($this->filePath); @@ -58,11 +58,11 @@ public function __destruct(){ } } - protected function isChunkGenerated($index){ + protected function isChunkGenerated(int $index) : bool{ return !($this->locationTable[$index][0] === 0 or $this->locationTable[$index][1] === 0); } - public function readChunk($x, $z){ + public function readChunk(int $x, int $z){ $index = self::getChunkOffset($x, $z); if($index < 0 or $index >= 4096){ return null; @@ -96,8 +96,8 @@ public function readChunk($x, $z){ return null; } - $chunk = $this->unserializeChunk(fread($this->filePointer, $length - 1)); - if($chunk instanceof FullChunk){ + $chunk = $this->levelProvider->nbtDeserialize(fread($this->filePointer, $length - 1)); + if($chunk instanceof GenericChunk){ return $chunk; }else{ MainLogger::getLogger()->error("Corrupted chunk detected"); @@ -105,18 +105,14 @@ public function readChunk($x, $z){ } } - protected function unserializeChunk($data){ - return Chunk::fromBinary($data, $this->levelProvider); - } - - public function chunkExists($x, $z){ + public function chunkExists(int $x, int $z) : bool{ return $this->isChunkGenerated(self::getChunkOffset($x, $z)); } - protected function saveChunk($x, $z, $chunkData){ + protected function saveChunk(int $x, int $z, string $chunkData){ $length = strlen($chunkData) + 1; if($length + 4 > self::MAX_SECTOR_LENGTH){ - throw new ChunkException("Chunk is too big! ".($length + 4)." > ".self::MAX_SECTOR_LENGTH); + throw new ChunkException("Chunk is too big! " . ($length + 4) . " > " . self::MAX_SECTOR_LENGTH); } $sectors = (int) ceil(($length + 4) / 4096); $index = self::getChunkOffset($x, $z); @@ -140,21 +136,21 @@ protected function saveChunk($x, $z, $chunkData){ } } - public function removeChunk($x, $z){ + public function removeChunk(int $x, int $z){ $index = self::getChunkOffset($x, $z); $this->locationTable[$index][0] = 0; $this->locationTable[$index][1] = 0; } - public function writeChunk(FullChunk $chunk){ + public function writeChunk(GenericChunk $chunk){ $this->lastUsed = time(); - $chunkData = $chunk->toBinary(); + $chunkData = $this->levelProvider->nbtSerialize($chunk); if($chunkData !== false){ $this->saveChunk($chunk->getX() - ($this->getX() * 32), $chunk->getZ() - ($this->getZ() * 32), $chunkData); } } - protected static function getChunkOffset($x, $z){ + protected static function getChunkOffset(int $x, int $z) : int{ return $x + ($z << 5); } @@ -164,7 +160,7 @@ public function close(){ $this->levelProvider = null; } - public function doSlowCleanUp(){ + public function doSlowCleanUp() : int{ for($i = 0; $i < 1024; ++$i){ if($this->locationTable[$i][0] === 0 or $this->locationTable[$i][1] === 0){ continue; @@ -200,7 +196,7 @@ public function doSlowCleanUp(){ return $n; } - private function cleanGarbage(){ + private function cleanGarbage() : int{ $sectors = []; foreach($this->locationTable as $index => $data){ //Calculate file usage if($data[0] === 0 or $data[1] === 0){ @@ -275,28 +271,16 @@ protected function writeLocationIndex($index){ protected function createBlank(){ fseek($this->filePointer, 0); - ftruncate($this->filePointer, 0); + ftruncate($this->filePointer, 8192); // this fills the file with the null byte $this->lastSector = 1; - $table = ""; - for($i = 0; $i < 1024; ++$i){ - $this->locationTable[$i] = [0, 0]; - $table .= Binary::writeInt(0); - } - - $time = time(); - for($i = 0; $i < 1024; ++$i){ - $this->locationTable[$i][2] = $time; - $table .= Binary::writeInt($time); - } - - fwrite($this->filePointer, $table, 4096 * 2); + $this->locationTable = array_fill(0, 1024, [0, 0, 0]); } - public function getX(){ + public function getX() : int{ return $this->x; } - public function getZ(){ + public function getZ() : int{ return $this->z; } diff --git a/src/devmine/levels/generator/Flat.php b/src/devmine/worlds/generator/Flat.php similarity index 86% rename from src/devmine/levels/generator/Flat.php rename to src/devmine/worlds/generator/Flat.php index 4944aef..6d9838f 100644 --- a/src/devmine/levels/generator/Flat.php +++ b/src/devmine/worlds/generator/Flat.php @@ -2,7 +2,7 @@ -namespace devmine\levels\generator; +namespace devmine\worlds\generator; use devmine\inventory\blocks\CoalOre; use devmine\inventory\blocks\DiamondOre; @@ -13,18 +13,17 @@ use devmine\inventory\blocks\LapisOre; use devmine\inventory\blocks\RedstoneOre; use devmine\inventory\items\Item; -use devmine\levels\ChunkManager; -use devmine\levels\format\FullChunk; -use devmine\levels\generator\biome\Biome; -use devmine\levels\generator\populator\Ore; -use devmine\levels\generator\populator\Populator; +use devmine\worlds\ChunkManager; +use devmine\worlds\format\Chunk; +use devmine\worlds\generator\populator\Ore; +use devmine\worlds\generator\populator\Populator; use devmine\server\calculations\Vector3; use devmine\utilities\main\Random; class Flat extends Generator{ /** @var ChunkManager */ private $level; - /** @var FullChunk */ + /** @var Chunk */ private $chunk; /** @var Random */ private $random; @@ -36,7 +35,7 @@ public function getSettings(){ return $this->options; } - public function getName() : string{ + public function getName(){ return "flat"; } @@ -50,7 +49,7 @@ public function __construct(array $options = []){ $ores = new Ore(); $ores->setOreTypes([ new object\OreType(new CoalOre(), 20, 16, 0, 128), - new object\OreType(New IronOre(), 20, 8, 0, 64), + new object\OreType(new IronOre(), 20, 8, 0, 64), new object\OreType(new RedstoneOre(), 8, 7, 0, 16), new object\OreType(new LapisOre(), 1, 6, 0, 32), new object\OreType(new GoldOre(), 2, 8, 0, 32), @@ -70,9 +69,9 @@ protected function parsePreset($preset, $chunkX, $chunkZ){ $this->preset = $preset; $preset = explode(";", $preset); $version = (int) $preset[0]; - $blocks = isset($preset[1]) ? $preset[1] : ""; - $biome = isset($preset[2]) ? $preset[2] : 1; - $options = isset($preset[3]) ? $preset[3] : ""; + $blocks = $preset[1] ?? ""; + $biome = $preset[2] ?? 1; + $options = $preset[3] ?? ""; preg_match_all('#^(([0-9]*x|)([0-9]{1,3})(|:[0-9]{0,2}))$#m', str_replace(",", "\n", $blocks), $matches); $y = 0; $this->structure = []; @@ -94,15 +93,10 @@ protected function parsePreset($preset, $chunkX, $chunkZ){ $this->chunk = clone $this->level->getChunk($chunkX, $chunkZ); $this->chunk->setGenerated(); - $c = Biome::getBiome($biome)->getColor(); - $R = $c >> 16; - $G = ($c >> 8) & 0xff; - $B = $c & 0xff; for($Z = 0; $Z < 16; ++$Z){ for($X = 0; $X < 16; ++$X){ $this->chunk->setBiomeId($X, $Z, $biome); - $this->chunk->setBiomeColor($X, $Z, $R, $G, $B); for($y = 0; $y < 128; ++$y){ $this->chunk->setBlock($X, $y, $Z, ...$this->structure[$y]); } diff --git a/src/devmine/levels/generator/GenerationTask.php b/src/devmine/worlds/generator/GenerationTask.php similarity index 66% rename from src/devmine/levels/generator/GenerationTask.php rename to src/devmine/worlds/generator/GenerationTask.php index 6f68e0b..9a076f7 100644 --- a/src/devmine/levels/generator/GenerationTask.php +++ b/src/devmine/worlds/generator/GenerationTask.php @@ -2,29 +2,25 @@ -namespace devmine\levels\generator; +namespace devmine\worlds\generator; - -use devmine\levels\format\FullChunk; - -use devmine\levels\Level; -use devmine\levels\SimpleChunkManager; +use devmine\worlds\format\Chunk; +use devmine\worlds\format\generic\GenericChunk; +use devmine\worlds\Level; +use devmine\worlds\SimpleChunkManager; use devmine\server\tasks\AsyncTask; -use devmine\Server; - +use devmine\server\server; class GenerationTask extends AsyncTask{ public $state; public $levelId; public $chunk; - public $chunkClass; - public function __construct(Level $level, FullChunk $chunk){ + public function __construct(Level $level, Chunk $chunk){ $this->state = true; $this->levelId = $level->getId(); - $this->chunk = $chunk->toFastBinary(); - $this->chunkClass = get_class($chunk); + $this->chunk = $chunk->fastSerialize(); } public function onRun(){ @@ -37,9 +33,8 @@ public function onRun(){ return; } - /** @var FullChunk $chunk */ - $chunk = $this->chunkClass; - $chunk = $chunk::fromFastBinary($this->chunk); + /** @var Chunk $chunk */ + $chunk = GenericChunk::fastDeserialize($this->chunk); if($chunk === null){ //TODO error return; @@ -51,7 +46,7 @@ public function onRun(){ $chunk = $manager->getChunk($chunk->getX(), $chunk->getZ()); $chunk->setGenerated(); - $this->chunk = $chunk->toFastBinary(); + $this->chunk = $chunk->fastSerialize(); $manager->setChunk($chunk->getX(), $chunk->getZ(), null); } @@ -63,9 +58,8 @@ public function onCompletion(Server $server){ $level->registerGenerator(); return; } - /** @var FullChunk $chunk */ - $chunk = $this->chunkClass; - $chunk = $chunk::fromFastBinary($this->chunk, $level->getProvider()); + /** @var Chunk $chunk */ + $chunk = GenericChunk::fastDeserialize($this->chunk, $level->getProvider()); if($chunk === null){ //TODO error return; diff --git a/src/devmine/levels/generator/Generator.php b/src/devmine/worlds/generator/Generator.php similarity index 80% rename from src/devmine/levels/generator/Generator.php rename to src/devmine/worlds/generator/Generator.php index 9404db7..035376e 100644 --- a/src/devmine/levels/generator/Generator.php +++ b/src/devmine/worlds/generator/Generator.php @@ -5,11 +5,11 @@ /** * Noise classes used in Levels */ -namespace devmine\levels\generator; +namespace devmine\worlds\generator; -use devmine\levels\ChunkManager; -use devmine\levels\generator\noise\Noise; -use devmine\levels\generator\normal\Normal; +use devmine\worlds\ChunkManager; +use devmine\worlds\generator\noise\Noise; +use devmine\worlds\generator\normal\Normal; use devmine\utilities\main\Random; abstract class Generator{ @@ -64,12 +64,14 @@ public static function getGeneratorName($class){ * @param int $z * * @return \SplFixedArray + * + * @throws \InvalidArgumentCountException */ public static function getFastNoise1D(Noise $noise, $xSize, $samplingRate, $x, $y, $z){ if($samplingRate === 0){ throw new \InvalidArgumentException("samplingRate cannot be 0"); } - if ($xSize % $samplingRate !== 0) { + if($xSize % $samplingRate !== 0){ throw new \InvalidArgumentCountException("xSize % samplingRate must return 0"); } @@ -99,17 +101,15 @@ public static function getFastNoise1D(Noise $noise, $xSize, $samplingRate, $x, $ * @param int $z * * @return \SplFixedArray + * + * @throws \InvalidArgumentException + * @throws \InvalidArgumentCountException */ public static function getFastNoise2D(Noise $noise, $xSize, $zSize, $samplingRate, $x, $y, $z){ - if($samplingRate === 0){ - throw new \InvalidArgumentException("samplingRate cannot be 0"); - } - if ($xSize % $samplingRate !== 0) { - throw new \InvalidArgumentCountException("xSize % samplingRate must return 0"); - } - if ($zSize % $samplingRate !== 0) { - throw new \InvalidArgumentCountException("zSize % samplingRate must return 0"); - } + assert($samplingRate !== 0, new \InvalidArgumentException("samplingRate cannot be 0")); + + assert($xSize % $samplingRate === 0, new \InvalidArgumentCountException("xSize % samplingRate must return 0")); + assert($zSize % $samplingRate === 0, new \InvalidArgumentCountException("zSize % samplingRate must return 0")); $noiseArray = new \SplFixedArray($xSize + 1); @@ -154,26 +154,19 @@ public static function getFastNoise2D(Noise $noise, $xSize, $zSize, $samplingRat * @param int $z * * @return \SplFixedArray + * + * @throws \InvalidArgumentException + * @throws \InvalidArgumentCountException */ public static function getFastNoise3D(Noise $noise, $xSize, $ySize, $zSize, $xSamplingRate, $ySamplingRate, $zSamplingRate, $x, $y, $z){ - if($xSamplingRate === 0){ - throw new \InvalidArgumentException("xSamplingRate cannot be 0"); - } - if($zSamplingRate === 0){ - throw new \InvalidArgumentException("zSamplingRate cannot be 0"); - } - if($ySamplingRate === 0){ - throw new \InvalidArgumentException("ySamplingRate cannot be 0"); - } - if ($xSize % $xSamplingRate !== 0) { - throw new \InvalidArgumentCountException("xSize % xSamplingRate must return 0"); - } - if ($zSize % $zSamplingRate !== 0) { - throw new \InvalidArgumentCountException("zSize % zSamplingRate must return 0"); - } - if ($ySize % $ySamplingRate !== 0) { - throw new \InvalidArgumentCountException("ySize % ySamplingRate must return 0"); - } + + assert($xSamplingRate !== 0, new \InvalidArgumentException("xSamplingRate cannot be 0")); + assert($zSamplingRate !== 0, new \InvalidArgumentException("zSamplingRate cannot be 0")); + assert($ySamplingRate !== 0, new \InvalidArgumentException("ySamplingRate cannot be 0")); + + assert($xSize % $xSamplingRate === 0, new \InvalidArgumentCountException("xSize % xSamplingRate must return 0")); + assert($zSize % $zSamplingRate === 0, new \InvalidArgumentCountException("zSize % zSamplingRate must return 0")); + assert($ySize % $ySamplingRate === 0, new \InvalidArgumentCountException("ySize % ySamplingRate must return 0")); $noiseArray = array_fill(0, $xSize + 1, array_fill(0, $zSize + 1, [])); @@ -223,10 +216,6 @@ public static function getFastNoise3D(Noise $noise, $xSize, $ySize, $zSize, $xSa return $noiseArray; } - public function getWaterHeight() : int{ - return 0; - } - public abstract function __construct(array $settings = []); public abstract function init(ChunkManager $level, Random $random); diff --git a/src/devmine/levels/generator/GeneratorRegisterTask.php b/src/devmine/worlds/generator/GeneratorRegisterTask.php similarity index 75% rename from src/devmine/levels/generator/GeneratorRegisterTask.php rename to src/devmine/worlds/generator/GeneratorRegisterTask.php index 976b99f..d3e58cf 100644 --- a/src/devmine/levels/generator/GeneratorRegisterTask.php +++ b/src/devmine/worlds/generator/GeneratorRegisterTask.php @@ -2,15 +2,13 @@ -namespace devmine\levels\generator; +namespace devmine\worlds\generator; use devmine\inventory\blocks\Block; - -use devmine\levels\generator\biome\Biome; -use devmine\levels\Level; -use devmine\levels\SimpleChunkManager; +use devmine\worlds\generator\biome\Biome; +use devmine\worlds\Level; +use devmine\worlds\SimpleChunkManager; use devmine\server\tasks\AsyncTask; - use devmine\utilities\main\Random; class GeneratorRegisterTask extends AsyncTask{ @@ -19,11 +17,9 @@ class GeneratorRegisterTask extends AsyncTask{ public $settings; public $seed; public $levelId; - public $waterHeight; public function __construct(Level $level, Generator $generator){ $this->generator = get_class($generator); - $this->waterHeight = $generator->getWaterHeight(); $this->settings = serialize($generator->getSettings()); $this->seed = $level->getSeed(); $this->levelId = $level->getId(); @@ -32,7 +28,7 @@ public function __construct(Level $level, Generator $generator){ public function onRun(){ Block::init(); Biome::init(); - $manager = new SimpleChunkManager($this->seed, $this->waterHeight); + $manager = new SimpleChunkManager($this->seed); $this->saveToThreadStore("generation.level{$this->levelId}.manager", $manager); /** @var Generator $generator */ $generator = $this->generator; diff --git a/src/devmine/levels/generator/GeneratorUnregisterTask.php b/src/devmine/worlds/generator/GeneratorUnregisterTask.php similarity index 85% rename from src/devmine/levels/generator/GeneratorUnregisterTask.php rename to src/devmine/worlds/generator/GeneratorUnregisterTask.php index e29656d..781eded 100644 --- a/src/devmine/levels/generator/GeneratorUnregisterTask.php +++ b/src/devmine/worlds/generator/GeneratorUnregisterTask.php @@ -2,14 +2,11 @@ -namespace devmine\levels\generator; - - -use devmine\levels\Level; +namespace devmine\worlds\generator; +use devmine\worlds\Level; use devmine\server\tasks\AsyncTask; - class GeneratorUnregisterTask extends AsyncTask{ public $levelId; diff --git a/src/devmine/levels/generator/LightPopulationTask.php b/src/devmine/worlds/generator/LightPopulationTask.php similarity index 51% rename from src/devmine/levels/generator/LightPopulationTask.php rename to src/devmine/worlds/generator/LightPopulationTask.php index 24fd759..f2569f3 100644 --- a/src/devmine/levels/generator/LightPopulationTask.php +++ b/src/devmine/worlds/generator/LightPopulationTask.php @@ -2,33 +2,27 @@ -namespace devmine\levels\generator; - - -use devmine\levels\format\FullChunk; - -use devmine\levels\Level; +namespace devmine\worlds\generator; +use devmine\worlds\format\Chunk; +use devmine\worlds\format\generic\GenericChunk; +use devmine\worlds\Level; use devmine\server\tasks\AsyncTask; -use devmine\Server; - +use devmine\server\server; class LightPopulationTask extends AsyncTask{ public $levelId; public $chunk; - public $chunkClass; - public function __construct(Level $level, FullChunk $chunk){ + public function __construct(Level $level, Chunk $chunk){ $this->levelId = $level->getId(); - $this->chunk = $chunk->toFastBinary(); - $this->chunkClass = get_class($chunk); + $this->chunk = $chunk->fastSerialize(); } public function onRun(){ - /** @var FullChunk $chunk */ - $chunk = $this->chunkClass; - $chunk = $chunk::fromFastBinary($this->chunk); + /** @var Chunk $chunk */ + $chunk = GenericChunk::fastDeserialize($this->chunk); if($chunk === null){ //TODO error return; @@ -38,15 +32,14 @@ public function onRun(){ $chunk->populateSkyLight(); $chunk->setLightPopulated(); - $this->chunk = $chunk->toFastBinary(); + $this->chunk = $chunk->fastSerialize(); } public function onCompletion(Server $server){ $level = $server->getLevel($this->levelId); if($level !== null){ - /** @var FullChunk $chunk */ - $chunk = $this->chunkClass; - $chunk = $chunk::fromFastBinary($this->chunk, $level->getProvider()); + /** @var Chunk $chunk */ + $chunk = GenericChunk::fastDeserialize($this->chunk, $level->getProvider()); if($chunk === null){ //TODO error return; diff --git a/src/devmine/levels/generator/PopulationTask.php b/src/devmine/worlds/generator/PopulationTask.php similarity index 74% rename from src/devmine/levels/generator/PopulationTask.php rename to src/devmine/worlds/generator/PopulationTask.php index 9b2382a..290c87d 100644 --- a/src/devmine/levels/generator/PopulationTask.php +++ b/src/devmine/worlds/generator/PopulationTask.php @@ -2,24 +2,20 @@ -namespace devmine\levels\generator; +namespace devmine\worlds\generator; - -use devmine\levels\format\FullChunk; - -use devmine\levels\Level; -use devmine\levels\SimpleChunkManager; +use devmine\worlds\format\Chunk; +use devmine\worlds\format\generic\GenericChunk; +use devmine\worlds\Level; +use devmine\worlds\SimpleChunkManager; use devmine\server\tasks\AsyncTask; -use devmine\Server; - +use devmine\server\server; class PopulationTask extends AsyncTask{ - public $state; public $levelId; public $chunk; - public $chunkClass; public $chunk0; public $chunk1; @@ -31,11 +27,10 @@ class PopulationTask extends AsyncTask{ public $chunk7; public $chunk8; - public function __construct(Level $level, FullChunk $chunk){ + public function __construct(Level $level, Chunk $chunk){ $this->state = true; $this->levelId = $level->getId(); - $this->chunk = $chunk->toFastBinary(); - $this->chunkClass = get_class($chunk); + $this->chunk = $chunk->fastSerialize(); for($i = 0; $i < 9; ++$i){ if($i === 4){ @@ -44,7 +39,7 @@ public function __construct(Level $level, FullChunk $chunk){ $xx = -1 + $i % 3; $zz = -1 + (int) ($i / 3); $ck = $level->getChunk($chunk->getX() + $xx, $chunk->getZ() + $zz, false); - $this->{"chunk$i"} = $ck !== null ? $ck->toFastBinary() : null; + $this->{"chunk$i"} = $ck !== null ? $ck->fastSerialize() : null; } } @@ -58,12 +53,10 @@ public function onRun(){ return; } - /** @var FullChunk[] $chunks */ + /** @var Chunk[] $chunks */ $chunks = []; - /** @var FullChunk $chunkC */ - $chunkC = $this->chunkClass; - $chunk = $chunkC::fromFastBinary($this->chunk); + $chunk = GenericChunk::fastDeserialize($this->chunk); for($i = 0; $i < 9; ++$i){ if($i === 4){ @@ -73,9 +66,9 @@ public function onRun(){ $zz = -1 + (int) ($i / 3); $ck = $this->{"chunk$i"}; if($ck === null){ - $chunks[$i] = $chunkC::getEmptyChunk($chunk->getX() + $xx, $chunk->getZ() + $zz); + $chunks[$i] = GenericChunk::getEmptyChunk($chunk->getX() + $xx, $chunk->getZ() + $zz); }else{ - $chunks[$i] = $chunkC::fromFastBinary($ck); + $chunks[$i] = GenericChunk::fastDeserialize($ck); } } @@ -108,7 +101,7 @@ public function onRun(){ $chunk->populateSkyLight(); $chunk->setLightPopulated(); $chunk->setPopulated(); - $this->chunk = $chunk->toFastBinary(); + $this->chunk = $chunk->fastSerialize(); $manager->setChunk($chunk->getX(), $chunk->getZ(), null); @@ -131,7 +124,7 @@ public function onRun(){ continue; } - $this->{"chunk$i"} = $chunks[$i] !== null ? $chunks[$i]->toFastBinary() : null; + $this->{"chunk$i"} = $chunks[$i] !== null ? $chunks[$i]->fastSerialize() : null; } } @@ -143,10 +136,7 @@ public function onCompletion(Server $server){ return; } - /** @var FullChunk $chunkC */ - $chunkC = $this->chunkClass; - - $chunk = $chunkC::fromFastBinary($this->chunk, $level->getProvider()); + $chunk = GenericChunk::fastDeserialize($this->chunk, $level->getProvider()); if($chunk === null){ //TODO error @@ -159,7 +149,7 @@ public function onCompletion(Server $server){ } $c = $this->{"chunk$i"}; if($c !== null){ - $c = $chunkC::fromFastBinary($c, $level->getProvider()); + $c = GenericChunk::fastDeserialize($c, $level->getProvider()); $level->generateChunkCallback($c->getX(), $c->getZ(), $c); } } diff --git a/src/devmine/levels/generator/biome/Biome.php b/src/devmine/worlds/generator/biome/Biome.php similarity index 56% rename from src/devmine/levels/generator/biome/Biome.php rename to src/devmine/worlds/generator/biome/Biome.php index 2608263..7c0eb5f 100644 --- a/src/devmine/levels/generator/biome/Biome.php +++ b/src/devmine/worlds/generator/biome/Biome.php @@ -2,26 +2,23 @@ -namespace devmine\levels\generator\biome; +namespace devmine\worlds\generator\biome; use devmine\inventory\blocks\Block; -use devmine\levels\ChunkManager; -use devmine\levels\generator\normal\biome\SwampBiome; -use devmine\levels\generator\normal\biome\DesertBiome; -use devmine\levels\generator\normal\biome\ForestBiome; -use devmine\levels\generator\normal\biome\IcePlainsBiome; -use devmine\levels\generator\normal\biome\MountainsBiome; -use devmine\levels\generator\normal\biome\OceanBiome; -use devmine\levels\generator\normal\biome\PlainBiome; -use devmine\levels\generator\normal\biome\RiverBiome; -use devmine\levels\generator\normal\biome\SmallMountainsBiome; -use devmine\levels\generator\normal\biome\TaigaBiome; -use devmine\levels\generator\hell\HellBiome; -use devmine\levels\generator\populator\Populator; +use devmine\worlds\ChunkManager; +use devmine\worlds\generator\normal\biome\DesertBiome; +use devmine\worlds\generator\normal\biome\ForestBiome; +use devmine\worlds\generator\normal\biome\IcePlainsBiome; +use devmine\worlds\generator\normal\biome\MountainsBiome; +use devmine\worlds\generator\normal\biome\OceanBiome; +use devmine\worlds\generator\normal\biome\PlainBiome; +use devmine\worlds\generator\normal\biome\RiverBiome; +use devmine\worlds\generator\normal\biome\SmallMountainsBiome; +use devmine\worlds\generator\normal\biome\SwampBiome; +use devmine\worlds\generator\normal\biome\TaigaBiome; +use devmine\worlds\generator\populator\Populator; use devmine\utilities\main\Random; -use devmine\levels\generator\populator\Flower; - abstract class Biome{ const OCEAN = 0; @@ -61,26 +58,10 @@ abstract class Biome{ protected $rainfall = 0.5; protected $temperature = 0.5; - protected $grassColor = 0; protected static function register($id, Biome $biome){ self::$biomes[(int) $id] = $biome; $biome->setId((int) $id); - $biome->grassColor = self::generateBiomeColor($biome->getTemperature(), $biome->getRainfall()); - - $flowerPopFound = false; - - foreach($biome->getPopulators() as $populator){ - if($populator instanceof Flower){ - $flowerPopFound = true; - break; - } - } - - if($flowerPopFound === false){ - $flower = new Flower(); - $biome->addPopulator($flower); - } } public static function init(){ @@ -97,7 +78,6 @@ public static function init(){ self::register(self::SMALL_MOUNTAINS, new SmallMountainsBiome()); - self::register(self::HELL, new HellBiome()); self::register(self::BIRCH_FOREST, new ForestBiome(ForestBiome::TYPE_BIRCH)); } @@ -108,7 +88,7 @@ public static function init(){ * @return Biome */ public static function getBiome($id){ - return isset(self::$biomes[$id]) ? self::$biomes[$id] : self::$biomes[self::OCEAN]; + return self::$biomes[$id] ?? self::$biomes[self::OCEAN]; } public function clearPopulators(){ @@ -176,30 +156,4 @@ public function getTemperature(){ public function getRainfall(){ return $this->rainfall; } - - private static function generateBiomeColor($temperature, $rainfall){ - $x = (1 - $temperature) * 255; - $z = (1 - $rainfall * $temperature) * 255; - $c = self::interpolateColor(256, $x, $z, [0x47, 0xd0, 0x33], [0x6c, 0xb4, 0x93], [0xbf, 0xb6, 0x55], [0x80, 0xb4, 0x97]); - return ((int) ($c[0] << 16)) | (int) (($c[1] << 8)) | (int) ($c[2]); - } - - - private static function interpolateColor($size, $x, $z, $c1, $c2, $c3, $c4){ - $l1 = self::lerpColor($c1, $c2, $x / $size); - $l2 = self::lerpColor($c3, $c4, $x / $size); - - return self::lerpColor($l1, $l2, $z / $size); - } - - private static function lerpColor($a, $b, $s){ - $invs = 1 - $s; - return [$a[0] * $invs + $b[0] * $s, $a[1] * $invs + $b[1] * $s, $a[2] * $invs + $b[2] * $s]; - } - - - /** - * @return int (Red|Green|Blue) - */ - abstract public function getColor(); } \ No newline at end of file diff --git a/src/devmine/levels/generator/biome/BiomeSelector.php b/src/devmine/worlds/generator/biome/BiomeSelector.php similarity index 88% rename from src/devmine/levels/generator/biome/BiomeSelector.php rename to src/devmine/worlds/generator/biome/BiomeSelector.php index a9afeef..101fc92 100644 --- a/src/devmine/levels/generator/biome/BiomeSelector.php +++ b/src/devmine/worlds/generator/biome/BiomeSelector.php @@ -2,9 +2,9 @@ -namespace devmine\levels\generator\biome; +namespace devmine\worlds\generator\biome; -use devmine\levels\generator\noise\Simplex; +use devmine\worlds\generator\noise\Simplex; use devmine\utilities\main\Random; class BiomeSelector{ @@ -64,6 +64,6 @@ public function pickBiome($x, $z){ $rainfall = (int) ($this->getRainfall($x, $z) * 63); $biomeId = $this->map[$temperature + ($rainfall << 6)]; - return isset($this->biomes[$biomeId]) ? $this->biomes[$biomeId] : $this->fallback; + return $this->biomes[$biomeId] ?? $this->fallback; } } \ No newline at end of file diff --git a/src/devmine/worlds/generator/hell/HellBiome.php b/src/devmine/worlds/generator/hell/HellBiome.php new file mode 100644 index 0000000..2c9a79f --- /dev/null +++ b/src/devmine/worlds/generator/hell/HellBiome.php @@ -0,0 +1,14 @@ +waterHeight; + public function getName(){ + return "normal"; } public function getSettings(){ @@ -93,23 +77,18 @@ public function init(ChunkManager $level, Random $random){ $this->noiseBase = new Simplex($this->random, 4, 1 / 4, 1 / 64); $this->random->setSeed($this->level->getSeed()); - $ores = new NetherOre(); + /*$ores = new Ore(); $ores->setOreTypes([ - new OreType(new NetherQuartzOre(), 20, 16, 0, 128), - new OreType(new SoulSand(), 5, 64, 0, 128), - new OreType(new Gravel(), 5, 64, 0, 128), - new OreType(new Lava(), 1, 16, 0, $this->waterHeight), + new OreType(new CoalOre(), 20, 16, 0, 128), + new OreType(New IronOre(), 20, 8, 0, 64), + new OreType(new RedstoneOre(), 8, 7, 0, 16), + new OreType(new LapisOre(), 1, 6, 0, 32), + new OreType(new GoldOre(), 2, 8, 0, 32), + new OreType(new DiamondOre(), 1, 7, 0, 16), + new OreType(new Dirt(), 20, 32, 0, 128), + new OreType(new Gravel(), 10, 16, 0, 128) ]); - $this->populators[] = $ores; - $this->populators[] = new NetherGlowStone(); - $groundFire = new GroundFire(); - $groundFire->setBaseAmount(1); - $groundFire->setRandomAmount(1); - $this->populators[] = $groundFire; - $lava = new NetherLava(); - $lava->setBaseAmount(0); - $lava->setRandomAmount(0); - $this->populators[] = $lava; + $this->populators[] = $ores;*/ } public function generateChunk($chunkX, $chunkZ){ @@ -124,13 +103,6 @@ public function generateChunk($chunkX, $chunkZ){ $biome = Biome::getBiome(Biome::HELL); $chunk->setBiomeId($x, $z, $biome->getId()); - $color = [0, 0, 0]; - $bColor = $biome->getColor(); - $color[0] += (($bColor >> 16) ** 2); - $color[1] += ((($bColor >> 8) & 0xff) ** 2); - $color[2] += (($bColor & 0xff) ** 2); - - $chunk->setBiomeColor($x, $z, $color[0], $color[1], $color[2]); for($y = 0; $y < 128; ++$y){ if($y === 0 or $y === 127){ @@ -144,7 +116,6 @@ public function generateChunk($chunkX, $chunkZ){ $chunk->setBlockId($x, $y, $z, Block::NETHERRACK); }elseif($y <= $this->waterHeight){ $chunk->setBlockId($x, $y, $z, Block::STILL_LAVA); - $chunk->setBlockLight($x, $y + 1, $z, 15); } } } diff --git a/src/devmine/levels/generator/noise/Noise.php b/src/devmine/worlds/generator/noise/Noise.php similarity index 98% rename from src/devmine/levels/generator/noise/Noise.php rename to src/devmine/worlds/generator/noise/Noise.php index d015ac7..02c0cf3 100644 --- a/src/devmine/levels/generator/noise/Noise.php +++ b/src/devmine/worlds/generator/noise/Noise.php @@ -5,7 +5,7 @@ /** * Different noise generators for level generation */ -namespace devmine\levels\generator\noise; +namespace devmine\worlds\generator\noise; abstract class Noise{ @@ -44,7 +44,7 @@ public static function bilinearLerp($x, $y, $q00, $q01, $q10, $q11, $x1, $x2, $y ); } - public static function trilinearLerp($x, $y, $z, $q000, $q001, $q010, $q011, $q100, $q101, $q110, $q111, $x1, $x2, $y1, $y2, $z1, $z2) { + public static function trilinearLerp($x, $y, $z, $q000, $q001, $q010, $q011, $q100, $q101, $q110, $q111, $x1, $x2, $y1, $y2, $z1, $z2){ $dx1 = (($x2 - $x) / ($x2 - $x1)); $dx2 = (($x - $x1) / ($x2 - $x1)); $dy1 = (($y2 - $y) / ($y2 - $y1)); diff --git a/src/devmine/levels/generator/noise/Perlin.php b/src/devmine/worlds/generator/noise/Perlin.php similarity index 98% rename from src/devmine/levels/generator/noise/Perlin.php rename to src/devmine/worlds/generator/noise/Perlin.php index 60739a8..4afb9dd 100644 --- a/src/devmine/levels/generator/noise/Perlin.php +++ b/src/devmine/worlds/generator/noise/Perlin.php @@ -2,7 +2,7 @@ -namespace devmine\levels\generator\noise; +namespace devmine\worlds\generator\noise; use devmine\utilities\main\Random; diff --git a/src/devmine/levels/generator/noise/Simplex.php b/src/devmine/worlds/generator/noise/Simplex.php similarity index 99% rename from src/devmine/levels/generator/noise/Simplex.php rename to src/devmine/worlds/generator/noise/Simplex.php index 181a3b5..bf39dc0 100644 --- a/src/devmine/levels/generator/noise/Simplex.php +++ b/src/devmine/worlds/generator/noise/Simplex.php @@ -2,7 +2,7 @@ -namespace devmine\levels\generator\noise; +namespace devmine\worlds\generator\noise; use devmine\utilities\main\Random; diff --git a/src/devmine/levels/generator/normal/Normal.php b/src/devmine/worlds/generator/normal/Normal.php similarity index 66% rename from src/devmine/levels/generator/normal/Normal.php rename to src/devmine/worlds/generator/normal/Normal.php index 2b06a0d..e0e546d 100644 --- a/src/devmine/levels/generator/normal/Normal.php +++ b/src/devmine/worlds/generator/normal/Normal.php @@ -1,30 +1,8 @@ waterHeight; + public function getName(){ + return "normal"; } public function getSettings(){ @@ -134,9 +102,9 @@ public function init(ChunkManager $level, Random $random){ $this->random->setSeed($this->level->getSeed()); $this->selector = new BiomeSelector($this->random, function($temperature, $rainfall){ if($rainfall < 0.25){ - if($temperature < 0.7){ + if($rainfall < 0.7){ return Biome::OCEAN; - }elseif($temperature < 0.85){ + }elseif($rainfall < 0.85){ return Biome::RIVER; }else{ return Biome::SWAMP; @@ -158,9 +126,9 @@ public function init(ChunkManager $level, Random $random){ return Biome::BIRCH_FOREST; } }else{ - if($temperature < 0.25){ + if($rainfall < 0.25){ return Biome::MOUNTAINS; - }elseif($temperature < 0.70){ + }elseif($rainfall < 0.70){ return Biome::SMALL_MOUNTAINS; }else{ return Biome::RIVER; @@ -194,9 +162,6 @@ public function init(ChunkManager $level, Random $random){ new OreType(new GoldOre(), 2, 8, 0, 32), new OreType(new DiamondOre(), 1, 7, 0, 16), new OreType(new Dirt(), 20, 32, 0, 128), - new OreType(new Stone(Stone::GRANITE), 20, 32, 0, 128), - new OreType(new Stone(Stone::DIORITE), 20, 32, 0, 128), - new OreType(new Stone(Stone::ANDESITE), 20, 32, 0, 128), new OreType(new Gravel(), 10, 16, 0, 128) ]); $this->populators[] = $ores; @@ -219,7 +184,6 @@ public function generateChunk($chunkX, $chunkZ){ $biome = $this->pickBiome($chunkX * 16 + $x, $chunkZ * 16 + $z); $chunk->setBiomeId($x, $z, $biome->getId()); - $color = [0, 0, 0]; for($sx = -self::$SMOOTH_SIZE; $sx <= self::$SMOOTH_SIZE; ++$sx){ for($sz = -self::$SMOOTH_SIZE; $sz <= self::$SMOOTH_SIZE; ++$sz){ @@ -239,10 +203,6 @@ public function generateChunk($chunkX, $chunkZ){ $minSum += ($adjacent->getMinElevation() - 1) * $weight; $maxSum += $adjacent->getMaxElevation() * $weight; - $bColor = $adjacent->getColor(); - $color[0] += (($bColor >> 16) ** 2) * $weight; - $color[1] += ((($bColor >> 8) & 0xff) ** 2) * $weight; - $color[2] += (($bColor & 0xff) ** 2) * $weight; $weightSum += $weight; } @@ -251,31 +211,18 @@ public function generateChunk($chunkX, $chunkZ){ $minSum /= $weightSum; $maxSum /= $weightSum; - $chunk->setBiomeColor($x, $z, sqrt($color[0] / $weightSum), sqrt($color[1] / $weightSum), sqrt($color[2] / $weightSum)); + $smoothHeight = ($maxSum - $minSum) / 2; - $solidLand = false; - for($y = 127; $y >= 0; --$y){ + for($y = 0; $y < 128; ++$y){ if($y === 0){ $chunk->setBlockId($x, $y, $z, Block::BEDROCK); continue; } - - // A noiseAdjustment of 1 will guarantee ground, a noiseAdjustment of -1 will guarantee air. - //$effHeight = min($y - $smoothHeight - $minSum, - $noiseAdjustment = 2 * (($maxSum - $y) / ($maxSum - $minSum)) - 1; - - - // To generate caves, we bring the noiseAdjustment down away from 1. - $caveLevel = $minSum - 10; - $distAboveCaveLevel = max(0, $y - $caveLevel); // must be positive - - $noiseAdjustment = min($noiseAdjustment, 0.4 + ($distAboveCaveLevel / 10)); - $noiseValue = $noise[$x][$z][$y] + $noiseAdjustment; + $noiseValue = $noise[$x][$z][$y] - 1 / $smoothHeight * ($y - $smoothHeight - $minSum); if($noiseValue > 0){ $chunk->setBlockId($x, $y, $z, Block::STONE); - $solidLand = true; - }elseif($y <= $this->waterHeight && $solidLand == false){ + }elseif($y <= $this->waterHeight){ $chunk->setBlockId($x, $y, $z, Block::STILL_WATER); } } diff --git a/src/devmine/levels/generator/normal/biome/DesertBiome.php b/src/devmine/worlds/generator/normal/biome/DesertBiome.php similarity index 71% rename from src/devmine/levels/generator/normal/biome/DesertBiome.php rename to src/devmine/worlds/generator/normal/biome/DesertBiome.php index 597ab9e..8d3fcfe 100644 --- a/src/devmine/levels/generator/normal/biome/DesertBiome.php +++ b/src/devmine/worlds/generator/normal/biome/DesertBiome.php @@ -2,8 +2,7 @@ -namespace devmine\levels\generator\normal\biome; - +namespace devmine\worlds\generator\normal\biome; class DesertBiome extends SandyBiome{ @@ -16,7 +15,7 @@ public function __construct(){ $this->rainfall = 0; } - public function getName() : string{ + public function getName(){ return "Desert"; } } \ No newline at end of file diff --git a/src/devmine/levels/generator/normal/biome/ForestBiome.php b/src/devmine/worlds/generator/normal/biome/ForestBiome.php similarity index 81% rename from src/devmine/levels/generator/normal/biome/ForestBiome.php rename to src/devmine/worlds/generator/normal/biome/ForestBiome.php index 808ca4d..d7ff28c 100644 --- a/src/devmine/levels/generator/normal/biome/ForestBiome.php +++ b/src/devmine/worlds/generator/normal/biome/ForestBiome.php @@ -2,11 +2,11 @@ -namespace devmine\levels\generator\normal\biome; +namespace devmine\worlds\generator\normal\biome; use devmine\inventory\blocks\Sapling; -use devmine\levels\generator\populator\TallGrass; -use devmine\levels\generator\populator\Tree; +use devmine\worlds\generator\populator\TallGrass; +use devmine\worlds\generator\populator\Tree; class ForestBiome extends GrassyBiome{ @@ -40,7 +40,7 @@ public function __construct($type = self::TYPE_NORMAL){ } } - public function getName() : string{ + public function getName(){ return $this->type === self::TYPE_BIRCH ? "Birch Forest" : "Forest"; } } \ No newline at end of file diff --git a/src/devmine/levels/generator/normal/biome/GrassyBiome.php b/src/devmine/worlds/generator/normal/biome/GrassyBiome.php similarity index 86% rename from src/devmine/levels/generator/normal/biome/GrassyBiome.php rename to src/devmine/worlds/generator/normal/biome/GrassyBiome.php index 2b1dfb5..9e9f7c8 100644 --- a/src/devmine/levels/generator/normal/biome/GrassyBiome.php +++ b/src/devmine/worlds/generator/normal/biome/GrassyBiome.php @@ -2,7 +2,7 @@ -namespace devmine\levels\generator\normal\biome; +namespace devmine\worlds\generator\normal\biome; use devmine\inventory\blocks\Block; diff --git a/src/devmine/levels/generator/normal/biome/IcePlainsBiome.php b/src/devmine/worlds/generator/normal/biome/IcePlainsBiome.php similarity index 70% rename from src/devmine/levels/generator/normal/biome/IcePlainsBiome.php rename to src/devmine/worlds/generator/normal/biome/IcePlainsBiome.php index b0b13de..0b22c44 100644 --- a/src/devmine/levels/generator/normal/biome/IcePlainsBiome.php +++ b/src/devmine/worlds/generator/normal/biome/IcePlainsBiome.php @@ -2,9 +2,9 @@ -namespace devmine\levels\generator\normal\biome; +namespace devmine\worlds\generator\normal\biome; -use devmine\levels\generator\populator\TallGrass; +use devmine\worlds\generator\populator\TallGrass; class IcePlainsBiome extends SnowyBiome{ @@ -22,7 +22,7 @@ public function __construct(){ $this->rainfall = 0.8; } - public function getName() : string{ + public function getName(){ return "Ice Plains"; } } \ No newline at end of file diff --git a/src/devmine/levels/generator/normal/biome/MountainsBiome.php b/src/devmine/worlds/generator/normal/biome/MountainsBiome.php similarity index 65% rename from src/devmine/levels/generator/normal/biome/MountainsBiome.php rename to src/devmine/worlds/generator/normal/biome/MountainsBiome.php index 0578c4b..4478d25 100644 --- a/src/devmine/levels/generator/normal/biome/MountainsBiome.php +++ b/src/devmine/worlds/generator/normal/biome/MountainsBiome.php @@ -2,10 +2,10 @@ -namespace devmine\levels\generator\normal\biome; +namespace devmine\worlds\generator\normal\biome; -use devmine\levels\generator\populator\TallGrass; -use devmine\levels\generator\populator\Tree; +use devmine\worlds\generator\populator\TallGrass; +use devmine\worlds\generator\populator\Tree; class MountainsBiome extends GrassyBiome{ @@ -17,7 +17,7 @@ public function __construct(){ $this->addPopulator($trees); $tallGrass = new TallGrass(); - $tallGrass->setBaseAmount(6); + $tallGrass->setBaseAmount(1); $this->addPopulator($tallGrass); @@ -29,7 +29,7 @@ public function __construct(){ $this->rainfall = 0.5; } - public function getName() : string{ + public function getName(){ return "Mountains"; } } \ No newline at end of file diff --git a/src/devmine/worlds/generator/normal/biome/NormalBiome.php b/src/devmine/worlds/generator/normal/biome/NormalBiome.php new file mode 100644 index 0000000..1d77f4d --- /dev/null +++ b/src/devmine/worlds/generator/normal/biome/NormalBiome.php @@ -0,0 +1,11 @@ +setBaseAmount(5); + + $this->addPopulator($tallGrass); + + $this->setElevation(46, 58); + + $this->temperature = 0.5; + $this->rainfall = 0.5; + } + + public function getName(){ + return "Ocean"; + } +} \ No newline at end of file diff --git a/src/devmine/worlds/generator/normal/biome/PlainBiome.php b/src/devmine/worlds/generator/normal/biome/PlainBiome.php new file mode 100644 index 0000000..ef3fab9 --- /dev/null +++ b/src/devmine/worlds/generator/normal/biome/PlainBiome.php @@ -0,0 +1,28 @@ +setBaseAmount(12); + + $this->addPopulator($tallGrass); + + $this->setElevation(63, 74); + + $this->temperature = 0.8; + $this->rainfall = 0.4; + } + + public function getName(){ + return "Plains"; + } +} \ No newline at end of file diff --git a/src/devmine/worlds/generator/normal/biome/RiverBiome.php b/src/devmine/worlds/generator/normal/biome/RiverBiome.php new file mode 100644 index 0000000..65d0e76 --- /dev/null +++ b/src/devmine/worlds/generator/normal/biome/RiverBiome.php @@ -0,0 +1,28 @@ +setBaseAmount(5); + + $this->addPopulator($tallGrass); + + $this->setElevation(58, 62); + + $this->temperature = 0.5; + $this->rainfall = 0.7; + } + + public function getName(){ + return "River"; + } +} \ No newline at end of file diff --git a/src/devmine/worlds/generator/normal/biome/SandyBiome.php b/src/devmine/worlds/generator/normal/biome/SandyBiome.php new file mode 100644 index 0000000..c24e1ba --- /dev/null +++ b/src/devmine/worlds/generator/normal/biome/SandyBiome.php @@ -0,0 +1,20 @@ +setGroundCover([ + Block::get(Block::SAND, 0), + Block::get(Block::SAND, 0), + Block::get(Block::SANDSTONE, 0), + Block::get(Block::SANDSTONE, 0), + Block::get(Block::SANDSTONE, 0), + ]); + } +} \ No newline at end of file diff --git a/src/devmine/levels/generator/normal/biome/SmallMountainsBiome.php b/src/devmine/worlds/generator/normal/biome/SmallMountainsBiome.php similarity index 68% rename from src/devmine/levels/generator/normal/biome/SmallMountainsBiome.php rename to src/devmine/worlds/generator/normal/biome/SmallMountainsBiome.php index ea8e7bc..4be0485 100644 --- a/src/devmine/levels/generator/normal/biome/SmallMountainsBiome.php +++ b/src/devmine/worlds/generator/normal/biome/SmallMountainsBiome.php @@ -2,7 +2,7 @@ -namespace devmine\levels\generator\normal\biome; +namespace devmine\worlds\generator\normal\biome; class SmallMountainsBiome extends MountainsBiome{ @@ -13,7 +13,7 @@ public function __construct(){ $this->setElevation(63, 97); } - public function getName() : string{ + public function getName(){ return "Small Mountains"; } } \ No newline at end of file diff --git a/src/devmine/levels/generator/normal/biome/SnowyBiome.php b/src/devmine/worlds/generator/normal/biome/SnowyBiome.php similarity index 86% rename from src/devmine/levels/generator/normal/biome/SnowyBiome.php rename to src/devmine/worlds/generator/normal/biome/SnowyBiome.php index a798d3b..b0aaf65 100644 --- a/src/devmine/levels/generator/normal/biome/SnowyBiome.php +++ b/src/devmine/worlds/generator/normal/biome/SnowyBiome.php @@ -2,7 +2,7 @@ -namespace devmine\levels\generator\normal\biome; +namespace devmine\worlds\generator\normal\biome; use devmine\inventory\blocks\Block; diff --git a/src/devmine/worlds/generator/normal/biome/SwampBiome.php b/src/devmine/worlds/generator/normal/biome/SwampBiome.php new file mode 100644 index 0000000..cd6c230 --- /dev/null +++ b/src/devmine/worlds/generator/normal/biome/SwampBiome.php @@ -0,0 +1,21 @@ +setElevation(62, 63); + + $this->temperature = 0.8; + $this->rainfall = 0.9; + } + + public function getName(){ + return "Swamp"; + } +} \ No newline at end of file diff --git a/src/devmine/worlds/generator/normal/biome/TaigaBiome.php b/src/devmine/worlds/generator/normal/biome/TaigaBiome.php new file mode 100644 index 0000000..d67934a --- /dev/null +++ b/src/devmine/worlds/generator/normal/biome/TaigaBiome.php @@ -0,0 +1,34 @@ +setBaseAmount(10); + $this->addPopulator($trees); + + $tallGrass = new TallGrass(); + $tallGrass->setBaseAmount(1); + + $this->addPopulator($tallGrass); + + $this->setElevation(63, 81); + + $this->temperature = 0.05; + $this->rainfall = 0.8; + } + + public function getName(){ + return "Taiga"; + } +} \ No newline at end of file diff --git a/src/devmine/worlds/generator/object/BigTree.php b/src/devmine/worlds/generator/object/BigTree.php new file mode 100644 index 0000000..985a2e5 --- /dev/null +++ b/src/devmine/worlds/generator/object/BigTree.php @@ -0,0 +1,67 @@ +trunkHeight = (int) ($this->totalHeight * $this->trunkHeightMultiplier); + $leaves = $this->getLeafGroupPoints($level, $pos); + foreach($leaves as $leafGroup){ + $groupX = $leafGroup->getBlockX(); + $groupY = $leafGroup->getBlockY(); + $groupZ = $leafGroup->getBlockZ(); + for($yy = $groupY; $yy < $groupY + $this->leafDistanceLimit; ++$yy){ + $this->generateGroupLayer($level, $groupX, $yy, $groupZ, $this->getLeafGroupLayerSize($yy - $groupY)); + } + } + /*final BlockIterator trunk = new BlockIterator(new Point(w, x, y - 1, z), new Point(w, x, y + trunkHeight, z)); + while (trunk.hasNext()) { + trunk.next().setMaterial(VanillaMaterials.LOG, logMetadata); + } + generateBranches(w, x, y, z, leaves); + + $level->setBlock($x, $pos->y - 1, $z, 3, 0); + $this->totalHeight += $random->nextRange(0, 2); + $this->leavesHeight += mt_rand(0, 1); + for($yy = ($this->totalHeight - $this->leavesHeight); $yy < ($this->totalHeight + 1); ++$yy){ + $yRadius = ($yy - $this->totalHeight); + $xzRadius = (int) (($this->radiusIncrease + 1) - $yRadius / 2); + for($xx = -$xzRadius; $xx < ($xzRadius + 1); ++$xx){ + for($zz = -$xzRadius; $zz < ($xzRadius + 1); ++$zz){ + if((abs($xx) != $xzRadius or abs($zz) != $xzRadius) and $yRadius != 0){ + $level->setBlock($pos->x + $xx, $pos->y + $yy, $pos->z + $zz, 18, $type); + } + } + } + } + for($yy = 0; $yy < ($this->totalHeight - 1); ++$yy){ + $level->setBlock($x, $pos->y + $yy, $z, 17, $type); + } + */ + } + + +} \ No newline at end of file diff --git a/src/devmine/levels/generator/object/BirchTree.php b/src/devmine/worlds/generator/object/BirchTree.php similarity index 80% rename from src/devmine/levels/generator/object/BirchTree.php rename to src/devmine/worlds/generator/object/BirchTree.php index 07138e4..43faad3 100644 --- a/src/devmine/levels/generator/object/BirchTree.php +++ b/src/devmine/worlds/generator/object/BirchTree.php @@ -2,12 +2,11 @@ -namespace devmine\levels\generator\object; +namespace devmine\worlds\generator\object; use devmine\inventory\blocks\Block; -use devmine\inventory\blocks\Leaves; use devmine\inventory\blocks\Wood; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\utilities\main\Random; class BirchTree extends Tree{ @@ -17,7 +16,6 @@ class BirchTree extends Tree{ public function __construct($superBirch = false){ $this->trunkBlock = Block::LOG; $this->leafBlock = Block::LEAVES; - $this->leafType = Leaves::BIRCH; $this->type = Wood::BIRCH; $this->superBirch = (bool) $superBirch; } diff --git a/src/devmine/levels/generator/object/JungleTree.php b/src/devmine/worlds/generator/object/JungleTree.php similarity index 70% rename from src/devmine/levels/generator/object/JungleTree.php rename to src/devmine/worlds/generator/object/JungleTree.php index 6c66a13..84852ec 100644 --- a/src/devmine/levels/generator/object/JungleTree.php +++ b/src/devmine/worlds/generator/object/JungleTree.php @@ -2,10 +2,9 @@ -namespace devmine\levels\generator\object; +namespace devmine\worlds\generator\object; use devmine\inventory\blocks\Block; -use devmine\inventory\blocks\Leaves; use devmine\inventory\blocks\Wood; class JungleTree extends Tree{ @@ -13,7 +12,6 @@ class JungleTree extends Tree{ public function __construct(){ $this->trunkBlock = Block::LOG; $this->leafBlock = Block::LEAVES; - $this->leafType = Leaves::JUNGLE; $this->type = Wood::JUNGLE; $this->treeHeight = 8; } diff --git a/src/devmine/levels/generator/object/OakTree.php b/src/devmine/worlds/generator/object/OakTree.php similarity index 76% rename from src/devmine/levels/generator/object/OakTree.php rename to src/devmine/worlds/generator/object/OakTree.php index 1e0ae9a..7afc287 100644 --- a/src/devmine/levels/generator/object/OakTree.php +++ b/src/devmine/worlds/generator/object/OakTree.php @@ -2,12 +2,11 @@ -namespace devmine\levels\generator\object; +namespace devmine\worlds\generator\object; use devmine\inventory\blocks\Block; -use devmine\inventory\blocks\Leaves; use devmine\inventory\blocks\Wood; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\utilities\main\Random; class OakTree extends Tree{ @@ -15,7 +14,6 @@ class OakTree extends Tree{ public function __construct(){ $this->trunkBlock = Block::LOG; $this->leafBlock = Block::LEAVES; - $this->leafType = Leaves::OAK; $this->type = Wood::OAK; } diff --git a/src/devmine/levels/generator/object/Object.php b/src/devmine/worlds/generator/object/Object.php similarity index 69% rename from src/devmine/levels/generator/object/Object.php rename to src/devmine/worlds/generator/object/Object.php index 1f75bc5..b9472b3 100644 --- a/src/devmine/levels/generator/object/Object.php +++ b/src/devmine/worlds/generator/object/Object.php @@ -5,7 +5,7 @@ /** * All the different object classes used in populators */ -namespace devmine\levels\generator\object; +namespace devmine\worlds\generator\object; abstract class Object{ diff --git a/src/devmine/levels/generator/object/NetherOre.php b/src/devmine/worlds/generator/object/Ore.php similarity index 88% rename from src/devmine/levels/generator/object/NetherOre.php rename to src/devmine/worlds/generator/object/Ore.php index 740950e..b66a5bd 100644 --- a/src/devmine/levels/generator/object/NetherOre.php +++ b/src/devmine/worlds/generator/object/Ore.php @@ -2,13 +2,13 @@ -namespace devmine\levels\generator\object; +namespace devmine\worlds\generator\object; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\server\calculations\VectorMath; use devmine\utilities\main\Random; -class NetherOre{ +class Ore{ private $random; public $type; @@ -22,7 +22,7 @@ public function getType(){ } public function canPlaceObject(ChunkManager $level, $x, $y, $z){ - return ($level->getBlockIdAt($x, $y, $z) === 87); + return ($level->getBlockIdAt($x, $y, $z) === 1); } public function placeObject(ChunkManager $level, $x, $y, $z){ @@ -35,7 +35,6 @@ public function placeObject(ChunkManager $level, $x, $y, $z){ $z2 = $z + 8 - $offset->y; $y1 = $y + $this->random->nextBoundedInt(3) + 2; $y2 = $y + $this->random->nextBoundedInt(3) + 2; - for($count = 0; $count <= $clusterSize; ++$count){ $seedX = $x1 + ($x2 - $x1) * $count / $clusterSize; $seedY = $y1 + ($y2 - $y1) * $count / $clusterSize; @@ -48,7 +47,7 @@ public function placeObject(ChunkManager $level, $x, $y, $z){ $endX = (int) ($seedX + $size); $endY = (int) ($seedY + $size); $endZ = (int) ($seedZ + $size); - //echo "ORE: $startX, $startY, $startZ,, $endX, $endY, $endZ\n"; + for($x = $startX; $x <= $endX; ++$x){ $sizeX = ($x + 0.5 - $seedX) / $size; $sizeX *= $sizeX; @@ -63,12 +62,11 @@ public function placeObject(ChunkManager $level, $x, $y, $z){ $sizeZ = ($z + 0.5 - $seedZ) / $size; $sizeZ *= $sizeZ; - if(($sizeX + $sizeY + $sizeZ) < 1 and $level->getBlockIdAt($x, $y, $z) === 87){ + if(($sizeX + $sizeY + $sizeZ) < 1 and $level->getBlockIdAt($x, $y, $z) === 1){ $level->setBlockIdAt($x, $y, $z, $this->type->material->getId()); if($this->type->material->getDamage() !== 0){ $level->setBlockDataAt($x, $y, $z, $this->type->material->getDamage()); } - //echo "Placed to $x, $y, $z\n"; } } } diff --git a/src/devmine/levels/generator/object/OreType.php b/src/devmine/worlds/generator/object/OreType.php similarity index 91% rename from src/devmine/levels/generator/object/OreType.php rename to src/devmine/worlds/generator/object/OreType.php index aea4178..840ca75 100644 --- a/src/devmine/levels/generator/object/OreType.php +++ b/src/devmine/worlds/generator/object/OreType.php @@ -2,7 +2,7 @@ -namespace devmine\levels\generator\object; +namespace devmine\worlds\generator\object; use devmine\inventory\blocks\Block; diff --git a/src/devmine/levels/generator/object/Pond.php b/src/devmine/worlds/generator/object/Pond.php similarity index 85% rename from src/devmine/levels/generator/object/Pond.php rename to src/devmine/worlds/generator/object/Pond.php index 086fdb0..9a28404 100644 --- a/src/devmine/levels/generator/object/Pond.php +++ b/src/devmine/worlds/generator/object/Pond.php @@ -2,10 +2,10 @@ -namespace devmine\levels\generator\object; +namespace devmine\worlds\generator\object; use devmine\inventory\blocks\Block; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\server\calculations\Vector3 as Vector3; use devmine\utilities\main\Random; diff --git a/src/devmine/levels/generator/object/SpruceTree.php b/src/devmine/worlds/generator/object/SpruceTree.php similarity index 78% rename from src/devmine/levels/generator/object/SpruceTree.php rename to src/devmine/worlds/generator/object/SpruceTree.php index cf65601..97d192c 100644 --- a/src/devmine/levels/generator/object/SpruceTree.php +++ b/src/devmine/worlds/generator/object/SpruceTree.php @@ -2,12 +2,11 @@ -namespace devmine\levels\generator\object; +namespace devmine\worlds\generator\object; use devmine\inventory\blocks\Block; -use devmine\inventory\blocks\Leaves; use devmine\inventory\blocks\Wood; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\utilities\main\Random; class SpruceTree extends Tree{ @@ -15,7 +14,6 @@ class SpruceTree extends Tree{ public function __construct(){ $this->trunkBlock = Block::LOG; $this->leafBlock = Block::LEAVES; - $this->leafType = Leaves::SPRUCE; $this->type = Wood::SPRUCE; $this->treeHeight = 10; } @@ -24,7 +22,7 @@ public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ $this->treeHeight = $random->nextBoundedInt(4) + 6; $topSize = $this->treeHeight - (1 + $random->nextBoundedInt(2)); - $lRadius = 2 + $random->nextBoundedInt(2); + $lRadius = 2 + $random->nextBoundedInt(2); $this->placeTrunk($level, $x, $y, $z, $random, $this->treeHeight - $random->nextBoundedInt(3)); @@ -39,7 +37,7 @@ public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ $xOff = abs($xx - $x); for($zz = $z - $radius; $zz <= $z + $radius; ++$zz){ $zOff = abs($zz - $z); - if($xOff === $radius and $zOff === $radius and $radius > 0){ + if($xOff === $radius and $zOff === $radius and $radius > 0){ continue; } @@ -47,10 +45,10 @@ public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ $level->setBlockIdAt($xx, $yyy, $zz, $this->leafBlock); $level->setBlockDataAt($xx, $yyy, $zz, $this->type); } - } - } + } + } - if($radius >= $maxR){ + if($radius >= $maxR){ $radius = $minR; $minR = 1; if(++$maxR > $lRadius){ diff --git a/src/devmine/levels/generator/object/TallGrass.php b/src/devmine/worlds/generator/object/TallGrass.php similarity index 92% rename from src/devmine/levels/generator/object/TallGrass.php rename to src/devmine/worlds/generator/object/TallGrass.php index 0e20abc..695d1bd 100644 --- a/src/devmine/levels/generator/object/TallGrass.php +++ b/src/devmine/worlds/generator/object/TallGrass.php @@ -2,10 +2,10 @@ -namespace devmine\levels\generator\object; +namespace devmine\worlds\generator\object; use devmine\inventory\blocks\Block; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\server\calculations\Vector3 as Vector3; use devmine\utilities\main\Random; diff --git a/src/devmine/levels/generator/object/Tree.php b/src/devmine/worlds/generator/object/Tree.php similarity index 85% rename from src/devmine/levels/generator/object/Tree.php rename to src/devmine/worlds/generator/object/Tree.php index 5ec3515..9baf675 100644 --- a/src/devmine/levels/generator/object/Tree.php +++ b/src/devmine/worlds/generator/object/Tree.php @@ -2,11 +2,11 @@ -namespace devmine\levels\generator\object; +namespace devmine\worlds\generator\object; use devmine\inventory\blocks\Block; use devmine\inventory\blocks\Sapling; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\utilities\main\Random; abstract class Tree{ @@ -24,9 +24,8 @@ abstract class Tree{ public $trunkBlock = Block::LOG; public $leafBlock = Block::LEAVES; public $treeHeight = 7; - public $leafType = 0; - public static function growTree(ChunkManager $level, $x, $y, $z, Random $random, $type = 0, bool $noBigTree = true){ + public static function growTree(ChunkManager $level, $x, $y, $z, Random $random, $type = 0){ switch($type){ case Sapling::SPRUCE: $tree = new SpruceTree(); @@ -41,19 +40,14 @@ public static function growTree(ChunkManager $level, $x, $y, $z, Random $random, case Sapling::JUNGLE: $tree = new JungleTree(); break; - case Sapling::ACACIA: - $tree = new AcaciaTree(); - break; - case Sapling::DARK_OAK: - $tree = new DarkOakTree(); - break; case Sapling::OAK: default: - if(!$noBigTree and $random->nextRange(0, 9) === 0){ + $tree = new OakTree(); + /*if($random->nextRange(0, 9) === 0){ $tree = new BigTree(); - }else{ - $tree = new OakTree(); - } + }else{*/ + + //} break; } if($tree->canPlaceObject($level, $x, $y, $z, $random)){ @@ -96,7 +90,7 @@ public function placeObject(ChunkManager $level, $x, $y, $z, Random $random){ } if(!Block::$solid[$level->getBlockIdAt($xx, $yy, $zz)]){ $level->setBlockIdAt($xx, $yy, $zz, $this->leafBlock); - $level->setBlockDataAt($xx, $yy, $zz, $this->leafType); + $level->setBlockDataAt($xx, $yy, $zz, $this->type); } } } diff --git a/src/devmine/levels/generator/populator/GroundCover.php b/src/devmine/worlds/generator/populator/GroundCover.php similarity index 69% rename from src/devmine/levels/generator/populator/GroundCover.php rename to src/devmine/worlds/generator/populator/GroundCover.php index d151c04..0543acc 100644 --- a/src/devmine/levels/generator/populator/GroundCover.php +++ b/src/devmine/worlds/generator/populator/GroundCover.php @@ -2,22 +2,17 @@ -namespace devmine\levels\generator\populator; +namespace devmine\worlds\generator\populator; use devmine\inventory\blocks\Block; -use devmine\levels\ChunkManager; -use devmine\levels\generator\biome\Biome; -use devmine\levels\Level; -use devmine\levels\SimpleChunkManager; +use devmine\worlds\ChunkManager; +use devmine\worlds\generator\biome\Biome; use devmine\utilities\main\Random; class GroundCover extends Populator{ public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ $chunk = $level->getChunk($chunkX, $chunkZ); - if($level instanceof Level or $level instanceof SimpleChunkManager){ - $waterHeight = $level->getWaterHeight(); - } else $waterHeight = 0; for($x = 0; $x < 16; ++$x){ for($z = 0; $z < 16; ++$z){ $biome = Biome::getBiome($chunk->getBiomeId($x, $z)); @@ -41,9 +36,6 @@ public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ if($column{$y} === "\x00" and $b->isSolid()){ break; } - if($y <= $waterHeight and $b->getId() == Block::GRASS and $chunk->getBlockId($x, $y + 1, $z) == Block::STILL_WATER){ - $b = Block::get(Block::DIRT); - } if($b->getDamage() === 0){ $chunk->setBlockId($x, $y, $z, $b->getId()); }else{ diff --git a/src/devmine/levels/generator/populator/Mineshaft.php b/src/devmine/worlds/generator/populator/Mineshaft.php similarity index 83% rename from src/devmine/levels/generator/populator/Mineshaft.php rename to src/devmine/worlds/generator/populator/Mineshaft.php index d36c671..8b220df 100644 --- a/src/devmine/levels/generator/populator/Mineshaft.php +++ b/src/devmine/worlds/generator/populator/Mineshaft.php @@ -2,9 +2,9 @@ -namespace devmine\levels\generator\populator; +namespace devmine\worlds\generator\populator; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\utilities\main\Random; class Mineshaft extends Populator{ diff --git a/src/devmine/levels/generator/populator/Ore.php b/src/devmine/worlds/generator/populator/Ore.php similarity index 84% rename from src/devmine/levels/generator/populator/Ore.php rename to src/devmine/worlds/generator/populator/Ore.php index 5d4979f..446458d 100644 --- a/src/devmine/levels/generator/populator/Ore.php +++ b/src/devmine/worlds/generator/populator/Ore.php @@ -2,10 +2,10 @@ -namespace devmine\levels\generator\populator; +namespace devmine\worlds\generator\populator; -use devmine\levels\ChunkManager; -use devmine\levels\generator\object\Ore as ObjectOre; +use devmine\worlds\ChunkManager; +use devmine\worlds\generator\object\Ore as ObjectOre; use devmine\utilities\main\Random; class Ore extends Populator{ diff --git a/src/devmine/levels/generator/populator/Pond.php b/src/devmine/worlds/generator/populator/Pond.php similarity index 85% rename from src/devmine/levels/generator/populator/Pond.php rename to src/devmine/worlds/generator/populator/Pond.php index a43f71d..a0e18b6 100644 --- a/src/devmine/levels/generator/populator/Pond.php +++ b/src/devmine/worlds/generator/populator/Pond.php @@ -2,10 +2,10 @@ -namespace devmine\levels\generator\populator; +namespace devmine\worlds\generator\populator; use devmine\inventory\blocks\Water; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\utilities\main\Random; class Pond extends Populator{ @@ -18,7 +18,7 @@ public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ $x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 16); $y = $random->nextBoundedInt(128); $z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 16); - $pond = new \devmine\levels\generator\object\Pond($random, new Water()); + $pond = new \devmine\worlds\generator\object\Pond($random, new Water()); if($pond->canPlaceObject($level, $x, $y, $z)){ $pond->placeObject($level, $x, $y, $z); } diff --git a/src/devmine/levels/generator/populator/Populator.php b/src/devmine/worlds/generator/populator/Populator.php similarity index 72% rename from src/devmine/levels/generator/populator/Populator.php rename to src/devmine/worlds/generator/populator/Populator.php index 3c4af17..b4f123a 100644 --- a/src/devmine/levels/generator/populator/Populator.php +++ b/src/devmine/worlds/generator/populator/Populator.php @@ -5,9 +5,9 @@ /** * All the Object populator classes */ -namespace devmine\levels\generator\populator; +namespace devmine\worlds\generator\populator; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\utilities\main\Random; abstract class Populator{ diff --git a/src/devmine/levels/generator/populator/TallGrass.php b/src/devmine/worlds/generator/populator/TallGrass.php similarity index 94% rename from src/devmine/levels/generator/populator/TallGrass.php rename to src/devmine/worlds/generator/populator/TallGrass.php index 867a1da..a711692 100644 --- a/src/devmine/levels/generator/populator/TallGrass.php +++ b/src/devmine/worlds/generator/populator/TallGrass.php @@ -2,10 +2,10 @@ -namespace devmine\levels\generator\populator; +namespace devmine\worlds\generator\populator; use devmine\inventory\blocks\Block; -use devmine\levels\ChunkManager; +use devmine\worlds\ChunkManager; use devmine\utilities\main\Random; class TallGrass extends Populator{ diff --git a/src/devmine/levels/generator/populator/Tree.php b/src/devmine/worlds/generator/populator/Tree.php similarity index 85% rename from src/devmine/levels/generator/populator/Tree.php rename to src/devmine/worlds/generator/populator/Tree.php index eb5b9cc..d0a2262 100644 --- a/src/devmine/levels/generator/populator/Tree.php +++ b/src/devmine/worlds/generator/populator/Tree.php @@ -2,12 +2,12 @@ -namespace devmine\levels\generator\populator; +namespace devmine\worlds\generator\populator; use devmine\inventory\blocks\Block; use devmine\inventory\blocks\Sapling; -use devmine\levels\ChunkManager; -use devmine\levels\generator\object\Tree as ObjectTree; +use devmine\worlds\ChunkManager; +use devmine\worlds\generator\object\Tree as ObjectTree; use devmine\utilities\main\Random; class Tree extends Populator{ @@ -47,7 +47,7 @@ public function populate(ChunkManager $level, $chunkX, $chunkZ, Random $random){ private function getHighestWorkableBlock($x, $z){ for($y = 127; $y > 0; --$y){ $b = $this->level->getBlockIdAt($x, $y, $z); - if($b === Block::DIRT or $b === Block::GRASS or $b === Block::PODZOL){ + if($b === Block::DIRT or $b === Block::GRASS){ break; }elseif($b !== 0 and $b !== Block::SNOW_LAYER){ return -1; @@ -56,4 +56,4 @@ private function getHighestWorkableBlock($x, $z){ return ++$y; } -} +} \ No newline at end of file diff --git a/src/devmine/levels/particle/AngryVillagerParticle.php b/src/devmine/worlds/particle/AngryVillagerParticle.php similarity index 85% rename from src/devmine/levels/particle/AngryVillagerParticle.php rename to src/devmine/worlds/particle/AngryVillagerParticle.php index d36df99..d15f1f2 100644 --- a/src/devmine/levels/particle/AngryVillagerParticle.php +++ b/src/devmine/worlds/particle/AngryVillagerParticle.php @@ -2,7 +2,7 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\server\calculations\Vector3; diff --git a/src/devmine/worlds/particle/BlockForceFieldParticle.php b/src/devmine/worlds/particle/BlockForceFieldParticle.php new file mode 100644 index 0000000..fd3e1e4 --- /dev/null +++ b/src/devmine/worlds/particle/BlockForceFieldParticle.php @@ -0,0 +1,13 @@ +x, $pos->y, $pos->z); $this->data = $b->getId() + ($b->getDamage() << 12); } - + public function encode(){ $pk = new LevelEventPacket; $pk->evid = LevelEventPacket::EVENT_PARTICLE_DESTROY; @@ -24,7 +24,7 @@ public function encode(){ $pk->y = $this->y; $pk->z = $this->z; $pk->data = $this->data; - + return $pk; } } diff --git a/src/devmine/levels/particle/DustParticle.php b/src/devmine/worlds/particle/DustParticle.php similarity index 89% rename from src/devmine/levels/particle/DustParticle.php rename to src/devmine/worlds/particle/DustParticle.php index 2247082..28c94e7 100644 --- a/src/devmine/levels/particle/DustParticle.php +++ b/src/devmine/worlds/particle/DustParticle.php @@ -2,7 +2,7 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\server\calculations\Vector3; diff --git a/src/devmine/levels/particle/EnchantParticle.php b/src/devmine/worlds/particle/EnchantParticle.php similarity index 85% rename from src/devmine/levels/particle/EnchantParticle.php rename to src/devmine/worlds/particle/EnchantParticle.php index 05e9915..f17f3e4 100644 --- a/src/devmine/levels/particle/EnchantParticle.php +++ b/src/devmine/worlds/particle/EnchantParticle.php @@ -2,7 +2,7 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\server\calculations\Vector3; diff --git a/src/devmine/levels/particle/EnchantmentTableParticle.php b/src/devmine/worlds/particle/EnchantmentTableParticle.php similarity index 86% rename from src/devmine/levels/particle/EnchantmentTableParticle.php rename to src/devmine/worlds/particle/EnchantmentTableParticle.php index aebbc7a..0589b36 100644 --- a/src/devmine/levels/particle/EnchantmentTableParticle.php +++ b/src/devmine/worlds/particle/EnchantmentTableParticle.php @@ -2,7 +2,7 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\server\calculations\Vector3; diff --git a/src/devmine/levels/particle/EntityFlameParticle.php b/src/devmine/worlds/particle/EntityFlameParticle.php similarity index 85% rename from src/devmine/levels/particle/EntityFlameParticle.php rename to src/devmine/worlds/particle/EntityFlameParticle.php index dd250b6..a258dbc 100644 --- a/src/devmine/levels/particle/EntityFlameParticle.php +++ b/src/devmine/worlds/particle/EntityFlameParticle.php @@ -2,7 +2,7 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\server\calculations\Vector3; diff --git a/src/devmine/levels/particle/ExplodeParticle.php b/src/devmine/worlds/particle/ExplodeParticle.php similarity index 85% rename from src/devmine/levels/particle/ExplodeParticle.php rename to src/devmine/worlds/particle/ExplodeParticle.php index fded98e..f55e289 100644 --- a/src/devmine/levels/particle/ExplodeParticle.php +++ b/src/devmine/worlds/particle/ExplodeParticle.php @@ -2,7 +2,7 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\server\calculations\Vector3; diff --git a/src/devmine/levels/particle/FlameParticle.php b/src/devmine/worlds/particle/FlameParticle.php similarity index 84% rename from src/devmine/levels/particle/FlameParticle.php rename to src/devmine/worlds/particle/FlameParticle.php index 8423560..cde7819 100644 --- a/src/devmine/levels/particle/FlameParticle.php +++ b/src/devmine/worlds/particle/FlameParticle.php @@ -2,7 +2,7 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\server\calculations\Vector3; diff --git a/src/devmine/levels/particle/FloatingTextParticle.php b/src/devmine/worlds/particle/FloatingTextParticle.php similarity index 68% rename from src/devmine/levels/particle/FloatingTextParticle.php rename to src/devmine/worlds/particle/FloatingTextParticle.php index 4a8a9b9..1d05af7 100644 --- a/src/devmine/levels/particle/FloatingTextParticle.php +++ b/src/devmine/worlds/particle/FloatingTextParticle.php @@ -2,16 +2,13 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\creatures\entities\Entity; use devmine\creatures\entities\Item as ItemEntity; -use devmine\inventory\items\Item; use devmine\server\calculations\Vector3; use devmine\server\network\protocol\AddEntityPacket; -use devmine\server\network\protocol\AddPlayerPacket; use devmine\server\network\protocol\RemoveEntityPacket; -use devmine\utilities\main\UUID; class FloatingTextParticle extends Particle{ //TODO: HACK! @@ -23,8 +20,8 @@ class FloatingTextParticle extends Particle{ /** * @param Vector3 $pos - * @param int $text - * @param string $title + * @param int $text + * @param string $title */ public function __construct(Vector3 $pos, $text, $title = ""){ parent::__construct($pos->x, $pos->y, $pos->z); @@ -39,11 +36,11 @@ public function setText($text){ public function setTitle($title){ $this->title = $title; } - + public function isInvisible(){ return $this->invisible; } - + public function setInvisible($value = true){ $this->invisible = (bool) $value; } @@ -61,31 +58,33 @@ public function encode(){ } if(!$this->invisible){ - - $pk = new AddPlayerPacket(); + + $pk = new AddEntityPacket(); $pk->eid = $this->entityId; - $pk->uuid = UUID::fromRandom(); + $pk->type = ItemEntity::NETWORK_ID; $pk->x = $this->x; - $pk->y = $this->y - 1.62; + $pk->y = $this->y - 0.75; $pk->z = $this->z; $pk->speedX = 0; $pk->speedY = 0; $pk->speedZ = 0; $pk->yaw = 0; $pk->pitch = 0; - $pk->item = Item::get(0); - $pk->epilogos = [ - Entity::DATA_FLAGS => [Entity::DATA_TYPE_BYTE, 1 << Entity::DATA_FLAG_INVISIBLE], + $pk->item = 0; + $pk->meta = 0; + $flags = 0; + $flags |= 1 << Entity::DATA_FLAG_INVISIBLE; + $flags |= 1 << Entity::DATA_FLAG_CAN_SHOW_NAMETAG; + $flags |= 1 << Entity::DATA_FLAG_ALWAYS_SHOW_NAMETAG; + $flags |= 1 << Entity::DATA_FLAG_IMMOBILE; + $pk->metadata = [ + Entity::DATA_FLAGS => [Entity::DATA_TYPE_LONG, $flags], Entity::DATA_NAMETAG => [Entity::DATA_TYPE_STRING, $this->title . ($this->text !== "" ? "\n" . $this->text : "")], - Entity::DATA_SHOW_NAMETAG => [Entity::DATA_TYPE_BYTE, 1], - Entity::DATA_NO_AI => [Entity::DATA_TYPE_BYTE, 1], - Entity::DATA_LEAD_HOLDER => [Entity::DATA_TYPE_LONG, -1], - Entity::DATA_LEAD => [Entity::DATA_TYPE_BYTE, 0] - ]; + ]; $p[] = $pk; } - + return $p; } } diff --git a/src/devmine/levels/particle/GenericParticle.php b/src/devmine/worlds/particle/GenericParticle.php similarity index 93% rename from src/devmine/levels/particle/GenericParticle.php rename to src/devmine/worlds/particle/GenericParticle.php index 577ef4b..f963ad6 100644 --- a/src/devmine/levels/particle/GenericParticle.php +++ b/src/devmine/worlds/particle/GenericParticle.php @@ -2,13 +2,13 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; -use devmine\server\network\protocol\LevelEventPacket; use devmine\server\calculations\Vector3; +use devmine\server\network\protocol\LevelEventPacket; class GenericParticle extends Particle{ - + protected $id; protected $data; @@ -17,7 +17,7 @@ public function __construct(Vector3 $pos, $id, $data = 0){ $this->id = $id & 0xFFF; $this->data = $data; } - + public function encode(){ $pk = new LevelEventPacket; $pk->evid = LevelEventPacket::EVENT_ADD_PARTICLE_MASK | $this->id; @@ -25,7 +25,7 @@ public function encode(){ $pk->y = $this->y; $pk->z = $this->z; $pk->data = $this->data; - + return $pk; } } diff --git a/src/devmine/levels/particle/HappyVillagerParticle.php b/src/devmine/worlds/particle/HappyVillagerParticle.php similarity index 85% rename from src/devmine/levels/particle/HappyVillagerParticle.php rename to src/devmine/worlds/particle/HappyVillagerParticle.php index c7f1160..165425f 100644 --- a/src/devmine/levels/particle/HappyVillagerParticle.php +++ b/src/devmine/worlds/particle/HappyVillagerParticle.php @@ -2,7 +2,7 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\server\calculations\Vector3; diff --git a/src/devmine/levels/particle/HeartParticle.php b/src/devmine/worlds/particle/HeartParticle.php similarity index 86% rename from src/devmine/levels/particle/HeartParticle.php rename to src/devmine/worlds/particle/HeartParticle.php index abfa907..8962ef0 100644 --- a/src/devmine/levels/particle/HeartParticle.php +++ b/src/devmine/worlds/particle/HeartParticle.php @@ -2,7 +2,7 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\server\calculations\Vector3; diff --git a/src/devmine/levels/particle/HugeExplodeParticle.php b/src/devmine/worlds/particle/HugeExplodeParticle.php similarity index 85% rename from src/devmine/levels/particle/HugeExplodeParticle.php rename to src/devmine/worlds/particle/HugeExplodeParticle.php index 6eb2bb9..2ebcbc4 100644 --- a/src/devmine/levels/particle/HugeExplodeParticle.php +++ b/src/devmine/worlds/particle/HugeExplodeParticle.php @@ -2,7 +2,7 @@ -namespace devmine\levels\particle; +namespace devmine\worlds\particle; use devmine\server\calculations\Vector3; diff --git a/src/devmine/worlds/particle/HugeExplodeSeedParticle.php b/src/devmine/worlds/particle/HugeExplodeSeedParticle.php new file mode 100644 index 0000000..eaf67e4 --- /dev/null +++ b/src/devmine/worlds/particle/HugeExplodeSeedParticle.php @@ -0,0 +1,13 @@ +x, $pos->y, $pos->z); $this->width = $width; $this->height = $height; } - + public function encode(){ $pk = new LevelEventPacket; $pk->evid = LevelEventPacket::EVENT_PARTICLE_SPAWN; @@ -25,7 +25,7 @@ public function encode(){ $pk->y = $this->y; $pk->z = $this->z; $pk->data = ($this->width & 0xff) + (($this->height & 0xff) << 8); - + return $pk; } } diff --git a/src/devmine/worlds/particle/Particle.php b/src/devmine/worlds/particle/Particle.php new file mode 100644 index 0000000..86a33b5 --- /dev/null +++ b/src/devmine/worlds/particle/Particle.php @@ -0,0 +1,59 @@ +x, $pos->y, $pos->z); $this->id = (int) $id; $this->pitch = (float) $pitch * 1000; } - + protected $pitch = 0; protected $id; - + public function getPitch(){ return $this->pitch / 1000; } - + public function setPitch($pitch){ $this->pitch = (float) $pitch * 1000; } - - + + public function encode(){ $pk = new LevelEventPacket; $pk->evid = $this->id; @@ -34,7 +34,7 @@ public function encode(){ $pk->y = $this->y; $pk->z = $this->z; $pk->data = (int) $this->pitch; - + return $pk; } diff --git a/src/devmine/levels/sound/GhastShootSound.php b/src/devmine/worlds/sound/GhastShootSound.php similarity index 90% rename from src/devmine/levels/sound/GhastShootSound.php rename to src/devmine/worlds/sound/GhastShootSound.php index f6866bf..0bed09d 100644 --- a/src/devmine/levels/sound/GhastShootSound.php +++ b/src/devmine/worlds/sound/GhastShootSound.php @@ -2,7 +2,7 @@ -namespace devmine\levels\sound; +namespace devmine\worlds\sound; use devmine\server\calculations\Vector3; use devmine\server\network\protocol\LevelEventPacket; diff --git a/src/devmine/levels/sound/GhastSound.php b/src/devmine/worlds/sound/GhastSound.php similarity index 89% rename from src/devmine/levels/sound/GhastSound.php rename to src/devmine/worlds/sound/GhastSound.php index f455236..69d1bf1 100644 --- a/src/devmine/levels/sound/GhastSound.php +++ b/src/devmine/worlds/sound/GhastSound.php @@ -2,7 +2,7 @@ -namespace devmine\levels\sound; +namespace devmine\worlds\sound; use devmine\server\calculations\Vector3; use devmine\server\network\protocol\LevelEventPacket; diff --git a/src/devmine/levels/sound/LaunchSound.php b/src/devmine/worlds/sound/LaunchSound.php similarity index 89% rename from src/devmine/levels/sound/LaunchSound.php rename to src/devmine/worlds/sound/LaunchSound.php index 7e10d2c..a0431ec 100644 --- a/src/devmine/levels/sound/LaunchSound.php +++ b/src/devmine/worlds/sound/LaunchSound.php @@ -2,7 +2,7 @@ -namespace devmine\levels\sound; +namespace devmine\worlds\sound; use devmine\server\calculations\Vector3; use devmine\server\network\protocol\LevelEventPacket; diff --git a/src/devmine/levels/sound/PopSound.php b/src/devmine/worlds/sound/PopSound.php similarity index 89% rename from src/devmine/levels/sound/PopSound.php rename to src/devmine/worlds/sound/PopSound.php index c0c1a7e..4f57430 100644 --- a/src/devmine/levels/sound/PopSound.php +++ b/src/devmine/worlds/sound/PopSound.php @@ -2,7 +2,7 @@ -namespace devmine\levels\sound; +namespace devmine\worlds\sound; use devmine\server\calculations\Vector3; use devmine\server\network\protocol\LevelEventPacket; diff --git a/src/devmine/levels/sound/Sound.php b/src/devmine/worlds/sound/Sound.php similarity index 86% rename from src/devmine/levels/sound/Sound.php rename to src/devmine/worlds/sound/Sound.php index f6bc4cf..d7715fa 100644 --- a/src/devmine/levels/sound/Sound.php +++ b/src/devmine/worlds/sound/Sound.php @@ -2,13 +2,13 @@ -namespace devmine\levels\sound; +namespace devmine\worlds\sound; use devmine\server\calculations\Vector3; use devmine\server\network\protocol\DataPacket; abstract class Sound extends Vector3{ - + /** * @return DataPacket|DataPacket[] */ diff --git a/src/devmine/levels/sound/ZombieHealSound.php b/src/devmine/worlds/sound/ZombieHealSound.php similarity index 90% rename from src/devmine/levels/sound/ZombieHealSound.php rename to src/devmine/worlds/sound/ZombieHealSound.php index be6a71c..c61d2da 100644 --- a/src/devmine/levels/sound/ZombieHealSound.php +++ b/src/devmine/worlds/sound/ZombieHealSound.php @@ -2,7 +2,7 @@ -namespace devmine\levels\sound; +namespace devmine\worlds\sound; use devmine\server\calculations\Vector3; use devmine\server\network\protocol\LevelEventPacket; diff --git a/src/devmine/levels/sound/ZombieInfectSound.php b/src/devmine/worlds/sound/ZombieInfectSound.php similarity index 90% rename from src/devmine/levels/sound/ZombieInfectSound.php rename to src/devmine/worlds/sound/ZombieInfectSound.php index 3ec3eda..ada64ac 100644 --- a/src/devmine/levels/sound/ZombieInfectSound.php +++ b/src/devmine/worlds/sound/ZombieInfectSound.php @@ -2,7 +2,7 @@ -namespace devmine\levels\sound; +namespace devmine\worlds\sound; use devmine\server\calculations\Vector3; use devmine\server\network\protocol\LevelEventPacket; diff --git a/src/raklib/Binary.php b/src/raklib/Binary.php index 7efb24c..4902957 100644 --- a/src/raklib/Binary.php +++ b/src/raklib/Binary.php @@ -1,17 +1,6 @@ identifierACK = null; } - - /* - * From http://www.jenkinssoftware.com/raknet/manual/reliabilitytypes.html - * - * Default: 0b010 (2) or 0b011 (3) - * - * 0: UNRELIABLE - * 1: UNRELIABLE_SEQUENCED - * 2: RELIABLE - * 3: RELIABLE_ORDERED - * 4: RELIABLE_SEQUENCED - * 5: UNRELIABLE_WITH_ACK_RECEIPT - * 6: RELIABLE_WITH_ACK_RECEIPT - * 7: RELIABLE_ORDERED_WITH_ACK_RECEIPT - */ - - if($reliability > 0){ - if($reliability >= 2 and $reliability !== 5){ + if($reliability > PacketReliability::UNRELIABLE){ + if($reliability >= PacketReliability::RELIABLE and $reliability !== PacketReliability::UNRELIABLE_WITH_ACK_RECEIPT){ $packet->messageIndex = Binary::readLTriad(substr($binary, $offset, 3)); $offset += 3; } - if($reliability <= 4 and $reliability !== 2){ + if($reliability <= PacketReliability::RELIABLE_SEQUENCED and $reliability !== PacketReliability::RELIABLE){ $packet->orderIndex = Binary::readLTriad(substr($binary, $offset, 3)); $offset += 3; $packet->orderChannel = ord($binary{$offset++}); @@ -106,9 +90,9 @@ public function toBinary($internal = false){ return chr(($this->reliability << 5) | ($this->hasSplit ? 0b00010000 : 0)) . ($internal ? Binary::writeInt(strlen($this->buffer)) . Binary::writeInt($this->identifierACK) : Binary::writeShort(strlen($this->buffer) << 3)) . - ($this->reliability > 0 ? - (($this->reliability >= 2 and $this->reliability !== 5) ? Binary::writeLTriad($this->messageIndex) : "") . - (($this->reliability <= 4 and $this->reliability !== 2) ? Binary::writeLTriad($this->orderIndex) . chr($this->orderChannel) : "") + ($this->reliability > PacketReliability::UNRELIABLE ? + (($this->reliability >= PacketReliability::RELIABLE and $this->reliability !== PacketReliability::UNRELIABLE_WITH_ACK_RECEIPT) ? Binary::writeLTriad($this->messageIndex) : "") . + (($this->reliability <= PacketReliability::RELIABLE_SEQUENCED and $this->reliability !== PacketReliability::RELIABLE) ? Binary::writeLTriad($this->orderIndex) . chr($this->orderChannel) : "") : "" ) . ($this->hasSplit ? Binary::writeInt($this->splitCount) . Binary::writeShort($this->splitID) . Binary::writeInt($this->splitIndex) : "") diff --git a/src/raklib/protocol/NACK.php b/src/raklib/protocol/NACK.php index 7a81a90..05c5be4 100644 --- a/src/raklib/protocol/NACK.php +++ b/src/raklib/protocol/NACK.php @@ -1,17 +1,6 @@ server->pushMainToThreadPacket($buffer); $this->server->shutdown(); $this->server->synchronized(function(){ - $this->server->wait(20000); + if($this->server !== null){ #pthreadssucks + $this->server->wait(20000); + } }); $this->server->join(); } diff --git a/src/raklib/server/ServerInstance.php b/src/raklib/server/ServerInstance.php index cff24b6..c0bc867 100644 --- a/src/raklib/server/ServerInstance.php +++ b/src/raklib/server/ServerInstance.php @@ -1,17 +1,6 @@ reliability === 2 or - $packet->reliability === 3 or - $packet->reliability === 4 or - $packet->reliability === 6 or - $packet->reliability === 7 + $packet->reliability === PacketReliability::RELIABLE or + $packet->reliability === PacketReliability::RELIABLE_ORDERED or + $packet->reliability === PacketReliability::RELIABLE_SEQUENCED or + $packet->reliability === PacketReliability::RELIABLE_WITH_ACK_RECEIPT or + $packet->reliability === PacketReliability::RELIABLE_ORDERED_WITH_ACK_RECEIPT ){ $packet->messageIndex = $this->messageIndex++; - if($packet->reliability === 3){ + if($packet->reliability === PacketReliability::RELIABLE_ORDERED){ $packet->orderIndex = $this->channelIndex[$packet->orderChannel]++; } } @@ -297,7 +298,7 @@ public function addEncapsulatedToQueue(EncapsulatedPacket $packet, $flags = RakL }else{ $pk->messageIndex = $packet->messageIndex; } - if($pk->reliability === 3){ + if($pk->reliability === PacketReliability::RELIABLE_ORDERED){ $pk->orderChannel = $packet->orderChannel; $pk->orderIndex = $packet->orderIndex; } @@ -407,7 +408,7 @@ private function handleEncapsulatedPacketRoute(EncapsulatedPacket $packet){ $pk->encode(); $sendPacket = new EncapsulatedPacket(); - $sendPacket->reliability = 0; + $sendPacket->reliability = PacketReliability::UNRELIABLE; $sendPacket->buffer = $pk->buffer; $this->addToQueue($sendPacket, RakLib::PRIORITY_IMMEDIATE); }elseif($id === CLIENT_HANDSHAKE_DataPacket::$ID){ @@ -433,7 +434,7 @@ private function handleEncapsulatedPacketRoute(EncapsulatedPacket $packet){ $pk->encode(); $sendPacket = new EncapsulatedPacket(); - $sendPacket->reliability = 0; + $sendPacket->reliability = PacketReliability::UNRELIABLE; $sendPacket->buffer = $pk->buffer; $this->addToQueue($sendPacket); }//TODO: add PING/PONG (0x00/0x03) automatic latency measure @@ -532,8 +533,7 @@ public function handlePacket(Packet $packet){ } public function close(){ - $data = "\x00\x00\x08\x15"; - $this->addEncapsulatedToQueue(EncapsulatedPacket::fromBinary($data), RakLib::PRIORITY_IMMEDIATE); //CLIENT_DISCONNECT packet 0x15 + $this->addEncapsulatedToQueue(EncapsulatedPacket::fromBinary("\x60\x00\x08\x00\x00\x00\x00\x00\x00\x00\x15")); //CLIENT_DISCONNECT packet 0x15 $this->sessionManager = null; } } diff --git a/src/raklib/server/SessionManager.php b/src/raklib/server/SessionManager.php index 238b586..6ffea50 100644 --- a/src/raklib/server/SessionManager.php +++ b/src/raklib/server/SessionManager.php @@ -154,7 +154,8 @@ private function tick(){ private function receivePacket(){ - if(($len = $this->socket->readPacket($buffer, $source, $port)) > 0){ + $len = $this->socket->readPacket($buffer, $source, $port); + if($buffer !== null){ $this->receiveBytes += $len; if(isset($this->block[$source])){ return true; @@ -166,33 +167,30 @@ private function receivePacket(){ $this->ipSec[$source] = 1; } - $pid = ord($buffer{0}); - - if($pid == UNCONNECTED_PONG::$ID){ - return false; - } - - if(($packet = $this->getPacketFromPool($pid)) !== null){ - $packet->buffer = $buffer; - $this->getSession($source, $port)->handlePacket($packet); - return true; - }elseif($pid === UNCONNECTED_PING::$ID){ - //No need to create a session for just pings - $packet = new UNCONNECTED_PING; - $packet->buffer = $buffer; - $packet->decode(); - - $pk = new UNCONNECTED_PONG(); - $pk->serverID = $this->getID(); - $pk->pingID = $packet->pingID; - $pk->serverName = $this->getName(); - $this->sendPacket($pk, $source, $port); - }elseif($buffer !== ""){ - $this->streamRaw($source, $port, $buffer); - return true; - }else{ - return false; + if($len > 0){ + $pid = ord($buffer{0}); + + if($pid === UNCONNECTED_PING::$ID){ + //No need to create a session for just pings + $packet = new UNCONNECTED_PING; + $packet->buffer = $buffer; + $packet->decode(); + + $pk = new UNCONNECTED_PONG(); + $pk->serverID = $this->getID(); + $pk->pingID = $packet->pingID; + $pk->serverName = $this->getName(); + $this->sendPacket($pk, $source, $port); + }elseif($pid === UNCONNECTED_PONG::$ID){ + //ignored + }elseif(($packet = $this->getPacketFromPool($pid)) !== null){ + $packet->buffer = $buffer; + $this->getSession($source, $port)->handlePacket($packet); + }else{ + $this->streamRaw($source, $port, $buffer); + } } + return true; } return false; diff --git a/src/spl/ArrayOutOfBoundsException.php b/src/spl/ArrayOutOfBoundsException.php index bce9a75..3a3477e 100644 --- a/src/spl/ArrayOutOfBoundsException.php +++ b/src/spl/ArrayOutOfBoundsException.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class ArrayOutOfBoundsException extends OutOfBoundsException{ diff --git a/src/spl/AttachableLogger.php b/src/spl/AttachableLogger.php index 085c9c2..9c16e39 100644 --- a/src/spl/AttachableLogger.php +++ b/src/spl/AttachableLogger.php @@ -1,36 +1,23 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + interface AttachableLogger extends \Logger{ - /** - * @param LoggerAttachment $attachment - */ - public function addAttachment(\LoggerAttachment $attachment); + /** + * @param LoggerAttachment $attachment + */ + public function addAttachment(\LoggerAttachment $attachment); - /** - * @param LoggerAttachment $attachment - */ - public function removeAttachment(\LoggerAttachment $attachment); + /** + * @param LoggerAttachment $attachment + */ + public function removeAttachment(\LoggerAttachment $attachment); - public function removeAttachments(); + public function removeAttachments(); - /** - * @return \LoggerAttachment[] - */ - public function getAttachments(); + /** + * @return \LoggerAttachment[] + */ + public function getAttachments(); } \ No newline at end of file diff --git a/src/spl/AttachableThreadedLogger.php b/src/spl/AttachableThreadedLogger.php index 76cd25d..eb3c970 100644 --- a/src/spl/AttachableThreadedLogger.php +++ b/src/spl/AttachableThreadedLogger.php @@ -1,67 +1,54 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ -abstract class AttachableThreadedLogger extends \ThreadedLogger{ - - /** @var \ThreadedLoggerAttachment */ - protected $attachment = null; - - /** - * @param ThreadedLoggerAttachment $attachment - */ - public function addAttachment(\ThreadedLoggerAttachment $attachment){ - if($this->attachment instanceof \ThreadedLoggerAttachment){ - $this->attachment->addAttachment($attachment); - }else{ - $this->attachment = $attachment; - } - } - /** - * @param ThreadedLoggerAttachment $attachment - */ - public function removeAttachment(\ThreadedLoggerAttachment $attachment){ - if($this->attachment instanceof \ThreadedLoggerAttachment){ - if($this->attachment === $attachment){ - $this->attachment = null; - foreach($attachment->getAttachments() as $attachment){ - $this->addAttachment($attachment); - } - } - } - } - - public function removeAttachments(){ - if($this->attachment instanceof \ThreadedLoggerAttachment){ - $this->attachment->removeAttachments(); - $this->attachment = null; - } - } - - /** - * @return \ThreadedLoggerAttachment[] - */ - public function getAttachments(){ - $attachments = []; - if($this->attachment instanceof \ThreadedLoggerAttachment){ - $attachments[] = $this->attachment; - $attachments += $this->attachment->getAttachments(); - } +abstract class AttachableThreadedLogger extends \ThreadedLogger{ - return $attachments; - } + /** @var \ThreadedLoggerAttachment */ + protected $attachment = null; + + /** + * @param ThreadedLoggerAttachment $attachment + */ + public function addAttachment(\ThreadedLoggerAttachment $attachment){ + if($this->attachment instanceof \ThreadedLoggerAttachment){ + $this->attachment->addAttachment($attachment); + }else{ + $this->attachment = $attachment; + } + } + + /** + * @param ThreadedLoggerAttachment $attachment + */ + public function removeAttachment(\ThreadedLoggerAttachment $attachment){ + if($this->attachment instanceof \ThreadedLoggerAttachment){ + if($this->attachment === $attachment){ + $this->attachment = null; + foreach($attachment->getAttachments() as $attachment){ + $this->addAttachment($attachment); + } + } + } + } + + public function removeAttachments(){ + if($this->attachment instanceof \ThreadedLoggerAttachment){ + $this->attachment->removeAttachments(); + $this->attachment = null; + } + } + + /** + * @return \ThreadedLoggerAttachment[] + */ + public function getAttachments(){ + $attachments = []; + if($this->attachment instanceof \ThreadedLoggerAttachment){ + $attachments[] = $this->attachment; + $attachments += $this->attachment->getAttachments(); + } + + return $attachments; + } } \ No newline at end of file diff --git a/src/spl/BaseClassLoader.php b/src/spl/BaseClassLoader.php index e13ac43..8e1b51e 100644 --- a/src/spl/BaseClassLoader.php +++ b/src/spl/BaseClassLoader.php @@ -1,54 +1,41 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class BaseClassLoader extends \Threaded implements ClassLoader{ - /** @var \ClassLoader */ - private $parent; - /** @var string[] */ - private $lookup; - /** @var string[] */ - private $classes; - - - /** - * @param ClassLoader $parent - */ - public function __construct(ClassLoader $parent = null){ - $this->parent = $parent; - $this->lookup = new \Threaded; - $this->classes = new \Threaded; - } - - /** - * Adds a path to the lookup list - * - * @param string $path - * @param bool $prepend - */ - public function addPath($path, $prepend = false){ - - foreach($this->lookup as $p){ - if($p === $path){ - return; - } - } - - if($prepend){ + /** @var \ClassLoader */ + private $parent; + /** @var string[] */ + private $lookup; + /** @var string[] */ + private $classes; + + + /** + * @param ClassLoader $parent + */ + public function __construct(ClassLoader $parent = null){ + $this->parent = $parent; + $this->lookup = new \Threaded; + $this->classes = new \Threaded; + } + + /** + * Adds a path to the lookup list + * + * @param string $path + * @param bool $prepend + */ + public function addPath($path, $prepend = false){ + + foreach($this->lookup as $p){ + if($p === $path){ + return; + } + } + + if($prepend){ $this->synchronized(function($path){ $entries = $this->getAndRemoveLookupEntries(); $this->lookup[] = $path; @@ -56,12 +43,12 @@ public function addPath($path, $prepend = false){ $this->lookup[] = $entry; } }, $path); - }else{ - $this->lookup[] = $path; - } - } - - protected function getAndRemoveLookupEntries(){ + }else{ + $this->lookup[] = $path; + } + } + + protected function getAndRemoveLookupEntries(){ $entries = []; while($this->count() > 0){ $entries[] = $this->shift(); @@ -69,107 +56,107 @@ protected function getAndRemoveLookupEntries(){ return $entries; } - /** - * Removes a path from the lookup list - * - * @param $path - */ - public function removePath($path){ - foreach($this->lookup as $i => $p){ - if($p === $path){ - unset($this->lookup[$i]); - } - } - } - - /** - * Returns an array of the classes loaded - * - * @return string[] - */ - public function getClasses(){ + /** + * Removes a path from the lookup list + * + * @param $path + */ + public function removePath($path){ + foreach($this->lookup as $i => $p){ + if($p === $path){ + unset($this->lookup[$i]); + } + } + } + + /** + * Returns an array of the classes loaded + * + * @return string[] + */ + public function getClasses(){ $classes = []; foreach($this->classes as $class){ $classes[] = $class; } - return $classes; - } - - /** - * Returns the parent ClassLoader, if any - * - * @return ClassLoader - */ - public function getParent(){ - return $this->parent; - } - - /** - * Attaches the ClassLoader to the PHP runtime - * - * @param bool $prepend - * - * @return bool - */ - public function register($prepend = false){ - spl_autoload_register([$this, "loadClass"], true, $prepend); - } - - /** - * Called when there is a class to load - * - * @param string $name - * - * @return bool - */ - public function loadClass($name){ - $path = $this->findClass($name); - if($path !== null){ - include($path); - if(!class_exists($name, false) and !interface_exists($name, false) and !trait_exists($name, false)){ - if($this->getParent() === null){ - throw new ClassNotFoundException("Class $name not found"); - } - return false; - } - - if(method_exists($name, "onClassLoaded") and (new ReflectionClass($name))->getMethod("onClassLoaded")->isStatic()){ - $name::onClassLoaded(); - } - - $this->classes[] = $name; - - return true; - }elseif($this->getParent() === null){ - throw new ClassNotFoundException("Class $name not found"); - } - - return false; - } - - /** - * Returns the path for the class, if any - * - * @param string $name - * - * @return string|null - */ - public function findClass($name){ - $components = explode("\\", $name); - - $baseName = implode(DIRECTORY_SEPARATOR, $components); - - - foreach($this->lookup as $path){ - if(PHP_INT_SIZE === 8 and file_exists($path . DIRECTORY_SEPARATOR . $baseName . "__64bit.php")){ - return $path . DIRECTORY_SEPARATOR . $baseName . "__64bit.php"; - }elseif(PHP_INT_SIZE === 4 and file_exists($path . DIRECTORY_SEPARATOR . $baseName . "__32bit.php")){ - return $path . DIRECTORY_SEPARATOR . $baseName . "__32bit.php"; - }elseif(file_exists($path . DIRECTORY_SEPARATOR . $baseName . ".php")){ - return $path . DIRECTORY_SEPARATOR . $baseName . ".php"; - } - } - - return null; - } + return $classes; + } + + /** + * Returns the parent ClassLoader, if any + * + * @return ClassLoader + */ + public function getParent(){ + return $this->parent; + } + + /** + * Attaches the ClassLoader to the PHP runtime + * + * @param bool $prepend + * + * @return bool + */ + public function register($prepend = false){ + spl_autoload_register([$this, "loadClass"], true, $prepend); + } + + /** + * Called when there is a class to load + * + * @param string $name + * + * @return bool + */ + public function loadClass($name){ + $path = $this->findClass($name); + if($path !== null){ + include($path); + if(!class_exists($name, false) and !interface_exists($name, false) and !trait_exists($name, false)){ + if($this->getParent() === null){ + throw new ClassNotFoundException("Class $name not found"); + } + return false; + } + + if(method_exists($name, "onClassLoaded") and (new ReflectionClass($name))->getMethod("onClassLoaded")->isStatic()){ + $name::onClassLoaded(); + } + + $this->classes[] = $name; + + return true; + }elseif($this->getParent() === null){ + throw new ClassNotFoundException("Class $name not found"); + } + + return false; + } + + /** + * Returns the path for the class, if any + * + * @param string $name + * + * @return string|null + */ + public function findClass($name){ + $components = explode("\\", $name); + + $baseName = implode(DIRECTORY_SEPARATOR, $components); + + + foreach($this->lookup as $path){ + if(PHP_INT_SIZE === 8 and file_exists($path . DIRECTORY_SEPARATOR . $baseName . "__64bit.php")){ + return $path . DIRECTORY_SEPARATOR . $baseName . "__64bit.php"; + }elseif(PHP_INT_SIZE === 4 and file_exists($path . DIRECTORY_SEPARATOR . $baseName . "__32bit.php")){ + return $path . DIRECTORY_SEPARATOR . $baseName . "__32bit.php"; + }elseif(file_exists($path . DIRECTORY_SEPARATOR . $baseName . ".php")){ + return $path . DIRECTORY_SEPARATOR . $baseName . ".php"; + } + } + + return null; + } } diff --git a/src/spl/ClassCastException.php b/src/spl/ClassCastException.php index cce95eb..ee5e030 100644 --- a/src/spl/ClassCastException.php +++ b/src/spl/ClassCastException.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class ClassCastException extends InvalidArgumentException{ diff --git a/src/spl/ClassLoader.php b/src/spl/ClassLoader.php index 29d37f8..eb76177 100644 --- a/src/spl/ClassLoader.php +++ b/src/spl/ClassLoader.php @@ -1,82 +1,69 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + interface ClassLoader{ - /** - * @param ClassLoader $parent - */ - public function __construct(ClassLoader $parent = null); + /** + * @param ClassLoader $parent + */ + public function __construct(ClassLoader $parent = null); - /** - * Adds a path to the lookup list - * - * @param string $path - * @param bool $prepend - */ - public function addPath($path, $prepend = false); + /** + * Adds a path to the lookup list + * + * @param string $path + * @param bool $prepend + */ + public function addPath($path, $prepend = false); - /** - * Removes a path from the lookup list - * - * @param $path - */ - public function removePath($path); + /** + * Removes a path from the lookup list + * + * @param $path + */ + public function removePath($path); - /** - * Returns an array of the classes loaded - * - * @return string[] - */ - public function getClasses(); + /** + * Returns an array of the classes loaded + * + * @return string[] + */ + public function getClasses(); - /** - * Returns the parent ClassLoader, if any - * - * @return ClassLoader - */ - public function getParent(); + /** + * Returns the parent ClassLoader, if any + * + * @return ClassLoader + */ + public function getParent(); - /** - * Attaches the ClassLoader to the PHP runtime - * - * @param bool $prepend - * - * @return bool - */ - public function register($prepend = false); + /** + * Attaches the ClassLoader to the PHP runtime + * + * @param bool $prepend + * + * @return bool + */ + public function register($prepend = false); - /** - * Called when there is a class to load - * - * @param string $name - * - * @return bool - * - * @throws ClassNotFoundException - */ - public function loadClass($name); + /** + * Called when there is a class to load + * + * @param string $name + * + * @return bool + * + * @throws ClassNotFoundException + */ + public function loadClass($name); - /** - * Returns the path for the class, if any - * - * @param string $name - * - * @return string|null - */ - public function findClass($name); + /** + * Returns the path for the class, if any + * + * @param string $name + * + * @return string|null + */ + public function findClass($name); } \ No newline at end of file diff --git a/src/spl/ClassNotFoundException.php b/src/spl/ClassNotFoundException.php index d0adef3..8ec593c 100644 --- a/src/spl/ClassNotFoundException.php +++ b/src/spl/ClassNotFoundException.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class ClassNotFoundException extends LogicException{ diff --git a/src/spl/InvalidArgumentCountException.php b/src/spl/InvalidArgumentCountException.php index 9f8d54a..0a765a9 100644 --- a/src/spl/InvalidArgumentCountException.php +++ b/src/spl/InvalidArgumentCountException.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class InvalidArgumentCountException extends InvalidArgumentException{ diff --git a/src/spl/InvalidKeyException.php b/src/spl/InvalidKeyException.php index 6ea80ea..9896e73 100644 --- a/src/spl/InvalidKeyException.php +++ b/src/spl/InvalidKeyException.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class InvalidKeyException extends InvalidArgumentException{ diff --git a/src/spl/InvalidStateException.php b/src/spl/InvalidStateException.php index 8c37cbc..7f6a8f9 100644 --- a/src/spl/InvalidStateException.php +++ b/src/spl/InvalidStateException.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class InvalidStateException extends InvalidArgumentException{ diff --git a/src/spl/LogLevel.php b/src/spl/LogLevel.php index e9fd548..cb2940e 100644 --- a/src/spl/LogLevel.php +++ b/src/spl/LogLevel.php @@ -1,27 +1,14 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + interface LogLevel{ - const EMERGENCY = "emergency"; - const ALERT = "alert"; - const CRITICAL = "critical"; - const ERROR = "error"; - const WARNING = "warning"; - const NOTICE = "notice"; - const INFO = "info"; - const DEBUG = "debug"; + const EMERGENCY = "emergency"; + const ALERT = "alert"; + const CRITICAL = "critical"; + const ERROR = "error"; + const WARNING = "warning"; + const NOTICE = "notice"; + const INFO = "info"; + const DEBUG = "debug"; } \ No newline at end of file diff --git a/src/spl/Logger.php b/src/spl/Logger.php index e3865fa..cf5eb4f 100644 --- a/src/spl/Logger.php +++ b/src/spl/Logger.php @@ -1,95 +1,82 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + interface Logger{ - /** - * System is unusable - * - * @param string $message - */ - public function emergency($message); + /** + * System is unusable + * + * @param string $message + */ + public function emergency($message); - /** - * Action must me taken immediately - * - * @param string $message - */ - public function alert($message); + /** + * Action must me taken immediately + * + * @param string $message + */ + public function alert($message); - /** - * Critical conditions - * - * @param string $message - */ - public function critical($message); + /** + * Critical conditions + * + * @param string $message + */ + public function critical($message); - /** - * Runtime errors that do not require immediate action but should typically - * be logged and monitored. - * - * @param string $message - */ - public function error($message); + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + */ + public function error($message); - /** - * Exceptional occurrences that are not errors. - * - * Example: Use of deprecated APIs, poor use of an API, undesirable things - * that are not necessarily wrong. - * - * @param string $message - */ - public function warning($message); + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + */ + public function warning($message); - /** - * Normal but significant events. - * - * @param string $message - */ - public function notice($message); + /** + * Normal but significant events. + * + * @param string $message + */ + public function notice($message); - /** - * Inersting events. - * - * @param string $message - */ - public function info($message); + /** + * Inersting events. + * + * @param string $message + */ + public function info($message); - /** - * Detailed debug information. - * - * @param string $message - */ - public function debug($message); + /** + * Detailed debug information. + * + * @param string $message + */ + public function debug($message); - /** - * Logs with an arbitrary level. - * - * @param mixed $level - * @param string $message - */ - public function log($level, $message); + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + */ + public function log($level, $message); - /** - * Logs a Throwable object - * - * @param Throwable $e - * @param $trace - */ - public function logException(\Throwable $e, $trace = null); + /** + * Logs a Throwable object + * + * @param Throwable $e + * @param $trace + */ + public function logException(\Throwable $e, $trace = null); } \ No newline at end of file diff --git a/src/spl/LoggerAttachment.php b/src/spl/LoggerAttachment.php index baf0f90..78cb124 100644 --- a/src/spl/LoggerAttachment.php +++ b/src/spl/LoggerAttachment.php @@ -1,26 +1,13 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + interface LoggerAttachment{ - /** - * @param mixed $level - * @param string $message - */ - public function log($level, $message); + /** + * @param mixed $level + * @param string $message + */ + public function log($level, $message); } \ No newline at end of file diff --git a/src/spl/README.md b/src/spl/README.md new file mode 100644 index 0000000..e439cd3 --- /dev/null +++ b/src/spl/README.md @@ -0,0 +1,17 @@ +# DevMine Standard PHP Library +These files are the classes used in most of the DevMine PHP projects. +They are required for the code to work. + + + DevMine Standard PHP Library + Copyright (C) 2014-2016 Mostly by PocketMine team, modified by DevMine Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser 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. \ No newline at end of file diff --git a/src/spl/SplFixedByteArray.php b/src/spl/SplFixedByteArray.php index ffac7c8..fb2a429 100644 --- a/src/spl/SplFixedByteArray.php +++ b/src/spl/SplFixedByteArray.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class SplFixedByteArray extends SplFixedArray{ diff --git a/src/spl/StringOutOfBoundsException.php b/src/spl/StringOutOfBoundsException.php index b4a4bcb..58b83d4 100644 --- a/src/spl/StringOutOfBoundsException.php +++ b/src/spl/StringOutOfBoundsException.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class StringOutOfBoundsException extends OutOfBoundsException{ diff --git a/src/spl/ThreadedLogger.php b/src/spl/ThreadedLogger.php index d2bde6a..a3d9b07 100644 --- a/src/spl/ThreadedLogger.php +++ b/src/spl/ThreadedLogger.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + abstract class ThreadedLogger extends \Thread implements Logger{ diff --git a/src/spl/ThreadedLoggerAttachment.php b/src/spl/ThreadedLoggerAttachment.php index e539b90..156d7f2 100644 --- a/src/spl/ThreadedLoggerAttachment.php +++ b/src/spl/ThreadedLoggerAttachment.php @@ -1,78 +1,65 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + abstract class ThreadedLoggerAttachment extends \Threaded implements \LoggerAttachment{ - /** @var \ThreadedLoggerAttachment */ - protected $attachment = null; + /** @var \ThreadedLoggerAttachment */ + protected $attachment = null; - /** - * @param mixed $level - * @param string $message - */ - public final function call($level, $message){ - $this->log($level, $message); - if($this->attachment instanceof \ThreadedLoggerAttachment){ - $this->attachment->call($level, $message); - } - } + /** + * @param mixed $level + * @param string $message + */ + public final function call($level, $message){ + $this->log($level, $message); + if($this->attachment instanceof \ThreadedLoggerAttachment){ + $this->attachment->call($level, $message); + } + } - /** - * @param ThreadedLoggerAttachment $attachment - */ - public function addAttachment(\ThreadedLoggerAttachment $attachment){ - if($this->attachment instanceof \ThreadedLoggerAttachment){ - $this->attachment->addAttachment($attachment); - }else{ - $this->attachment = $attachment; - } - } + /** + * @param ThreadedLoggerAttachment $attachment + */ + public function addAttachment(\ThreadedLoggerAttachment $attachment){ + if($this->attachment instanceof \ThreadedLoggerAttachment){ + $this->attachment->addAttachment($attachment); + }else{ + $this->attachment = $attachment; + } + } - /** - * @param ThreadedLoggerAttachment $attachment - */ - public function removeAttachment(\ThreadedLoggerAttachment $attachment){ - if($this->attachment instanceof \ThreadedLoggerAttachment){ - if($this->attachment === $attachment){ - $this->attachment = null; - foreach($attachment->getAttachments() as $attachment){ - $this->addAttachment($attachment); - } - } - } - } + /** + * @param ThreadedLoggerAttachment $attachment + */ + public function removeAttachment(\ThreadedLoggerAttachment $attachment){ + if($this->attachment instanceof \ThreadedLoggerAttachment){ + if($this->attachment === $attachment){ + $this->attachment = null; + foreach($attachment->getAttachments() as $attachment){ + $this->addAttachment($attachment); + } + } + } + } - public function removeAttachments(){ - if($this->attachment instanceof \ThreadedLoggerAttachment){ - $this->attachment->removeAttachments(); - $this->attachment = null; - } - } + public function removeAttachments(){ + if($this->attachment instanceof \ThreadedLoggerAttachment){ + $this->attachment->removeAttachments(); + $this->attachment = null; + } + } - /** - * @return \ThreadedLoggerAttachment[] - */ - public function getAttachments(){ - $attachments = []; - if($this->attachment instanceof \ThreadedLoggerAttachment){ - $attachments[] = $this->attachment; - $attachments += $this->attachment->getAttachments(); - } + /** + * @return \ThreadedLoggerAttachment[] + */ + public function getAttachments(){ + $attachments = []; + if($this->attachment instanceof \ThreadedLoggerAttachment){ + $attachments[] = $this->attachment; + $attachments += $this->attachment->getAttachments(); + } - return $attachments; - } + return $attachments; + } } \ No newline at end of file diff --git a/src/spl/UndefinedConstantException.php b/src/spl/UndefinedConstantException.php index 9d97e26..eda6cf0 100644 --- a/src/spl/UndefinedConstantException.php +++ b/src/spl/UndefinedConstantException.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class UndefinedConstantException extends InvalidStateException{ diff --git a/src/spl/UndefinedPropertyException.php b/src/spl/UndefinedPropertyException.php index b581b33..ee98d3d 100644 --- a/src/spl/UndefinedPropertyException.php +++ b/src/spl/UndefinedPropertyException.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class UndefinedPropertyException extends LogicException{ diff --git a/src/spl/UndefinedVariableException.php b/src/spl/UndefinedVariableException.php index fec3e39..22cd05d 100644 --- a/src/spl/UndefinedVariableException.php +++ b/src/spl/UndefinedVariableException.php @@ -1,19 +1,6 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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. -*/ + class UndefinedVariableException extends InvalidStateException{ diff --git a/src/synapse/Player.php b/src/synapse/Player.php deleted file mode 100644 index f75f2da..0000000 --- a/src/synapse/Player.php +++ /dev/null @@ -1,263 +0,0 @@ -isFirstTimeLogin = $packet->isFirstTime; - $this->server->getPluginManager()->callEvent($ev = new PlayerConnectEvent($this, $this->isFirstTimeLogin)); - $pk = Synapse::getInstance()->getPacket($packet->cachedLoginPacket); - $pk->decode(); - $this->handleDataPacket($pk); - } - - protected function processLogin(){ - if($this->isFirstTimeLogin){ - parent::processLogin(); - }else{ - if(!$this->server->isWhitelisted(strtolower($this->getName()))){ - $this->close($this->getLeaveMessage(), "Server is white-listed"); - - return; - }elseif($this->server->getNameBans()->isBanned(strtolower($this->getName())) or $this->server->getIPBans()->isBanned($this->getAddress()) or $this->server->getCIDBans()->isBanned($this->randomClientId)){ - $this->close($this->getLeaveMessage(), TextFormat::RED . "You are banned"); - - return; - } - - if($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)){ - $this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_USERS, $this); - } - if($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)){ - $this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this); - } - - foreach($this->server->getOnlinePlayers() as $p){ - if($p !== $this and strtolower($p->getName()) === strtolower($this->getName())){ - if($p->kick("logged in from another location") === false){ - $this->close($this->getLeaveMessage(), "Logged in from another location"); - return; - } - }elseif($p->loggedIn and $this->getUniqueId()->equals($p->getUniqueId())){ - if($p->kick("logged in from another location") === false){ - $this->close($this->getLeaveMessage(), "Logged in from another location"); - return; - } - } - } - - $nbt = $this->server->getOfflinePlayerData($this->username); - $this->playedBefore = ($nbt["lastPlayed"] - $nbt["firstPlayed"]) > 1; - if(!isset($nbt->NameTag)){ - $nbt->NameTag = new StringTag("NameTag", $this->username); - }else{ - $nbt["NameTag"] = $this->username; - } - if(!isset($nbt->Hunger) or !isset($nbt->Experience) or !isset($nbt->ExpLevel) or !isset($nbt->Health) or !isset($nbt->MaxHealth)){ - $nbt->Hunger = new ShortTag("Hunger", 20); - $nbt->Experience = new LongTag("Experience", 0); - $nbt->ExpLevel = new LongTag("ExpLevel", 0); - $nbt->Health = new ShortTag("Health", 20); - $nbt->MaxHealth = new ShortTag("MaxHealth", 20); - } - $this->food = $nbt["Hunger"]; - $this->setMaxHealth($nbt["MaxHealth"]); - Entity::setHealth(($nbt["Health"] <= 0) ? 20 : $nbt["Health"]); - $this->exp = ($nbt["Experience"] > 0) ? $nbt["Experience"] : 0; - $this->expLevel = ($nbt["ExpLevel"] >= 0) ? $nbt["ExpLevel"] : 0; - $this->calcExpLevel(); - $this->gamemode = $nbt["playerGameType"] & 0x03; - if($this->server->getForceGamemode()){ - $this->gamemode = $this->server->getGamemode(); - $nbt->playerGameType = new IntTag("playerGameType", $this->gamemode); - } - - $this->allowFlight = $this->isCreative(); - - - if(($level = $this->server->getLevelByName($nbt["Level"])) === null){ - $this->setLevel($this->server->getDefaultLevel()); - $nbt["Level"] = $this->level->getName(); - $nbt["Pos"][0] = $this->level->getSpawnLocation()->x; - $nbt["Pos"][1] = $this->level->getSpawnLocation()->y; - $nbt["Pos"][2] = $this->level->getSpawnLocation()->z; - }else{ - $this->setLevel($level); - } - - if(!($nbt instanceof CompoundTag)){ - $this->close($this->getLeaveMessage(), "Invalid data"); - - return; - } - - $this->achievements = []; - - /** @var ByteTag $achievement */ - foreach($nbt->Achievements as $achievement){ - $this->achievements[$achievement->getName()] = $achievement->getValue() > 0 ? true : false; - } - - $nbt->lastPlayed = new LongTag("lastPlayed", floor(microtime(true) * 1000)); - if($this->server->getAutoSave()){ - $this->server->saveOfflinePlayerData($this->username, $nbt, true); - } - - Entity::__construct($this->level->getChunk($nbt["Pos"][0] >> 4, $nbt["Pos"][2] >> 4, true), $nbt); - $this->loggedIn = true; - $this->server->addOnlinePlayer($this); - - $this->server->getPluginManager()->callEvent($ev = new PlayerLoginEvent($this, "Plugin reason")); - if($ev->isCancelled()){ - $this->close($this->getLeaveMessage(), $ev->getKickMessage()); - - return; - } - - if($this->isCreative()){ - $this->inventory->setHeldItemSlot(0); - }else{ - $this->inventory->setHeldItemSlot($this->inventory->getHotbarSlotIndex(0)); - } - - if($this->spawnPosition === null and isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName($this->namedtag["SpawnLevel"])) instanceof Level){ - $this->spawnPosition = new Position($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level); - } - $spawnPosition = $this->getSpawn(); - - $pk = new SetTimePacket(); - $pk->time = $this->level->getTime(); - $pk->started = $this->level->stopTime == false; - $this->dataPacket($pk); - - $pk = new SetSpawnPositionPacket(); - $pk->x = (int) $spawnPosition->x; - $pk->y = (int) $spawnPosition->y; - $pk->z = (int) $spawnPosition->z; - $this->dataPacket($pk); - - $this->sendAttributes(); - - $pk = new SetDifficultyPacket(); - $pk->difficulty = $this->server->getDifficulty(); - $this->dataPacket($pk); - - $pk = new SetPlayerGameTypePacket(); - $pk->gamemode = $this->gamemode & 0x01; - $this->dataPacket($pk); - $this->sendSettings(); - - $this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("devmine.player.logIn", [ - TextFormat::AQUA . $this->username . TextFormat::WHITE, - $this->ip, - $this->port, - TextFormat::GREEN . $this->randomClientId . TextFormat::WHITE, - $this->id, - $this->level->getName(), - round($this->x, 4), - round($this->y, 4), - round($this->z, 4) - ])); - - if($this->gamemode === Player::SPECTATOR){ - $pk = new ContainerSetContentPacket(); - $pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE; - $this->dataPacket($pk); - }else{ - $pk = new ContainerSetContentPacket(); - $pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE; - $pk->slots = array_merge(Item::getCreativeItems(), $this->personalCreativeItems); - $this->dataPacket($pk); - } - - $pk = new SetEntityDataPacket(); - $pk->eid = 0; - $pk->epilogos = [self::DATA_LEAD_HOLDER => [self::DATA_TYPE_LONG, -1]]; - $this->dataPacket($pk); - - $this->forceMovement = $this->teleportPosition = $this->getPosition(); - } - } - - public function transfer(string $hash){ - $clients = Synapse::getInstance()->getClientData(); - if(isset($clients[$hash])){ - foreach($this->getLevel()->getEntities() as $entity){ - if(isset($entity->hasSpawned[$this->getLoaderId()])){ - $entity->despawnFrom($this); - } - } - $pk = new TransferPacket(); - $pk->uuid = $this->uuid; - $pk->clientHash = $hash; - Synapse::getInstance()->sendDataPacket($pk); - - /*$ip = $clients[$hash]["ip"]; - $port = $clients[$hash]["port"]; - - $this->close("", "Transferred to $ip:$port"); - Synapse::getInstance()->removePlayer($this);*/ - } - } - - public function handleDataPacket(DataPacket $packet){ - $this->lastPacketTime = microtime(true); - return parent::handleDataPacket($packet); - } - - public function onUpdate($currentTick){ - if((microtime(true) - $this->lastPacketTime) >= 5 * 60){//5 minutes time out - $this->close("", "timeout"); - return false; - } - return parent::onUpdate($currentTick); - } - - public function setUniqueId(UUID $uuid){ - $this->uuid = $uuid; - } - - public function dataPacket(DataPacket $packet, $needACK = false){ - $this->interface->putPacket($this, $packet, $needACK); - } - - public function directDataPacket(DataPacket $packet, $needACK = false){ - $this->interface->putPacket($this, $packet, $needACK, true); - } -} \ No newline at end of file diff --git a/src/synapse/Synapse.php b/src/synapse/Synapse.php deleted file mode 100644 index ab81996..0000000 --- a/src/synapse/Synapse.php +++ /dev/null @@ -1,233 +0,0 @@ -getHash() => [ - "ip" => $client->getIp(), - "port" => $client->getPort(), - "playerCount" => count($client->getPlayers()), - "maxPlayers" => $client->getMaxPlayers(), - "description" => $client->getDescription(), - ] - */ - private $description; - - public function __construct(Server $server, array $config){ - self::$obj = $this; - $this->server = $server; - $this->serverIp = $config["server-ip"]; - $this->port = $config["server-port"]; - $this->isMainServer = $config["isMainServer"]; - $this->password = $config["password"]; - $this->description = $config["description"]; - $this->logger = $server->getLogger(); - $this->interface = new SynapseInterface($this, $this->serverIp, $this->port); - $this->synLibInterface = new SynLibInterface($this, $this->interface); - $this->lastUpdate = microtime(true); - $this->lastRecvInfo = microtime(true); - $this->connect(); - } - - public function getClientData(){ - return $this->clientData; - } - - public function getdevmineServer(){ - return $this->server; - } - - public function getInterface(){ - return $this->interface; - } - - public static function getInstance(){ - return self::$obj; - } - - public function shutdown(){ - if($this->verified){ - $pk = new DisconnectPacket(); - $pk->type = DisconnectPacket::TYPE_GENERIC; - $pk->message = "Server closed"; - $this->sendDataPacket($pk); - $this->getLogger()->debug("Synapse client has disconnected from Synapse server"); - } - } - - public function getDescription() : string{ - return $this->description; - } - - public function setDescription(string $description){ - $this->description = $description; - } - - public function sendDataPacket(DataPacket $pk){ - $this->interface->putPacket($pk); - } - - public function connect(){ - $this->verified = false; - $pk = new ConnectPacket(); - $pk->password = $this->password; - $pk->isMainServer = $this->isMainServer(); - $pk->description = $this->description; - $pk->maxPlayers = $this->server->getMaxPlayers(); - $pk->protocol = Info::CURRENT_PROTOCOL; - $this->sendDataPacket($pk); - } - - public function tick(){ - $this->interface->process(); - if((($time = microtime(true)) - $this->lastUpdate) >= 5){//Heartbeat! - $this->lastUpdate = $time; - $pk = new HeartbeatPacket(); - $pk->tps = $this->server->getTicksPerSecondAverage(); - $pk->load = $this->server->getTickUsageAverage(); - $pk->upTime = microtime(true) - \devmine\START_TIME; - $this->sendDataPacket($pk); - } - if(((($time = microtime(true)) - $this->lastUpdate) >= 30) and $this->interface->isConnected()){//30 seconds timeout - $this->interface->reconnect(); - } - } - - public function getServerIp() : string{ - return $this->serverIp; - } - - public function getPort() : int{ - return $this->port; - } - - public function isMainServer() : bool{ - return $this->isMainServer; - } - - public function getLogger(){ - return $this->logger; - } - - public function getHash() : string{ - return $this->serverIp . ":" . $this->port; - } - - public function getPacket($buffer){ - $pid = ord($buffer{0}); - $start = 1; - if($pid == 0xfe){ - $pid = ord($buffer{1}); - $start++; - } - if(($data = $this->getdevmineServer()->getNetwork()->getPacket($pid)) === null){ - return null; - } - $data->setBuffer($buffer, $start); - - return $data; - } - - public function removePlayer(Player $player){ - if(isset($this->players[$uuid = $player->getUniqueId()->toBinary()])){ - unset($this->players[$uuid]); - } - } - - public function handleDataPacket(DataPacket $pk){ - $this->logger->debug("Received packet " . $pk::NETWORK_ID . " from {$this->serverIp}:{$this->port}"); - switch($pk::NETWORK_ID){ - case Info::DISCONNECT_PACKET: - /** @var DisconnectPacket $pk */ - $this->verified = false; - switch($pk->type){ - case DisconnectPacket::TYPE_GENERIC: - $this->getLogger()->notice("Synapse Client has disconnected due to " . $pk->message); - $this->interface->reconnect(); - break; - case DisconnectPacket::TYPE_WRONG_PROTOCOL: - $this->getLogger()->error($pk->message); - break; - } - break; - case Info::INFORMATION_PACKET: - /** @var InformationPacket $pk */ - switch($pk->type){ - case InformationPacket::TYPE_LOGIN: - if($pk->message == InformationPacket::INFO_LOGIN_SUCCESS){ - $this->logger->info("Login success to {$this->serverIp}:{$this->port}"); - $this->verified = true; - }elseif($pk->message == InformationPacket::INFO_LOGIN_FAILED){ - $this->logger->info("Login failed to {$this->serverIp}:{$this->port}"); - } - break; - case InformationPacket::TYPE_CLIENT_DATA: - $this->clientData = json_decode($pk->message, true); - $this->lastRecvInfo = microtime(); - break; - } - break; - case Info::PLAYER_LOGIN_PACKET: - /** @var PlayerLoginPacket $pk */ - $player = new Player($this->synLibInterface, mt_rand(0, PHP_INT_MAX), $pk->address, $pk->port); - $player->setUniqueId($pk->uuid); - $this->server->addPlayer(spl_object_hash($player), $player); - $this->players[$pk->uuid->toBinary()] = $player; - $player->handleLoginPacket($pk); - break; - case Info::REDIRECT_PACKET: - /** @var RedirectPacket $pk */ - if(isset($this->players[$uuid = $pk->uuid->toBinary()])){ - $pk = $this->getPacket($pk->mcpeBuffer); - if($pk != null){//drop unknown packet - $pk->decode(); - $this->players[$uuid]->handleDataPacket($pk); - } - } - break; - case Info::PLAYER_LOGOUT_PACKET: - /** @var PlayerLogoutPacket $pk */ - if(isset($this->players[$uuid = $pk->uuid->toBinary()])){ - $this->players[$uuid]->close("", $pk->reason, false); - $this->removePlayer($this->players[$uuid]); - } - break; - } - } -} diff --git a/src/synapse/event/Event.php b/src/synapse/event/Event.php deleted file mode 100644 index 16bb1d2..0000000 --- a/src/synapse/event/Event.php +++ /dev/null @@ -1,11 +0,0 @@ -player = $player; - $this->firstTime = $firstTime; - } - - /** - * Gets if the player is first time login - * - * @return bool - */ - public function isFirstTime() : bool{ - return $this->firstTime; - } -} \ No newline at end of file diff --git a/src/synapse/event/player/PlayerEvent.php b/src/synapse/event/player/PlayerEvent.php deleted file mode 100644 index 5defadf..0000000 --- a/src/synapse/event/player/PlayerEvent.php +++ /dev/null @@ -1,16 +0,0 @@ -player; - } -} \ No newline at end of file diff --git a/src/synapse/network/Network.php b/src/synapse/network/Network.php deleted file mode 100644 index 016b26e..0000000 --- a/src/synapse/network/Network.php +++ /dev/null @@ -1,9 +0,0 @@ -synapse = $synapse; - $this->synapseInterface = $interface; - } - - public function emergencyShutdown(){ - } - - public function setName($name){ - } - - public function process(){ - } - - public function close(Player $player, $reason = "unknown reason"){ - } - - public function putPacket(Player $player, DataPacket $packet, $needACK = false, $immediate = true){ - $packet->encode(); - $pk = new RedirectPacket(); - $pk->uuid = $player->getUniqueId(); - $pk->direct = $immediate; - $pk->mcpeBuffer = $packet->buffer; - $this->synapseInterface->putPacket($pk); - } - - public function shutdown(){ - } -} \ No newline at end of file diff --git a/src/synapse/network/SynapseInterface.php b/src/synapse/network/SynapseInterface.php deleted file mode 100644 index dd7e48b..0000000 --- a/src/synapse/network/SynapseInterface.php +++ /dev/null @@ -1,117 +0,0 @@ -synapse = $server; - $this->ip = $ip; - $this->port = $port; - $this->registerPackets(); - $this->client = new SynapseClient($server->getLogger(), $server->getdevmineServer()->getLoader(), $port, $ip); - } - - public function getSynapse(){ - return $this->synapse; - } - - public function reconnect(){ - $this->client->reconnect(); - } - - public function shutdown(){ - $this->client->shutdown(); - } - - public function putPacket(DataPacket $pk){ - if(!$pk->isEncoded){ - $pk->encode(); - } - $this->client->pushMainToThreadPacket($pk->buffer); - } - - public function isConnected() : bool{ - return $this->connected; - } - - public function process(){ - while(strlen($buffer = $this->client->readThreadToMainPacket()) > 0){ - $this->handlePacket($buffer); - } - $this->connected = $this->client->isConnected(); - if($this->client->isNeedAuth()){ - $this->synapse->connect(); - $this->client->setNeedAuth(false); - } - } - - /** - * @param $buffer - * - * @return DataPacket - */ - public function getPacket($buffer) { - $pid = ord($buffer{0}); - /** @var DataPacket $class */ - $class = $this->packetPool[$pid]; - if ($class !== null) { - $pk = clone $class; - $pk->setBuffer($buffer, 1); - return $pk; - } - return null; - } - - public function handlePacket($buffer){ - if(($pk = $this->getPacket($buffer)) != null){ - $pk->decode(); - $this->synapse->handleDataPacket($pk); - } - } - - /** - * @param int $id 0-255 - * @param DataPacket $class - */ - public function registerPacket($id, $class) { - $this->packetPool[$id] = new $class; - } - - - private function registerPackets() { - $this->packetPool = new \SplFixedArray(256); - - $this->registerPacket(Info::HEARTBEAT_PACKET, HeartbeatPacket::class); - $this->registerPacket(Info::CONNECT_PACKET, ConnectPacket::class); - $this->registerPacket(Info::DISCONNECT_PACKET, DisconnectPacket::class); - $this->registerPacket(Info::REDIRECT_PACKET, RedirectPacket::class); - $this->registerPacket(Info::PLAYER_LOGIN_PACKET, PlayerLoginPacket::class); - $this->registerPacket(Info::PLAYER_LOGOUT_PACKET, PlayerLogoutPacket::class); - $this->registerPacket(Info::INFORMATION_PACKET, InformationPacket::class); - $this->registerPacket(Info::TRANSFER_PACKET, TransferPacket::class); - } -} \ No newline at end of file diff --git a/src/synapse/network/protocol/spp/ConnectPacket.php b/src/synapse/network/protocol/spp/ConnectPacket.php deleted file mode 100644 index 8483044..0000000 --- a/src/synapse/network/protocol/spp/ConnectPacket.php +++ /dev/null @@ -1,33 +0,0 @@ -reset(); - $this->putInt($this->protocol); - $this->putInt($this->maxPlayers); - $this->putByte($this->isMainServer ? 1 : 0); - $this->putString($this->description); - $this->putString($this->password); - } - - public function decode(){ - $this->protocol = $this->getInt(); - $this->maxPlayers = $this->getInt(); - $this->isMainServer = ($this->getByte() == 1) ? true : false; - $this->description = $this->getString(); - $this->password = $this->getString(); - } - -} \ No newline at end of file diff --git a/src/synapse/network/protocol/spp/DataPacket.php b/src/synapse/network/protocol/spp/DataPacket.php deleted file mode 100644 index 05a6658..0000000 --- a/src/synapse/network/protocol/spp/DataPacket.php +++ /dev/null @@ -1,11 +0,0 @@ -reset(); - $this->putByte($this->type); - $this->putString($this->message); - } - - public function decode(){ - $this->type = $this->getByte(); - $this->message = $this->getString(); - } -} \ No newline at end of file diff --git a/src/synapse/network/protocol/spp/HeartbeatPacket.php b/src/synapse/network/protocol/spp/HeartbeatPacket.php deleted file mode 100644 index 80d2f96..0000000 --- a/src/synapse/network/protocol/spp/HeartbeatPacket.php +++ /dev/null @@ -1,26 +0,0 @@ -reset(); - $this->putFloat($this->tps); - $this->putFloat($this->load); - $this->putLong($this->upTime); - } - - public function decode(){ - $this->tps = $this->getFloat(); - $this->load = $this->getFloat(); - $this->upTime = $this->getLong(); - } -} \ No newline at end of file diff --git a/src/synapse/network/protocol/spp/Info.php b/src/synapse/network/protocol/spp/Info.php deleted file mode 100644 index c582203..0000000 --- a/src/synapse/network/protocol/spp/Info.php +++ /dev/null @@ -1,18 +0,0 @@ -reset(); - $this->putByte($this->type); - $this->putString($this->message); - } - - public function decode(){ - $this->type = $this->getByte(); - $this->message = $this->getString(); - } -} \ No newline at end of file diff --git a/src/synapse/network/protocol/spp/PlayerLoginPacket.php b/src/synapse/network/protocol/spp/PlayerLoginPacket.php deleted file mode 100644 index e4f1798..0000000 --- a/src/synapse/network/protocol/spp/PlayerLoginPacket.php +++ /dev/null @@ -1,35 +0,0 @@ -reset(); - $this->putUUID($this->uuid); - $this->putString($this->address); - $this->putInt($this->port); - $this->putByte($this->isFirstTime ? 1 : 0); - $this->putString($this->cachedLoginPacket); - } - - public function decode(){ - $this->uuid = $this->getUUID(); - $this->address = $this->getString(); - $this->port = $this->getInt(); - $this->isFirstTime = ($this->getByte() == 1) ? true : false; - $this->cachedLoginPacket = $this->getString(); - } -} \ No newline at end of file diff --git a/src/synapse/network/protocol/spp/PlayerLogoutPacket.php b/src/synapse/network/protocol/spp/PlayerLogoutPacket.php deleted file mode 100644 index 3c0a8ec..0000000 --- a/src/synapse/network/protocol/spp/PlayerLogoutPacket.php +++ /dev/null @@ -1,26 +0,0 @@ -reset(); - $this->putUUID($this->uuid); - $this->putString($this->reason); - } - - public function decode(){ - $this->uuid = $this->getUUID(); - $this->reason = $this->getString(); - } -} \ No newline at end of file diff --git a/src/synapse/network/protocol/spp/RedirectPacket.php b/src/synapse/network/protocol/spp/RedirectPacket.php deleted file mode 100644 index 1385e26..0000000 --- a/src/synapse/network/protocol/spp/RedirectPacket.php +++ /dev/null @@ -1,29 +0,0 @@ -reset(); - $this->putUUID($this->uuid); - $this->putByte($this->direct ? 1 : 0); - $this->putString($this->mcpeBuffer); - } - - public function decode(){ - $this->uuid = $this->getUUID(); - $this->direct = ($this->getByte() == 1) ? true : false; - $this->mcpeBuffer = $this->getString(); - } -} \ No newline at end of file diff --git a/src/synapse/network/protocol/spp/TransferPacket.php b/src/synapse/network/protocol/spp/TransferPacket.php deleted file mode 100644 index 1dc674a..0000000 --- a/src/synapse/network/protocol/spp/TransferPacket.php +++ /dev/null @@ -1,26 +0,0 @@ -reset(); - $this->putUUID($this->uuid); - $this->putString($this->clientHash); - } - - public function decode(){ - $this->uuid = $this->getUUID(); - $this->clientHash = $this->getString(); - } -} \ No newline at end of file diff --git a/src/synapse/network/synlib/ServerConnection.php b/src/synapse/network/synlib/ServerConnection.php deleted file mode 100644 index 00d10f5..0000000 --- a/src/synapse/network/synlib/ServerConnection.php +++ /dev/null @@ -1,148 +0,0 @@ -server = $server; - $this->socket = $socket; - @socket_getpeername($this->socket->getSocket(), $address, $port); - $this->ip = $address; - $this->port = $port; - - $this->lastCheck = microtime(true); - $this->connected = true; - - $this->run(); - } - - public function run(){ - $this->tickProcessor(); - } - - private function tickProcessor(){ - while(!$this->server->isShutdown()){ - $start = microtime(true); - $this->tick(); - $time = microtime(true); - if($time - $start < 0.01){ - @time_sleep_until($time + 0.01 - ($time - $start)); - } - } - $this->tick(); - $this->socket->close(); - } - - private function tick(){ - $this->update(); - while(($data = $this->readPacket()) !== null){ - $this->server->pushThreadToMainPacket($data); - } - while(strlen($data = $this->server->readMainToThreadPacket()) > 0){ - $this->writePacket($data); - } - } - - public function getHash(){ - return $this->ip . ':' . $this->port; - } - - public function getIp() : string{ - return $this->ip; - } - - public function getPort() : int{ - return $this->port; - } - - public function update(){ - if($this->server->needReconnect and $this->connected){ - $this->connected = false; - $this->server->needReconnect = false; - } - if($this->connected){ - $err = socket_last_error($this->socket->getSocket()); - socket_clear_error($this->socket->getSocket()); - if($err == 10057 or $err == 10054){ - $this->server->getLogger()->error("Synapse connection has disconnected unexpectedly"); - $this->connected = false; - $this->server->setConnected(false); - }else{ - $data = @socket_read($this->socket->getSocket(), 65535, PHP_BINARY_READ); - if($data != ""){ - $this->receiveBuffer .= $data; - } - if($this->sendBuffer != ""){ - @socket_write($this->socket->getSocket(), $this->sendBuffer); - $this->sendBuffer = ""; - } - } - }else{ - if((($time = microtime(true)) - $this->lastCheck) >= 3){//re-connect - $this->server->getLogger()->notice("Trying to re-connect to Synapse Server"); - if($this->socket->connect()){ - $this->connected = true; - @socket_getpeername($this->socket->getSocket(), $address, $port); - $this->ip = $address; - $this->port = $port; - $this->server->setConnected(true); - $this->server->setNeedAuth(true); - } - $this->lastCheck = $time; - } - } - } - - public function getSocket(){ - return $this->socket; - } - - public function readPacket(){ - $end = explode(self::MAGIC_BYTES, $this->receiveBuffer, 2);//用MAGIC_BYTES分割缓存,仅分割成两个 - if(count($end) <= 2){//如果存在两个及以下(废话) - if(count($end) == 1){//如果只有一个 - if(strstr($end[0], self::MAGIC_BYTES)){//判断是否为MAGIC_BYTES结尾,是的话就是一个完整的包 - $this->receiveBuffer = "";//清空缓存 - }else{ - return null; - } - }else{ - $this->receiveBuffer = $end[1];//否则剩余缓存为数组的第一个成员 - } - $buffer = $end[0]; - if(strlen($buffer) < 4){//如果长度小于4 - return null; - } - $len = Binary::readLInt(substr($buffer, 0, 4));//开头四个字节是包长度 - $buffer = substr($buffer, 4);//截取剩余的缓存,长度后面的都是包的内容了 - if($len != strlen($buffer)){//校验长度 - throw new \Exception("Wrong packet $buffer"); - } - return $buffer; - } - return null; - } - - public function writePacket($data){ - $this->sendBuffer .= Binary::writeLInt(strlen($data)) . $data . self::MAGIC_BYTES; - } - -} \ No newline at end of file diff --git a/src/synapse/network/synlib/SynapseClient.php b/src/synapse/network/synlib/SynapseClient.php deleted file mode 100644 index 073c40f..0000000 --- a/src/synapse/network/synlib/SynapseClient.php +++ /dev/null @@ -1,220 +0,0 @@ -logger = $logger; - $this->interface = $interface; - $this->port = (int) $port; - if($port < 1 or $port > 65536){ - throw new \Exception("Invalid port range"); - } - - $this->setClassLoader($loader); - - $this->shutdown = false; - $this->externalQueue = new \Threaded; - $this->internalQueue = new \Threaded; - - if(\Phar::running(true) !== ""){ - $this->mainPath = \Phar::running(true); - }else{ - $this->mainPath = \getcwd() . DIRECTORY_SEPARATOR; - } - - $this->start(); - } - - public function reconnect(){ - $this->needReconnect = true; - } - - public function isNeedAuth() : bool{ - return $this->needAuth; - } - - public function setNeedAuth(bool $need){ - $this->needAuth = $need; - } - - public function isConnected() : bool{ - return $this->connected; - } - - public function setConnected(bool $con){ - $this->connected = $con; - } - - public function quit(){ - $this->shutdown(); - parent::quit(); - } - - public function run(){ - $this->registerClassLoader(); - gc_enable(); - error_reporting(-1); - ini_set("display_errors", 1); - ini_set("display_startup_errors", 1); - - set_error_handler([$this, "errorHandler"], E_ALL); - register_shutdown_function([$this, "shutdownHandler"]); - - try{ - $socket = new SynapseSocket($this->getLogger(), $this->port, $this->interface); - new ServerConnection($this, $socket); - }catch(\Throwable $e){ - $this->logger->logException($e); - } - } - - public function shutdownHandler(){ - if($this->shutdown !== true){ - $this->getLogger()->emergency("SynLib crashed!"); - } - } - - public function errorHandler($errno, $errstr, $errfile, $errline, $context, $trace = null){ - if(error_reporting() === 0){ - return false; - } - $errorConversion = [ - E_ERROR => "E_ERROR", - E_WARNING => "E_WARNING", - E_PARSE => "E_PARSE", - E_NOTICE => "E_NOTICE", - E_CORE_ERROR => "E_CORE_ERROR", - E_CORE_WARNING => "E_CORE_WARNING", - E_COMPILE_ERROR => "E_COMPILE_ERROR", - E_COMPILE_WARNING => "E_COMPILE_WARNING", - E_USER_ERROR => "E_USER_ERROR", - E_USER_WARNING => "E_USER_WARNING", - E_USER_NOTICE => "E_USER_NOTICE", - E_STRICT => "E_STRICT", - E_RECOVERABLE_ERROR => "E_RECOVERABLE_ERROR", - E_DEPRECATED => "E_DEPRECATED", - E_USER_DEPRECATED => "E_USER_DEPRECATED", - ]; - $errno = isset($errorConversion[$errno]) ? $errorConversion[$errno] : $errno; - if(($pos = strpos($errstr, "\n")) !== false){ - $errstr = substr($errstr, 0, $pos); - } - $errfile = $this->cleanPath($errfile); - - $this->getLogger()->debug("An $errno error happened: \"$errstr\" in \"$errfile\" at line $errline"); - - foreach(($trace = $this->getTrace($trace === null ? 3 : 0, $trace)) as $i => $line){ - $this->getLogger()->debug($line); - } - - return true; - } - - public function getTrace($start = 1, $trace = null){ - if($trace === null){ - if(function_exists("xdebug_get_function_stack")){ - $trace = array_reverse(xdebug_get_function_stack()); - }else{ - $e = new \Exception(); - $trace = $e->getTrace(); - } - } - - $messages = []; - $j = 0; - for($i = (int) $start; isset($trace[$i]); ++$i, ++$j){ - $params = ""; - if(isset($trace[$i]["args"]) or isset($trace[$i]["params"])){ - if(isset($trace[$i]["args"])){ - $args = $trace[$i]["args"]; - }else{ - $args = $trace[$i]["params"]; - } - foreach($args as $name => $value){ - $params .= (is_object($value) ? get_class($value) . " " . (method_exists($value, "__toString") ? $value->__toString() : "object") : gettype($value) . " " . @strval($value)) . ", "; - } - } - $messages[] = "#$j " . (isset($trace[$i]["file"]) ? $this->cleanPath($trace[$i]["file"]) : "") . "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . substr($params, 0, -2) . ")"; - } - - return $messages; - } - - public function cleanPath($path){ - return rtrim(str_replace(["\\", ".php", "phar://", rtrim(str_replace(["\\", "phar://"], ["/", ""], $this->mainPath), "/")], ["/", "", "", ""], $path), "/"); - } - - public function getExternalQueue(){ - return $this->externalQueue; - } - - public function getInternalQueue(){ - return $this->internalQueue; - } - - public function pushMainToThreadPacket($str){ - $this->internalQueue[] = $str; - } - - public function readMainToThreadPacket(){ - return $this->internalQueue->shift(); - } - - public function pushThreadToMainPacket($str){ - $this->externalQueue[] = $str; - } - - public function readThreadToMainPacket(){ - return $this->externalQueue->shift(); - } - - public function isShutdown(){ - return $this->shutdown === true; - } - - public function shutdown(){ - $this->shutdown = true; - } - - public function getPort(){ - return $this->port; - } - - public function getInterface(){ - return $this->interface; - } - - /** - * @return \ThreadedLogger - */ - public function getLogger(){ - return $this->logger; - } - - public function isGarbage() : bool{ - parent::isGarbage(); - } - - public function getThreadName(){ - return "SynapseClient"; - } - -} \ No newline at end of file diff --git a/src/synapse/network/synlib/SynapseSocket.php b/src/synapse/network/synlib/SynapseSocket.php deleted file mode 100644 index 0b24452..0000000 --- a/src/synapse/network/synlib/SynapseSocket.php +++ /dev/null @@ -1,41 +0,0 @@ -logger = $logger; - $this->interface = $interface; - $this->port = $port; - $this->connect(); - } - - public function connect(){ - $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); - if($this->socket === false or !@socket_connect($this->socket, $this->interface, $this->port)){ - $this->logger->critical("Synapse Client can't connect $this->interface:$this->port"); - $this->logger->error("Socket error: " . socket_strerror(socket_last_error())); - return false; - } - $this->logger->info("Synapse has connected to $this->interface:$this->port"); - socket_set_nonblock($this->socket); - return true; - } - - public function getSocket(){ - return $this->socket; - } - - public function close(){ - socket_close($this->socket); - } -} \ No newline at end of file diff --git a/start.cmd b/start.cmd new file mode 100644 index 0000000..6824b40 --- /dev/null +++ b/start.cmd @@ -0,0 +1,25 @@ +@echo off +TITLE Devmine- The Awesome software that does NOT use the DevMine folder structure! +cd /d %~dp0 + +if exist bin\php\php.exe ( + set PHPRC="" + set PHP_BINARY=bin\php\php.exe +) else ( + set PHP_BINARY=php +) + +if exist src\devmine\server\DevMine.php ( + set DEVMINE_FILE=src\devmine\server\DevMine.php + ) else ( + echo "error> There was an error in starting DevMine. Check that there is either a file named DevMine.phar or an src folder, or try reinstalling DevMine." + pause + exit 7 + ) +) +if exist bin\mintty.exe ( + start "" bin\mintty.exe -o Columns=88 -o Rows=32 -o AllowBlinking=0 -o FontQuality=3 -o Font="DejaVu Sans Mono" -o FontHeight=10 -o CursorType=0 -o CursorBlinks=1 -h error -t "DevMine" -w max %PHP_BINARY% %DevMine_FILE% --enable-ansi %* +) else ( + %PHP_BINARY% -c bin\php %DevMine_FILE% %* +) +pause diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..a56fb91 --- /dev/null +++ b/start.sh @@ -0,0 +1,74 @@ +# Variable define +DIR="$(cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" + +# Change Directory +cd "$DIR" + +# Loop starting +# Don't edit this if you don't know what this does! + +DO_LOOP="no" + +########################################## +# DO NOT EDIT ANYTHING BEYOND THIS LINE! # +########################################## + +while getopts "p:f:l" OPTION 2> /dev/null; do + case ${OPTION} in + p) + PHP_BINARY="$OPTARG" + ;; + f) + DevMine_FILE="$OPTARG" + ;; + l) + DO_LOOP="yes" + ;; + \?) + break + ;; + esac +done + +if [ "$PHP_BINARY" == "" ]; then + if [ -f ./bin/php7/bin/php ]; then + export PHPRC="" + PHP_BINARY="./bin/php7/bin/php" + elif type php 2>/dev/null; then + PHP_BINARY=$(type -p php) + else + echo "[ERROR] Couldn't find a working PHP binary, please use the installer." + exit 1 + fi +fi + +if [ "$Devmine_FILE" == "" ]; then + if [ -f ./DevMine-devmine.phar ]; then + DevMine_FILE="./DevMine-devmine.phar" + elif [ -f ./Devmine*.phar ]; then + DevMine_FILE="./DevMine*.phar" + elif [ -f ./DevMine-MP.phar ]; then + DevMine_FILE="./DevMine-MP.phar" + elif [ -f ./src/devmine/server/DevMine.php ]; then + Devmine_FILE="./src/devmine/server/DevMine.php" + else + echo "[ERROR] Couldn't find a valid Devmine installation." + exit 1 + fi +fi + +LOOPS=0 + +set +e +while [ "$LOOPS" -eq 0 ] || [ "$DO_LOOP" == "yes" ]; do + if [ "$DO_LOOP" == "yes" ]; then + "$PHP_BINARY" $DevMine_FILE $@ + else + exec "$PHP_BINARY" $DevMine_FILE $@ + fi + ((LOOPS++)) +done + +if [ ${LOOPS} -gt 1 ]; then + echo "[INFO] Restarted $LOOPS times" +fi