forked from SteamWar/SteamWar
Merge branch 'main' into FightSystem/fix-tech-and-hull-hider
This commit is contained in:
@@ -25,6 +25,23 @@ tasks.compileJava {
|
||||
options.isWarnings = false
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.compilerArgs.addAll(
|
||||
listOf(
|
||||
"--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
jvmArgs("--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.classindex)
|
||||
annotationProcessor(libs.classindex)
|
||||
@@ -32,11 +49,14 @@ dependencies {
|
||||
compileOnly(project(":CommandFramework", "default"))
|
||||
compileOnly(project(":SpigotCore:CRIUDummy", "default"))
|
||||
|
||||
compileOnly(libs.worldedit12)
|
||||
compileOnly(libs.fawe)
|
||||
|
||||
compileOnly(libs.spigotapi)
|
||||
compileOnly(libs.netty)
|
||||
compileOnly(libs.paperapi)
|
||||
compileOnly(libs.nms)
|
||||
compileOnly(libs.authlib)
|
||||
compileOnly(libs.datafixer)
|
||||
compileOnly(libs.netty)
|
||||
compileOnly(libs.brigadier)
|
||||
compileOnly(libs.fastutil)
|
||||
compileOnly(libs.nms21)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
LOCAL_CHAT=§eLocal §r{0}§8»§7 {1}
|
||||
LOCAL_CHAT = §eLocal §r{0}§8»§7 {1}
|
||||
|
||||
COMMAND_SYSTEM_ERROR = §cError executing the command!
|
||||
|
||||
@@ -25,86 +25,86 @@ SWLISINV_NEXT_PAGE_INACTIVE = §7Next page
|
||||
SWLISINV_PREVIOUS_PAGE_ACTIVE = §ePrevious page
|
||||
SWLISINV_PREVIOUS_PAGE_INACTIVE = §7Previous page
|
||||
|
||||
SCHEM_SELECTOR_TITLE={0} selection: {1}
|
||||
SCHEM_SELECTOR_BACK=§eBack
|
||||
SCHEM_SELECTOR_DIR=§9Directory
|
||||
SCHEM_SELECTOR_RANK=§8Rank {0}
|
||||
SCHEM_SELECTOR_OWN=§7Own schematics
|
||||
SCHEM_SELECTOR_PUB=§7Public schematics
|
||||
SCHEM_SELECTOR_SEL_DIR=§7Select directory
|
||||
SCHEM_SELECTOR_NEW_DIR=§7New directory
|
||||
SCHEM_SELECTOR_FILTER=§7Filter
|
||||
SCHEM_SELECTOR_SORTING=§7Order by
|
||||
SCHEM_SELECTOR_SORTING_CURRENT=§7Current: §e{0}
|
||||
SCHEM_SELECTOR_SORTING_NAME=Name
|
||||
SCHEM_SELECTOR_SORTING_TYPE=Schematic type
|
||||
SCHEM_SELECTOR_SORTING_UPDATE=Last update
|
||||
SCHEM_SELECTOR_SORTING_DIRECTION=§e{0} §7order
|
||||
SCHEM_SELECTOR_SORTING_ASC=Ascending
|
||||
SCHEM_SELECTOR_SORTING_DSC=Descending
|
||||
SCHEM_SELECTOR_CLICK_BACK=§7Click to go back
|
||||
SCHEM_SELECTOR_TITLE = {0} selection: {1}
|
||||
SCHEM_SELECTOR_BACK = §eBack
|
||||
SCHEM_SELECTOR_DIR = §9Directory
|
||||
SCHEM_SELECTOR_RANK = §8Rank {0}
|
||||
SCHEM_SELECTOR_OWN = §7Own schematics
|
||||
SCHEM_SELECTOR_PUB = §7Public schematics
|
||||
SCHEM_SELECTOR_SEL_DIR = §7Select directory
|
||||
SCHEM_SELECTOR_NEW_DIR = §7New directory
|
||||
SCHEM_SELECTOR_FILTER = §7Filter
|
||||
SCHEM_SELECTOR_SORTING = §7Order by
|
||||
SCHEM_SELECTOR_SORTING_CURRENT = §7Current: §e{0}
|
||||
SCHEM_SELECTOR_SORTING_NAME = Name
|
||||
SCHEM_SELECTOR_SORTING_TYPE = Schematic type
|
||||
SCHEM_SELECTOR_SORTING_UPDATE = Last update
|
||||
SCHEM_SELECTOR_SORTING_DIRECTION = §e{0} §7order
|
||||
SCHEM_SELECTOR_SORTING_ASC = Ascending
|
||||
SCHEM_SELECTOR_SORTING_DSC = Descending
|
||||
SCHEM_SELECTOR_CLICK_BACK = §7Click to go back
|
||||
|
||||
SCHEM_SELECTOR_ITEM_NAME=§e{0}
|
||||
SCHEM_SELECTOR_ITEM_NAME_FILTER=§7{0}
|
||||
SCHEM_SELECTOR_ITEM_REPLACE=§e{0}§7
|
||||
SCHEM_SELECTOR_ITEM_LORE_TYPE=§7{0}
|
||||
SCHEM_SELECTOR_ITEM_NAME = §e{0}
|
||||
SCHEM_SELECTOR_ITEM_NAME_FILTER = §7{0}
|
||||
SCHEM_SELECTOR_ITEM_REPLACE = §e{0}§7
|
||||
SCHEM_SELECTOR_ITEM_LORE_TYPE = §7{0}
|
||||
|
||||
SCHEM_SELECTOR_CREATE_DIR_TITLE=Create directory
|
||||
SCHEM_SELECTOR_CREATE_DIR_TITLE = Create directory
|
||||
|
||||
SCHEM_SELECTOR_FILTER_TITLE=Filter
|
||||
SCHEM_SELECTOR_FILTER_ENTER_NAME=Insert name
|
||||
SCHEM_SELECTOR_FILTER_NAME=§7Search by name...
|
||||
SCHEM_SELECTOR_FILTER_NAME_SEARCH=§7Search term: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_ENTER_OWNER=Choose owner
|
||||
SCHEM_SELECTOR_FILTER_OWNER=§7Search by owner...
|
||||
SCHEM_SELECTOR_FILTER_OWNER_SEARCH=§7Owner: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_SEL_TYPE=Choose type...
|
||||
SCHEM_SELECTOR_FILTER_TYPE=§7Search by type...
|
||||
SCHEM_SELECTOR_FILTER_TYPE_SEARCH=§7Type: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_MAT=§7Filter by item...
|
||||
SCHEM_SELECTOR_FILTER_MAT_SEARCH=§7Item: §e{0}
|
||||
SCHEM_SELECTOR_CANCEL=§eCancel
|
||||
SCHEM_SELECTOR_GO=§eSearch...
|
||||
SCHEM_SELECTOR_SCHEMATIC=Schematic
|
||||
SCHEM_SELECTOR_DIRECTORY=Directory
|
||||
SCHEM_SELECTOR_SCHEMATIC_NODE=Schematic/Directory
|
||||
SCHEM_SELECTOR_FILTER_TITLE = Filter
|
||||
SCHEM_SELECTOR_FILTER_ENTER_NAME = Insert name
|
||||
SCHEM_SELECTOR_FILTER_NAME = §7Search by name...
|
||||
SCHEM_SELECTOR_FILTER_NAME_SEARCH = §7Search term: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_ENTER_OWNER = Choose owner
|
||||
SCHEM_SELECTOR_FILTER_OWNER = §7Search by owner...
|
||||
SCHEM_SELECTOR_FILTER_OWNER_SEARCH = §7Owner: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_SEL_TYPE = Choose type...
|
||||
SCHEM_SELECTOR_FILTER_TYPE = §7Search by type...
|
||||
SCHEM_SELECTOR_FILTER_TYPE_SEARCH = §7Type: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_MAT = §7Filter by item...
|
||||
SCHEM_SELECTOR_FILTER_MAT_SEARCH = §7Item: §e{0}
|
||||
SCHEM_SELECTOR_CANCEL = §eCancel
|
||||
SCHEM_SELECTOR_GO = §eSearch...
|
||||
SCHEM_SELECTOR_SCHEMATIC = Schematic
|
||||
SCHEM_SELECTOR_DIRECTORY = Directory
|
||||
SCHEM_SELECTOR_SCHEMATIC_NODE = Schematic/Directory
|
||||
|
||||
SCHEM_SELECTOR_FILTER_TITLE_SINGLE=§eSingle Filter
|
||||
SCHEM_SELECTOR_FILTER_TITLE_MULTI=§e{0} Filters
|
||||
SCHEM_SELECTOR_FILTER_TITLE_EMPTY=§eNo Filters
|
||||
SCHEM_SELECTOR_FILTER_EMPTY=§7Empty
|
||||
SCHEM_SELECTOR_FILTER_TITLE_SINGLE = §eSingle Filter
|
||||
SCHEM_SELECTOR_FILTER_TITLE_MULTI = §e{0} Filters
|
||||
SCHEM_SELECTOR_FILTER_TITLE_EMPTY = §eNo Filters
|
||||
SCHEM_SELECTOR_FILTER_EMPTY = §7Empty
|
||||
|
||||
MATERIAL_SELECTOR_TITLE=Select material
|
||||
MATERIAL_SELECTOR_TITLE = Select material
|
||||
|
||||
BAN_TEAM={0} §e{1} §7was §e§lbanned§7 by §e{2} {3}§8: §f{4}
|
||||
BAN_PERMA=§7You are §e§lbanned §epermanently§8: §e{0}
|
||||
BAN_UNTIL=§7You are §e§lbanned §euntil {0}§8: §e{1}
|
||||
UNBAN_ERROR=§cThe player isn't banned.
|
||||
UNBAN=§7You have §e§lunbanned §e{0}.
|
||||
BAN_TEAM = {0} §e{1} §7was §e§lbanned§7 by §e{2} {3}§8: §f{4}
|
||||
BAN_PERMA = §7You are §e§lbanned §epermanently§8: §e{0}
|
||||
BAN_UNTIL = §7You are §e§lbanned §euntil {0}§8: §e{1}
|
||||
UNBAN_ERROR = §cThe player isn't banned.
|
||||
UNBAN = §7You have §e§lunbanned §e{0}.
|
||||
|
||||
MUTE_TEAM={0} §e{1} §7was §e§lmuted§7 by §e{2} {3}§8: §f{4}
|
||||
MUTE_PERMA=§7You are §epermanently §e§lmuted§8: §e{0}
|
||||
MUTE_UNTIL=§7You are §e§lmuted §euntil {0}§8: §e{1}
|
||||
UNMUTE_ERROR=§cThe player isn't muted.
|
||||
UNMUTE=§7You have §e§lunmuted §e{0}.
|
||||
MUTE_TEAM = {0} §e{1} §7was §e§lmuted§7 by §e{2} {3}§8: §f{4}
|
||||
MUTE_PERMA = §7You are §epermanently §e§lmuted§8: §e{0}
|
||||
MUTE_UNTIL = §7You are §e§lmuted §euntil {0}§8: §e{1}
|
||||
UNMUTE_ERROR = §cThe player isn't muted.
|
||||
UNMUTE = §7You have §e§lunmuted §e{0}.
|
||||
|
||||
NOSCHEMRECEIVING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lrecieving schematics§8: §f{4}
|
||||
NOSCHEMRECEIVING_PERMA=§7You are §epermanently§7 excluded from receiving §e§lschematics§8: §e{0}
|
||||
NOSCHEMRECEIVING_UNTIL=§7You are excluded from receiving §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMRECEIVING_ERROR=§cThe player is not excluded from receiving schematics.
|
||||
UNNOSCHEMRECEIVING=§e{0} §7may now receive §e§lschematics§7 again§8.
|
||||
NOSCHEMRECEIVING_TEAM = {0} §e{1} §7was excluded from §e{2} {3} §7from §e§lrecieving schematics§8: §f{4}
|
||||
NOSCHEMRECEIVING_PERMA = §7You are §epermanently§7 excluded from receiving §e§lschematics§8: §e{0}
|
||||
NOSCHEMRECEIVING_UNTIL = §7You are excluded from receiving §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMRECEIVING_ERROR = §cThe player is not excluded from receiving schematics.
|
||||
UNNOSCHEMRECEIVING = §e{0} §7may now receive §e§lschematics§7 again§8.
|
||||
|
||||
NOSCHEMSHARING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lsharing schematics§8: §f{4}
|
||||
NOSCHEMSHARING_PERMA=§7You are §epermanently§7 excluded from sharing §e§lschematics§8: §e{0}
|
||||
NOSCHEMSHARING_UNTIL=§7You are excluded from sharing §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMSHARING_ERROR=§cThe player is not excluded from sharing schematics.
|
||||
UNNOSCHEMSHARING=§e{0} §7may now share §e§lschematics§7 again§8.
|
||||
NOSCHEMSHARING_TEAM = {0} §e{1} §7was excluded from §e{2} {3} §7from §e§lsharing schematics§8: §f{4}
|
||||
NOSCHEMSHARING_PERMA = §7You are §epermanently§7 excluded from sharing §e§lschematics§8: §e{0}
|
||||
NOSCHEMSHARING_UNTIL = §7You are excluded from sharing §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMSHARING_ERROR = §cThe player is not excluded from sharing schematics.
|
||||
UNNOSCHEMSHARING = §e{0} §7may now share §e§lschematics§7 again§8.
|
||||
|
||||
NOSCHEMSUBMITTING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lsubmitting schematics§8: §f{4}
|
||||
NOSCHEMSUBMITTING_PERMA=§7You are §epermanently§7 excluded from submitting §e§lschematics§8: §e{0}
|
||||
NOSCHEMSUBMITTING_UNTIL=§7You are excluded from submitting §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMSUBMITTING_ERROR=§cThe player is not excluded from submitting schematics.
|
||||
UNNOSCHEMSUBMITTING=§e{0} §7may now submit §e§lschematics§7 again§8.
|
||||
NOSCHEMSUBMITTING_TEAM = {0} §e{1} §7was excluded from §e{2} {3} §7from §e§lsubmitting schematics§8: §f{4}
|
||||
NOSCHEMSUBMITTING_PERMA = §7You are §epermanently§7 excluded from submitting §e§lschematics§8: §e{0}
|
||||
NOSCHEMSUBMITTING_UNTIL = §7You are excluded from submitting §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMSUBMITTING_ERROR = §cThe player is not excluded from submitting schematics.
|
||||
UNNOSCHEMSUBMITTING = §e{0} §7may now submit §e§lschematics§7 again§8.
|
||||
|
||||
WORLDEDIT_CUI_TITLE = WorldEdit CUI
|
||||
WORLDEDIT_CUI_TITLE_SUBMENU = WorldEdit CUI - {0}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
LOCAL_CHAT=§eLokal §r{0}§8»§7 {1}
|
||||
LOCAL_CHAT = §eLokal §r{0}§8»§7 {1}
|
||||
|
||||
COMMAND_SYSTEM_ERROR = §cFehler beim Ausführen des Befehls!
|
||||
|
||||
@@ -25,81 +25,81 @@ SWLISINV_NEXT_PAGE_INACTIVE = §7Seite vor
|
||||
SWLISINV_PREVIOUS_PAGE_ACTIVE = §eSeite zurück
|
||||
SWLISINV_PREVIOUS_PAGE_INACTIVE = §7Seite zurück
|
||||
|
||||
SCHEM_SELECTOR_TITLE={0} auswählen: {1}
|
||||
SCHEM_SELECTOR_BACK=§eZurück
|
||||
SCHEM_SELECTOR_DIR=§9Ordner
|
||||
SCHEM_SELECTOR_RANK=§8Rang {0}
|
||||
SCHEM_SELECTOR_OWN=§7Eigene Schematics
|
||||
SCHEM_SELECTOR_PUB=§7Public Schematics
|
||||
SCHEM_SELECTOR_SEL_DIR=§7Ordner auswählen
|
||||
SCHEM_SELECTOR_NEW_DIR=§7Neuer Ordner
|
||||
SCHEM_SELECTOR_FILTER=§7Filter
|
||||
SCHEM_SELECTOR_SORTING=§7Sortierung
|
||||
SCHEM_SELECTOR_SORTING_CURRENT=§7Aktuell: §e{0}
|
||||
SCHEM_SELECTOR_SORTING_NAME=Name
|
||||
SCHEM_SELECTOR_SORTING_TYPE=Schematic-Typ
|
||||
SCHEM_SELECTOR_SORTING_UPDATE=Letztes Update
|
||||
SCHEM_SELECTOR_SORTING_DIRECTION=§7Richtung: §e{0}
|
||||
SCHEM_SELECTOR_SORTING_ASC=Aufsteigend
|
||||
SCHEM_SELECTOR_SORTING_DSC=Absteigend
|
||||
SCHEM_SELECTOR_CLICK_BACK=§7Klicke hier, um zurückzugehen
|
||||
SCHEM_SELECTOR_TITLE = {0} auswählen: {1}
|
||||
SCHEM_SELECTOR_BACK = §eZurück
|
||||
SCHEM_SELECTOR_DIR = §9Ordner
|
||||
SCHEM_SELECTOR_RANK = §8Rang {0}
|
||||
SCHEM_SELECTOR_OWN = §7Eigene Schematics
|
||||
SCHEM_SELECTOR_PUB = §7Public Schematics
|
||||
SCHEM_SELECTOR_SEL_DIR = §7Ordner auswählen
|
||||
SCHEM_SELECTOR_NEW_DIR = §7Neuer Ordner
|
||||
SCHEM_SELECTOR_FILTER = §7Filter
|
||||
SCHEM_SELECTOR_SORTING = §7Sortierung
|
||||
SCHEM_SELECTOR_SORTING_CURRENT = §7Aktuell: §e{0}
|
||||
SCHEM_SELECTOR_SORTING_NAME = Name
|
||||
SCHEM_SELECTOR_SORTING_TYPE = Schematic-Typ
|
||||
SCHEM_SELECTOR_SORTING_UPDATE = Letztes Update
|
||||
SCHEM_SELECTOR_SORTING_DIRECTION = §7Richtung: §e{0}
|
||||
SCHEM_SELECTOR_SORTING_ASC = Aufsteigend
|
||||
SCHEM_SELECTOR_SORTING_DSC = Absteigend
|
||||
SCHEM_SELECTOR_CLICK_BACK = §7Klicke hier, um zurückzugehen
|
||||
|
||||
SCHEM_SELECTOR_CREATE_DIR_TITLE=Ordner erstellen
|
||||
SCHEM_SELECTOR_CREATE_DIR_TITLE = Ordner erstellen
|
||||
|
||||
SCHEM_SELECTOR_FILTER_TITLE=Filter
|
||||
SCHEM_SELECTOR_FILTER_ENTER_NAME=Name eingeben
|
||||
SCHEM_SELECTOR_FILTER_NAME=§7Nach Namen suchen...
|
||||
SCHEM_SELECTOR_FILTER_NAME_SEARCH=§7Suchbegriff: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_ENTER_OWNER=Besitzer eingeben
|
||||
SCHEM_SELECTOR_FILTER_OWNER=§7Nach Besitzer suchen...
|
||||
SCHEM_SELECTOR_FILTER_OWNER_SEARCH=§7Besitzer: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_SEL_TYPE=Typ wählen...
|
||||
SCHEM_SELECTOR_FILTER_TYPE=§7Nach Typ filtern...
|
||||
SCHEM_SELECTOR_FILTER_TYPE_SEARCH=§7Typ: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_MAT=§7Nach Item filtern...
|
||||
SCHEM_SELECTOR_FILTER_MAT_SEARCH=§7Item: §e{0}
|
||||
SCHEM_SELECTOR_CANCEL=§eAbbrechen
|
||||
SCHEM_SELECTOR_GO=§eSuchen...
|
||||
SCHEM_SELECTOR_SCHEMATIC=Schematic
|
||||
SCHEM_SELECTOR_DIRECTORY=Ordner
|
||||
SCHEM_SELECTOR_SCHEMATIC_NODE=Schematic/Ordner
|
||||
SCHEM_SELECTOR_FILTER_TITLE = Filter
|
||||
SCHEM_SELECTOR_FILTER_ENTER_NAME = Name eingeben
|
||||
SCHEM_SELECTOR_FILTER_NAME = §7Nach Namen suchen...
|
||||
SCHEM_SELECTOR_FILTER_NAME_SEARCH = §7Suchbegriff: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_ENTER_OWNER = Besitzer eingeben
|
||||
SCHEM_SELECTOR_FILTER_OWNER = §7Nach Besitzer suchen...
|
||||
SCHEM_SELECTOR_FILTER_OWNER_SEARCH = §7Besitzer: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_SEL_TYPE = Typ wählen...
|
||||
SCHEM_SELECTOR_FILTER_TYPE = §7Nach Typ filtern...
|
||||
SCHEM_SELECTOR_FILTER_TYPE_SEARCH = §7Typ: §e{0}
|
||||
SCHEM_SELECTOR_FILTER_MAT = §7Nach Item filtern...
|
||||
SCHEM_SELECTOR_FILTER_MAT_SEARCH = §7Item: §e{0}
|
||||
SCHEM_SELECTOR_CANCEL = §eAbbrechen
|
||||
SCHEM_SELECTOR_GO = §eSuchen...
|
||||
SCHEM_SELECTOR_SCHEMATIC = Schematic
|
||||
SCHEM_SELECTOR_DIRECTORY = Ordner
|
||||
SCHEM_SELECTOR_SCHEMATIC_NODE = Schematic/Ordner
|
||||
|
||||
SCHEM_SELECTOR_FILTER_TITLE_SINGLE=§eEinzelfilter
|
||||
SCHEM_SELECTOR_FILTER_TITLE_MULTI=§e{0} §e§lMehrfachfilter
|
||||
SCHEM_SELECTOR_FILTER_TITLE_EMPTY=§eKeine Filter
|
||||
SCHEM_SELECTOR_FILTER_EMPTY=§7Leer
|
||||
SCHEM_SELECTOR_FILTER_TITLE_SINGLE = §eEinzelfilter
|
||||
SCHEM_SELECTOR_FILTER_TITLE_MULTI = §e{0} §e§lMehrfachfilter
|
||||
SCHEM_SELECTOR_FILTER_TITLE_EMPTY = §eKeine Filter
|
||||
SCHEM_SELECTOR_FILTER_EMPTY = §7Leer
|
||||
|
||||
MATERIAL_SELECTOR_TITLE=Material auswählen
|
||||
MATERIAL_SELECTOR_TITLE = Material auswählen
|
||||
|
||||
BAN_TEAM={0} §e{1} §7wurde von §e{2} {3} §e§lgebannt§8: §f{4}
|
||||
BAN_PERMA=§7Du bist §epermanent §e§lgebannt§8: §e{0}
|
||||
BAN_UNTIL=§7Du bist §ebis zum {0} §e§lgebannt§8: §e{1}
|
||||
UNBAN_ERROR=§cDer Spieler ist nicht gebannt.
|
||||
UNBAN=§7Du hast §e{0} §e§lentbannt.
|
||||
BAN_TEAM = {0} §e{1} §7wurde von §e{2} {3} §e§lgebannt§8: §f{4}
|
||||
BAN_PERMA = §7Du bist §epermanent §e§lgebannt§8: §e{0}
|
||||
BAN_UNTIL = §7Du bist §ebis zum {0} §e§lgebannt§8: §e{1}
|
||||
UNBAN_ERROR = §cDer Spieler ist nicht gebannt.
|
||||
UNBAN = §7Du hast §e{0} §e§lentbannt.
|
||||
|
||||
MUTE_TEAM={0} §e{1} §7wurde von §e{2} {3} §e§lgemuted§8: §f{4}
|
||||
MUTE_PERMA=§7Du bist §epermanent §e§lgemuted§8: §e{0}
|
||||
MUTE_UNTIL=§7Du bist §ebis zum {0} §e§lgemuted§8: §e{1}
|
||||
UNMUTE_ERROR=§cDer Spieler ist nicht gemuted.
|
||||
UNMUTE=§7Du hast §e{0} §e§lentmuted.
|
||||
MUTE_TEAM = {0} §e{1} §7wurde von §e{2} {3} §e§lgemuted§8: §f{4}
|
||||
MUTE_PERMA = §7Du bist §epermanent §e§lgemuted§8: §e{0}
|
||||
MUTE_UNTIL = §7Du bist §ebis zum {0} §e§lgemuted§8: §e{1}
|
||||
UNMUTE_ERROR = §cDer Spieler ist nicht gemuted.
|
||||
UNMUTE = §7Du hast §e{0} §e§lentmuted.
|
||||
|
||||
NOSCHEMRECEIVING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematicerhalten§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMRECEIVING_PERMA=§7Du bist §epermanent §7vom Erhalten von §e§lSchematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMRECEIVING_UNTIL=§7Du bist §ebis zum {0} §7vom Erhalten von §e§lSchematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMRECEIVING_ERROR=§cDer Spieler ist nicht vom Erhalten von Schematics ausgeschlossen.
|
||||
UNNOSCHEMRECEIVING=§e{0} §7darf nun wieder §e§lSchematics§7 erhalten§8.
|
||||
NOSCHEMRECEIVING_TEAM = {0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematicerhalten§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMRECEIVING_PERMA = §7Du bist §epermanent §7vom Erhalten von §e§lSchematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMRECEIVING_UNTIL = §7Du bist §ebis zum {0} §7vom Erhalten von §e§lSchematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMRECEIVING_ERROR = §cDer Spieler ist nicht vom Erhalten von Schematics ausgeschlossen.
|
||||
UNNOSCHEMRECEIVING = §e{0} §7darf nun wieder §e§lSchematics§7 erhalten§8.
|
||||
|
||||
NOSCHEMSHARING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematicverteilen§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMSHARING_PERMA=§7Du bist §epermanent §7vom §e§lVerteilen von Schematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMSHARING_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lVerteilen von Schematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMSHARING_ERROR=§cDer Spieler ist nicht vom Verteilen von Schematics ausgeschlossen.
|
||||
UNNOSCHEMSHARING=§e{0} §7darf nun wieder §e§lSchematics§7 verteilen§8.
|
||||
NOSCHEMSHARING_TEAM = {0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematicverteilen§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMSHARING_PERMA = §7Du bist §epermanent §7vom §e§lVerteilen von Schematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMSHARING_UNTIL = §7Du bist §ebis zum {0} §7vom §e§lVerteilen von Schematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMSHARING_ERROR = §cDer Spieler ist nicht vom Verteilen von Schematics ausgeschlossen.
|
||||
UNNOSCHEMSHARING = §e{0} §7darf nun wieder §e§lSchematics§7 verteilen§8.
|
||||
|
||||
NOSCHEMSUBMITTING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematiceinsenden§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMSUBMITTING_PERMA=§7Du bist §epermanent §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMSUBMITTING_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMSUBMITTING_ERROR=§cDer Spieler ist nicht vom Einsenden von Schematics ausgeschlossen.
|
||||
UNNOSCHEMSUBMITTING=§e{0} §7darf nun wieder §e§lSchematis§7 einsenden§8.
|
||||
NOSCHEMSUBMITTING_TEAM = {0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematiceinsenden§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMSUBMITTING_PERMA = §7Du bist §epermanent §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMSUBMITTING_UNTIL = §7Du bist §ebis zum {0} §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMSUBMITTING_ERROR = §cDer Spieler ist nicht vom Einsenden von Schematics ausgeschlossen.
|
||||
UNNOSCHEMSUBMITTING = §e{0} §7darf nun wieder §e§lSchematis§7 einsenden§8.
|
||||
|
||||
WORLDEDIT_CUI_SELECTION = Eigene Auswahl
|
||||
WORLDEDIT_CUI_CLIPBOARD = Eigene Kopie
|
||||
|
||||
@@ -1,25 +1,15 @@
|
||||
package com.comphenix.tinyprotocol;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.core.Core;
|
||||
import io.netty.channel.*;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.login.ServerboundHelloPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerConnectionListener;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -40,33 +30,10 @@ import com.mojang.authlib.GameProfile;
|
||||
* Represents a very tiny alternative to ProtocolLib.
|
||||
* <p>
|
||||
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
|
||||
*
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public abstract class TinyProtocol {
|
||||
private static final AtomicInteger ID = new AtomicInteger(0);
|
||||
|
||||
// Required Minecraft classes
|
||||
private static final Class<?> entityPlayerClass = Reflection.getClass("{nms}.EntityPlayer", "net.minecraft.server.level.EntityPlayer");
|
||||
private static final Class<?> playerConnectionClass = Reflection.getClass("{nms}.PlayerConnection", "net.minecraft.server.network.PlayerConnection");
|
||||
private static final Class<?> networkManagerClass = Reflection.getClass("{nms}.NetworkManager", "net.minecraft.network.NetworkManager");
|
||||
|
||||
// Used in order to lookup a channel
|
||||
private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle");
|
||||
private static final FieldAccessor<?> getConnection = Reflection.getField(entityPlayerClass, null, playerConnectionClass);
|
||||
private static final FieldAccessor<?> getManager = Reflection.getField(playerConnectionClass, null, networkManagerClass);
|
||||
private static final FieldAccessor<Channel> getChannel = Reflection.getField(networkManagerClass, Channel.class, 0);
|
||||
|
||||
// Looking up ServerConnection
|
||||
private static final Class<Object> minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer", "net.minecraft.server.MinecraftServer");
|
||||
private static final Class<Object> serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection", "net.minecraft.server.network.ServerConnection");
|
||||
private static final FieldAccessor<Object> getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0);
|
||||
private static final FieldAccessor<Object> getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0);
|
||||
|
||||
// Packets we have to intercept
|
||||
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getClass("{nms}.PacketLoginInStart", "net.minecraft.network.protocol.login.PacketLoginInStart");
|
||||
private static final FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
|
||||
|
||||
public class TinyProtocol {
|
||||
// Speedup channel lookup
|
||||
private Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap();
|
||||
private Listener listener;
|
||||
@@ -75,7 +42,7 @@ public abstract class TinyProtocol {
|
||||
private Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().<Channel, Boolean>makeMap());
|
||||
|
||||
// List of network markers
|
||||
private List<Object> networkManagers;
|
||||
public List<Connection> networkManagers;
|
||||
|
||||
// Injected channel handlers
|
||||
private List<Channel> serverChannels = new ArrayList<>();
|
||||
@@ -84,24 +51,28 @@ public abstract class TinyProtocol {
|
||||
private ChannelInitializer<Channel> endInitProtocol;
|
||||
|
||||
// Current handler name
|
||||
private String handlerName;
|
||||
private static final String HANDLER_NAME = "tiny-steamwar";
|
||||
|
||||
protected volatile boolean closed;
|
||||
protected Plugin plugin;
|
||||
|
||||
public static final TinyProtocol instance = new TinyProtocol(Core.getInstance());
|
||||
private final Map<Class<?>, List<BiFunction<Player, Object, Object>>> packetFilters = new HashMap<>();
|
||||
|
||||
public static void init() {
|
||||
// enforce init
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients.
|
||||
* <p>
|
||||
* You can construct multiple instances per plugin.
|
||||
*
|
||||
*
|
||||
* @param plugin - the plugin.
|
||||
*/
|
||||
public TinyProtocol(final Plugin plugin) {
|
||||
private TinyProtocol(final Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
// Compute handler name
|
||||
this.handlerName = getHandlerName();
|
||||
|
||||
// Prepare existing players
|
||||
registerBukkitEvents();
|
||||
|
||||
@@ -155,7 +126,7 @@ public abstract class TinyProtocol {
|
||||
};
|
||||
|
||||
serverChannelHandler = new ChannelInboundHandlerAdapter() {
|
||||
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
Channel channel = (Channel) msg;
|
||||
@@ -176,8 +147,7 @@ public abstract class TinyProtocol {
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public final void onPlayerLogin(PlayerLoginEvent e) {
|
||||
if (closed)
|
||||
return;
|
||||
if (closed) return;
|
||||
|
||||
Channel channel = getChannel(e.getPlayer());
|
||||
|
||||
@@ -201,35 +171,18 @@ public abstract class TinyProtocol {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerChannelHandler() {
|
||||
Object mcServer = getMinecraftServer.get(Bukkit.getServer());
|
||||
Object serverConnection = getServerConnection.get(mcServer);
|
||||
boolean looking = true;
|
||||
|
||||
try {
|
||||
Field field = Reflection.getParameterizedField(serverConnectionClass, List.class, networkManagerClass);
|
||||
field.setAccessible(true);
|
||||
|
||||
networkManagers = (List<Object>) field.get(serverConnection);
|
||||
} catch (Exception ex) {
|
||||
plugin.getLogger().info("Encountered an exception checking list fields" + ex);
|
||||
MethodInvoker method = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass);
|
||||
|
||||
networkManagers = (List<Object>) method.invoke(null, serverConnection);
|
||||
}
|
||||
|
||||
if (networkManagers == null) {
|
||||
throw new IllegalArgumentException("Failed to obtain list of network managers");
|
||||
}
|
||||
ServerConnectionListener serverConnection = MinecraftServer.getServer().getConnection();
|
||||
networkManagers = serverConnection.getConnections();
|
||||
// We need to synchronize against this list
|
||||
createServerChannelHandler();
|
||||
|
||||
// Find the correct list, or implicitly throw an exception
|
||||
boolean looking = true;
|
||||
for (int i = 0; looking; i++) {
|
||||
List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection);
|
||||
|
||||
for (Object item : list) {
|
||||
if (!ChannelFuture.class.isInstance(item))
|
||||
break;
|
||||
if (!(item instanceof ChannelFuture)) break;
|
||||
|
||||
// Channel future that contains the server connection
|
||||
Channel serverChannel = ((ChannelFuture) item).channel();
|
||||
@@ -242,8 +195,7 @@ public abstract class TinyProtocol {
|
||||
}
|
||||
|
||||
private void unregisterChannelHandler() {
|
||||
if (serverChannelHandler == null)
|
||||
return;
|
||||
if (serverChannelHandler == null) return;
|
||||
|
||||
for (Channel serverChannel : serverChannels) {
|
||||
final ChannelPipeline pipeline = serverChannel.pipeline();
|
||||
@@ -270,98 +222,71 @@ public abstract class TinyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the server is starting to send a packet to a player.
|
||||
* <p>
|
||||
* Note that this is not executed on the main thread.
|
||||
*
|
||||
* @param receiver - the receiving player, NULL for early login/status packets.
|
||||
* @param channel - the channel that received the packet. Never NULL.
|
||||
* @param packet - the packet being sent.
|
||||
* @return The packet to send instead, or NULL to cancel the transmission.
|
||||
*/
|
||||
public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) {
|
||||
return packet;
|
||||
public <T> void addTypedFilter(Class<T> packetType, BiFunction<Player, ? super T, Object> filter) {
|
||||
packetFilters.computeIfAbsent(packetType, c -> new CopyOnWriteArrayList<>()).add((BiFunction) filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the server has received a packet from a given player.
|
||||
* <p>
|
||||
* Use {@link Channel#remoteAddress()} to get the remote address of the client.
|
||||
*
|
||||
* @param sender - the player that sent the packet, NULL for early login/status packets.
|
||||
* @param channel - channel that received the packet. Never NULL.
|
||||
* @param packet - the packet being received.
|
||||
* @return The packet to recieve instead, or NULL to cancel.
|
||||
*/
|
||||
public Object onPacketInAsync(Player sender, Channel channel, Object packet) {
|
||||
return packet;
|
||||
@Deprecated
|
||||
public void addFilter(Class<?> packetType, BiFunction<Player, Object, Object> filter) {
|
||||
packetFilters.computeIfAbsent(packetType, c -> new CopyOnWriteArrayList<>()).add(filter);
|
||||
}
|
||||
|
||||
public void removeFilter(Class<?> packetType, BiFunction<Player, ?, Object> filter) {
|
||||
packetFilters.getOrDefault(packetType, Collections.emptyList()).remove(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to a particular player.
|
||||
* <p>
|
||||
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
*
|
||||
* @param player - the destination player.
|
||||
* @param packet - the packet to send.
|
||||
*/
|
||||
public void sendPacket(Player player, Object packet) {
|
||||
public void sendPacket(Player player, Packet<?> packet) {
|
||||
sendPacket(getChannel(player), packet);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void sendPacket(Player player, Object object) {
|
||||
if (object instanceof Packet<?> packet) {
|
||||
sendPacket(getChannel(player), packet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to a particular client.
|
||||
* <p>
|
||||
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
*
|
||||
* @param channel - client identified by a channel.
|
||||
* @param packet - the packet to send.
|
||||
* @param packet - the packet to send.
|
||||
*/
|
||||
public void sendPacket(Channel channel, Object packet) {
|
||||
public void sendPacket(Channel channel, Packet<?> packet) {
|
||||
channel.pipeline().writeAndFlush(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretend that a given packet has been received from a player.
|
||||
* <p>
|
||||
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
*
|
||||
* @param player - the player that sent the packet.
|
||||
* @param packet - the packet that will be received by the server.
|
||||
*/
|
||||
public void receivePacket(Player player, Object packet) {
|
||||
public void receivePacket(Player player, Packet<?> packet) {
|
||||
receivePacket(getChannel(player), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretend that a given packet has been received from a given client.
|
||||
* <p>
|
||||
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
*
|
||||
* @param channel - client identified by a channel.
|
||||
* @param packet - the packet that will be received by the server.
|
||||
* @param packet - the packet that will be received by the server.
|
||||
*/
|
||||
public void receivePacket(Channel channel, Object packet) {
|
||||
public void receivePacket(Channel channel, Packet<?> packet) {
|
||||
channel.pipeline().context("encoder").fireChannelRead(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID.
|
||||
* <p>
|
||||
* Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances.
|
||||
*
|
||||
* @return A unique channel handler name.
|
||||
*/
|
||||
protected String getHandlerName() {
|
||||
return "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets.
|
||||
* <p>
|
||||
* This will automatically be called when a player has logged in.
|
||||
*
|
||||
*
|
||||
* @param player - the player to inject.
|
||||
*/
|
||||
public void injectPlayer(Player player) {
|
||||
@@ -370,7 +295,7 @@ public abstract class TinyProtocol {
|
||||
|
||||
/**
|
||||
* Add a custom channel handler to the given channel.
|
||||
*
|
||||
*
|
||||
* @param channel - the channel to inject.
|
||||
* @return The intercepted channel, or NULL if it has already been injected.
|
||||
*/
|
||||
@@ -380,31 +305,31 @@ public abstract class TinyProtocol {
|
||||
|
||||
/**
|
||||
* Add a custom channel handler to the given channel.
|
||||
*
|
||||
*
|
||||
* @param channel - the channel to inject.
|
||||
* @return The packet interceptor.
|
||||
*/
|
||||
private PacketInterceptor injectChannelInternal(Channel channel) {
|
||||
try {
|
||||
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
|
||||
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(HANDLER_NAME);
|
||||
|
||||
// Inject our packet interceptor
|
||||
if (interceptor == null) {
|
||||
interceptor = new PacketInterceptor();
|
||||
channel.pipeline().addBefore("packet_handler", handlerName, interceptor);
|
||||
channel.pipeline().addBefore("packet_handler", HANDLER_NAME, interceptor);
|
||||
uninjectedChannels.remove(channel);
|
||||
}
|
||||
|
||||
return interceptor;
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Try again
|
||||
return (PacketInterceptor) channel.pipeline().get(handlerName);
|
||||
return (PacketInterceptor) channel.pipeline().get(HANDLER_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Netty channel associated with a player. This is cached.
|
||||
*
|
||||
*
|
||||
* @param player - the player.
|
||||
* @return The Netty channel.
|
||||
*/
|
||||
@@ -413,10 +338,8 @@ public abstract class TinyProtocol {
|
||||
|
||||
// Lookup channel again
|
||||
if (channel == null) {
|
||||
Object connection = getConnection.get(getPlayerHandle.invoke(player));
|
||||
Object manager = getManager.get(connection);
|
||||
|
||||
channelLookup.put(player.getName(), channel = getChannel.get(manager));
|
||||
Channel playerChannel = ((CraftPlayer) player).getHandle().connection.connection.channel;
|
||||
channelLookup.put(player.getName(), channel = playerChannel);
|
||||
}
|
||||
|
||||
return channel;
|
||||
@@ -424,7 +347,7 @@ public abstract class TinyProtocol {
|
||||
|
||||
/**
|
||||
* Uninject a specific player.
|
||||
*
|
||||
*
|
||||
* @param player - the injected player.
|
||||
*/
|
||||
public void uninjectPlayer(Player player) {
|
||||
@@ -435,7 +358,7 @@ public abstract class TinyProtocol {
|
||||
* Uninject a specific channel.
|
||||
* <p>
|
||||
* This will also disable the automatic channel injection that occurs when a player has properly logged in.
|
||||
*
|
||||
*
|
||||
* @param channel - the injected channel.
|
||||
*/
|
||||
public void uninjectChannel(final Channel channel) {
|
||||
@@ -449,7 +372,7 @@ public abstract class TinyProtocol {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
channel.pipeline().remove(handlerName);
|
||||
channel.pipeline().remove(HANDLER_NAME);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -457,7 +380,7 @@ public abstract class TinyProtocol {
|
||||
|
||||
/**
|
||||
* Determine if the given player has been injected by TinyProtocol.
|
||||
*
|
||||
*
|
||||
* @param player - the player.
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
@@ -467,12 +390,12 @@ public abstract class TinyProtocol {
|
||||
|
||||
/**
|
||||
* Determine if the given channel has been injected by TinyProtocol.
|
||||
*
|
||||
*
|
||||
* @param channel - the channel.
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public boolean hasInjected(Channel channel) {
|
||||
return channel.pipeline().get(handlerName) != null;
|
||||
return channel.pipeline().get(HANDLER_NAME) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -495,7 +418,7 @@ public abstract class TinyProtocol {
|
||||
|
||||
/**
|
||||
* Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets.
|
||||
*
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
private final class PacketInterceptor extends ChannelDuplexHandler {
|
||||
@@ -509,7 +432,7 @@ public abstract class TinyProtocol {
|
||||
handleLoginStart(channel, msg);
|
||||
|
||||
try {
|
||||
msg = onPacketInAsync(player, channel, msg);
|
||||
msg = filterPacket(player, msg);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e);
|
||||
}
|
||||
@@ -522,7 +445,7 @@ public abstract class TinyProtocol {
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
try {
|
||||
msg = onPacketOutAsync(player, ctx.channel(), msg);
|
||||
msg = filterPacket(player, msg);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e);
|
||||
}
|
||||
@@ -533,10 +456,20 @@ public abstract class TinyProtocol {
|
||||
}
|
||||
|
||||
private void handleLoginStart(Channel channel, Object packet) {
|
||||
if (PACKET_LOGIN_IN_START.isInstance(packet)) {
|
||||
GameProfile profile = getGameProfile.get(packet);
|
||||
channelLookup.put(profile.getName(), channel);
|
||||
if (packet instanceof ServerboundHelloPacket(String name, UUID packetId)) {
|
||||
channelLookup.put(name, channel);
|
||||
}
|
||||
}
|
||||
|
||||
private Object filterPacket(Player player, Object packet) {
|
||||
List<BiFunction<Player, Object, Object>> filters = packetFilters.getOrDefault(packet.getClass(), Collections.emptyList());
|
||||
|
||||
for (BiFunction<Player, Object, Object> filter : filters) {
|
||||
packet = filter.apply(player, packet);
|
||||
if (packet == null) break;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,301 +35,281 @@ import java.util.Map;
|
||||
@UtilityClass
|
||||
public final class Reflection {
|
||||
|
||||
public static final int MAJOR_VERSION;
|
||||
public static final int MINOR_VERSION;
|
||||
static {
|
||||
String[] version = Bukkit.getServer().getBukkitVersion().split("-")[0].split("\\.");
|
||||
MAJOR_VERSION = Integer.parseInt(version[1]);
|
||||
MINOR_VERSION = version.length > 2 ? Integer.parseInt(version[2]) : 0;
|
||||
}
|
||||
public static final int MAJOR_VERSION;
|
||||
public static final int MINOR_VERSION;
|
||||
|
||||
private static final String ORG_BUKKIT_CRAFTBUKKIT = Bukkit.getServer().getClass().getPackage().getName();
|
||||
public static final String LEGACY_NET_MINECRAFT_SERVER = ORG_BUKKIT_CRAFTBUKKIT.replace("org.bukkit.craftbukkit", "net.minecraft.server");
|
||||
static {
|
||||
String[] version = Bukkit.getServer().getBukkitVersion().split("-")[0].split("\\.");
|
||||
MAJOR_VERSION = Integer.parseInt(version[1]);
|
||||
MINOR_VERSION = version.length > 2 ? Integer.parseInt(version[2]) : 0;
|
||||
}
|
||||
|
||||
private static final Map<String, String> spigotClassnames = new HashMap<>();
|
||||
static {
|
||||
// See https://mappings.dev for complete mappings
|
||||
spigotClassnames.put("net.minecraft.Util", "net.minecraft.SystemUtils");
|
||||
private static final String ORG_BUKKIT_CRAFTBUKKIT = Bukkit.getServer().getClass().getPackage().getName();
|
||||
public static final String LEGACY_NET_MINECRAFT_SERVER = ORG_BUKKIT_CRAFTBUKKIT.replace("org.bukkit.craftbukkit", "net.minecraft.server");
|
||||
|
||||
spigotClassnames.put("net.minecraft.core.BlockPos", "net.minecraft.core.BlockPosition");
|
||||
spigotClassnames.put("net.minecraft.core.DefaultedRegistry", "net.minecraft.core.RegistryBlocks");
|
||||
spigotClassnames.put("net.minecraft.core.IdMapper", "net.minecraft.core.RegistryBlockID");
|
||||
spigotClassnames.put("net.minecraft.core.Vec3i", "net.minecraft.core.BaseBlockPosition");
|
||||
private static final Map<String, String> spigotClassnames = new HashMap<>();
|
||||
|
||||
spigotClassnames.put("net.minecraft.nbt.CompoundTag", "net.minecraft.nbt.NBTTagCompound");
|
||||
static {
|
||||
// See https://mappings.dev for complete mappings
|
||||
spigotClassnames.put("net.minecraft.Util", "net.minecraft.SystemUtils");
|
||||
|
||||
spigotClassnames.put("net.minecraft.network.Connection", "net.minecraft.network.NetworkManager");
|
||||
spigotClassnames.put("net.minecraft.core.BlockPos", "net.minecraft.core.BlockPosition");
|
||||
spigotClassnames.put("net.minecraft.core.DefaultedRegistry", "net.minecraft.core.RegistryBlocks");
|
||||
spigotClassnames.put("net.minecraft.core.IdMapper", "net.minecraft.core.RegistryBlockID");
|
||||
spigotClassnames.put("net.minecraft.core.Vec3i", "net.minecraft.core.BaseBlockPosition");
|
||||
|
||||
spigotClassnames.put("net.minecraft.network.chat.Component", "net.minecraft.network.chat.IChatBaseComponent");
|
||||
spigotClassnames.put("net.minecraft.nbt.CompoundTag", "net.minecraft.nbt.NBTTagCompound");
|
||||
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundAddEntityPacket", "net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundAddPlayerPacket", "net.minecraft.network.protocol.game.PacketPlayOutNamedEntitySpawn");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundAnimatePacket", "net.minecraft.network.protocol.game.PacketPlayOutAnimation");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket", "net.minecraft.network.protocol.game.PacketPlayOutBlockBreak");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket", "net.minecraft.network.protocol.game.PacketPlayOutTileEntityData");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundBlockEventPacket", "net.minecraft.network.protocol.game.PacketPlayOutBlockAction");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket", "net.minecraft.network.protocol.game.PacketPlayOutBlockChange");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundContainerClosePacket", "net.minecraft.network.protocol.game.PacketPlayOutCloseWindow");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundEntityEventPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityStatus");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundExplodePacket", "net.minecraft.network.protocol.game.PacketPlayOutExplosion");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundGameEventPacket", "net.minecraft.network.protocol.game.PacketPlayOutGameStateChange");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo", "net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$a");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundLevelEventPacket", "net.minecraft.network.protocol.game.PacketPlayOutWorldEvent");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket", "net.minecraft.network.protocol.game.PacketPlayOutWorldParticles");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntity");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Pos", "net.minecraft.network.protocol.game.PacketPlayOutEntity$PacketPlayOutRelEntityMove");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$PosRot", "net.minecraft.network.protocol.game.PacketPlayOutEntity$PacketPlayOutRelEntityMoveLook");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Rot", "net.minecraft.network.protocol.game.PacketPlayOutEntity$PacketPlayOutEntityLook");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundOpenSignEditorPacket", "net.minecraft.network.protocol.game.PacketPlayOutOpenSignEditor");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundRotateHeadPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityHeadRotation");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket", "net.minecraft.network.protocol.game.PacketPlayOutMultiBlockChange");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityVelocity");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityEquipment");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSetObjectivePacket", "net.minecraft.network.protocol.game.PacketPlayOutScoreboardObjective");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSetScorePacket", "net.minecraft.network.protocol.game.PacketPlayOutScoreboardScore");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSoundPacket", "net.minecraft.network.protocol.game.PacketPlayOutNamedSoundEffect");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityTeleport");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundContainerClickPacket", "net.minecraft.network.protocol.game.PacketPlayInWindowClick");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundInteractPacket", "net.minecraft.network.protocol.game.PacketPlayInUseEntity");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundInteractPacket$Action", "net.minecraft.network.protocol.game.PacketPlayInUseEntity$EnumEntityUseAction");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundInteractPacket$ActionType", "net.minecraft.network.protocol.game.PacketPlayInUseEntity$b");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos", "net.minecraft.network.protocol.game.PacketPlayInFlying$PacketPlayInPosition");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot", "net.minecraft.network.protocol.game.PacketPlayInFlying$PacketPlayInPositionLook");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Rot", "net.minecraft.network.protocol.game.PacketPlayInFlying$PacketPlayInLook");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundPlayerActionPacket", "net.minecraft.network.protocol.game.PacketPlayInBlockDig");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket", "net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundSignUpdatePacket", "net.minecraft.network.protocol.game.PacketPlayInUpdateSign");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundUseItemPacket", "net.minecraft.network.protocol.game.PacketPlayInBlockPlace");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundUseItemOnPacket", "net.minecraft.network.protocol.game.PacketPlayInUseItem");
|
||||
spigotClassnames.put("net.minecraft.network.Connection", "net.minecraft.network.NetworkManager");
|
||||
|
||||
spigotClassnames.put("net.minecraft.network.syncher.EntityDataAccessor", "net.minecraft.network.syncher.DataWatcherObject");
|
||||
spigotClassnames.put("net.minecraft.network.syncher.EntityDataSerializer", "net.minecraft.network.syncher.DataWatcherSerializer");
|
||||
spigotClassnames.put("net.minecraft.network.syncher.EntityDataSerializers", "net.minecraft.network.syncher.DataWatcherRegistry");
|
||||
spigotClassnames.put("net.minecraft.network.syncher.SynchedEntityData$DataItem", "net.minecraft.network.syncher.DataWatcher$Item");
|
||||
spigotClassnames.put("net.minecraft.network.chat.Component", "net.minecraft.network.chat.IChatBaseComponent");
|
||||
|
||||
spigotClassnames.put("net.minecraft.server.ServerScoreboard$Method", "net.minecraft.server.ScoreboardServer$Action");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundAddEntityPacket", "net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundAddPlayerPacket", "net.minecraft.network.protocol.game.PacketPlayOutNamedEntitySpawn");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundAnimatePacket", "net.minecraft.network.protocol.game.PacketPlayOutAnimation");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket", "net.minecraft.network.protocol.game.PacketPlayOutBlockBreak");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket", "net.minecraft.network.protocol.game.PacketPlayOutTileEntityData");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundBlockEventPacket", "net.minecraft.network.protocol.game.PacketPlayOutBlockAction");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket", "net.minecraft.network.protocol.game.PacketPlayOutBlockChange");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundContainerClosePacket", "net.minecraft.network.protocol.game.PacketPlayOutCloseWindow");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundEntityEventPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityStatus");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundExplodePacket", "net.minecraft.network.protocol.game.PacketPlayOutExplosion");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundGameEventPacket", "net.minecraft.network.protocol.game.PacketPlayOutGameStateChange");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo", "net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$a");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundLevelEventPacket", "net.minecraft.network.protocol.game.PacketPlayOutWorldEvent");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket", "net.minecraft.network.protocol.game.PacketPlayOutWorldParticles");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntity");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Pos", "net.minecraft.network.protocol.game.PacketPlayOutEntity$PacketPlayOutRelEntityMove");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$PosRot", "net.minecraft.network.protocol.game.PacketPlayOutEntity$PacketPlayOutRelEntityMoveLook");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Rot", "net.minecraft.network.protocol.game.PacketPlayOutEntity$PacketPlayOutEntityLook");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundOpenSignEditorPacket", "net.minecraft.network.protocol.game.PacketPlayOutOpenSignEditor");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundRotateHeadPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityHeadRotation");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket", "net.minecraft.network.protocol.game.PacketPlayOutMultiBlockChange");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityVelocity");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityEquipment");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSetObjectivePacket", "net.minecraft.network.protocol.game.PacketPlayOutScoreboardObjective");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSetScorePacket", "net.minecraft.network.protocol.game.PacketPlayOutScoreboardScore");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundSoundPacket", "net.minecraft.network.protocol.game.PacketPlayOutNamedSoundEffect");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket", "net.minecraft.network.protocol.game.PacketPlayOutEntityTeleport");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundContainerClickPacket", "net.minecraft.network.protocol.game.PacketPlayInWindowClick");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundInteractPacket", "net.minecraft.network.protocol.game.PacketPlayInUseEntity");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundInteractPacket$Action", "net.minecraft.network.protocol.game.PacketPlayInUseEntity$EnumEntityUseAction");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundInteractPacket$ActionType", "net.minecraft.network.protocol.game.PacketPlayInUseEntity$b");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos", "net.minecraft.network.protocol.game.PacketPlayInFlying$PacketPlayInPosition");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot", "net.minecraft.network.protocol.game.PacketPlayInFlying$PacketPlayInPositionLook");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Rot", "net.minecraft.network.protocol.game.PacketPlayInFlying$PacketPlayInLook");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundPlayerActionPacket", "net.minecraft.network.protocol.game.PacketPlayInBlockDig");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket", "net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundSignUpdatePacket", "net.minecraft.network.protocol.game.PacketPlayInUpdateSign");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundUseItemPacket", "net.minecraft.network.protocol.game.PacketPlayInBlockPlace");
|
||||
spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundUseItemOnPacket", "net.minecraft.network.protocol.game.PacketPlayInUseItem");
|
||||
|
||||
spigotClassnames.put("net.minecraft.server.level.ChunkMap", "net.minecraft.server.level.PlayerChunkMap");
|
||||
spigotClassnames.put("net.minecraft.server.level.ChunkMap$TrackedEntity", "net.minecraft.server.level.PlayerChunkMap$EntityTracker");
|
||||
spigotClassnames.put("net.minecraft.server.level.ServerChunkCache", "net.minecraft.server.level.ChunkProviderServer");
|
||||
spigotClassnames.put("net.minecraft.server.level.ServerLevel", "net.minecraft.server.level.WorldServer");
|
||||
spigotClassnames.put("net.minecraft.server.level.ServerPlayer", "net.minecraft.server.level.EntityPlayer");
|
||||
spigotClassnames.put("net.minecraft.network.syncher.EntityDataAccessor", "net.minecraft.network.syncher.DataWatcherObject");
|
||||
spigotClassnames.put("net.minecraft.network.syncher.EntityDataSerializer", "net.minecraft.network.syncher.DataWatcherSerializer");
|
||||
spigotClassnames.put("net.minecraft.network.syncher.EntityDataSerializers", "net.minecraft.network.syncher.DataWatcherRegistry");
|
||||
spigotClassnames.put("net.minecraft.network.syncher.SynchedEntityData$DataItem", "net.minecraft.network.syncher.DataWatcher$Item");
|
||||
|
||||
spigotClassnames.put("net.minecraft.server.network.ServerConnectionListener", "net.minecraft.server.network.ServerConnection");
|
||||
spigotClassnames.put("net.minecraft.server.ServerScoreboard$Method", "net.minecraft.server.ScoreboardServer$Action");
|
||||
|
||||
spigotClassnames.put("net.minecraft.world.InteractionHand", "net.minecraft.world.EnumHand");
|
||||
spigotClassnames.put("net.minecraft.server.level.ChunkMap", "net.minecraft.server.level.PlayerChunkMap");
|
||||
spigotClassnames.put("net.minecraft.server.level.ChunkMap$TrackedEntity", "net.minecraft.server.level.PlayerChunkMap$EntityTracker");
|
||||
spigotClassnames.put("net.minecraft.server.level.ServerChunkCache", "net.minecraft.server.level.ChunkProviderServer");
|
||||
spigotClassnames.put("net.minecraft.server.level.ServerLevel", "net.minecraft.server.level.WorldServer");
|
||||
spigotClassnames.put("net.minecraft.server.level.ServerPlayer", "net.minecraft.server.level.EntityPlayer");
|
||||
|
||||
spigotClassnames.put("net.minecraft.world.entity.EntityType", "net.minecraft.world.entity.EntityTypes");
|
||||
spigotClassnames.put("net.minecraft.world.entity.Pose", "net.minecraft.world.entity.EntityPose");
|
||||
spigotClassnames.put("net.minecraft.server.network.ServerConnectionListener", "net.minecraft.server.network.ServerConnection");
|
||||
|
||||
spigotClassnames.put("net.minecraft.world.entity.item.PrimedTnt", "net.minecraft.world.entity.item.EntityTNTPrimed");
|
||||
spigotClassnames.put("net.minecraft.world.InteractionHand", "net.minecraft.world.EnumHand");
|
||||
|
||||
spigotClassnames.put("net.minecraft.world.entity.projectile.AbstractArrow", "net.minecraft.world.entity.projectile.EntityArrow");
|
||||
spigotClassnames.put("net.minecraft.world.entity.EntityType", "net.minecraft.world.entity.EntityTypes");
|
||||
spigotClassnames.put("net.minecraft.world.entity.Pose", "net.minecraft.world.entity.EntityPose");
|
||||
|
||||
spigotClassnames.put("net.minecraft.world.level.GameType", "net.minecraft.world.level.EnumGamemode");
|
||||
spigotClassnames.put("net.minecraft.world.level.LevelAccessor", "net.minecraft.world.level.GeneratorAccess");
|
||||
spigotClassnames.put("net.minecraft.world.entity.item.PrimedTnt", "net.minecraft.world.entity.item.EntityTNTPrimed");
|
||||
|
||||
spigotClassnames.put("net.minecraft.world.level.block.state.BlockState", "net.minecraft.world.level.block.state.IBlockData");
|
||||
spigotClassnames.put("net.minecraft.world.level.block.state.StateDefinition", "net.minecraft.world.level.block.state.BlockStateList");
|
||||
spigotClassnames.put("net.minecraft.world.entity.projectile.AbstractArrow", "net.minecraft.world.entity.projectile.EntityArrow");
|
||||
|
||||
spigotClassnames.put("net.minecraft.world.level.chunk.LevelChunk", "net.minecraft.world.level.chunk.Chunk");
|
||||
spigotClassnames.put("net.minecraft.world.level.GameType", "net.minecraft.world.level.EnumGamemode");
|
||||
spigotClassnames.put("net.minecraft.world.level.LevelAccessor", "net.minecraft.world.level.GeneratorAccess");
|
||||
|
||||
spigotClassnames.put("net.minecraft.world.level.material.FlowingFluid", "net.minecraft.world.level.material.FluidTypeFlowing");
|
||||
spigotClassnames.put("net.minecraft.world.level.material.Fluids", "net.minecraft.world.level.material.FluidTypes");
|
||||
spigotClassnames.put("net.minecraft.world.level.material.FluidState", "net.minecraft.world.level.material.Fluid");
|
||||
spigotClassnames.put("net.minecraft.world.level.block.state.BlockState", "net.minecraft.world.level.block.state.IBlockData");
|
||||
spigotClassnames.put("net.minecraft.world.level.block.state.StateDefinition", "net.minecraft.world.level.block.state.BlockStateList");
|
||||
|
||||
spigotClassnames.put("net.minecraft.world.phys.BlockHitResult", "net.minecraft.world.phys.MovingObjectPositionBlock");
|
||||
spigotClassnames.put("net.minecraft.world.phys.Vec3", "net.minecraft.world.phys.Vec3D");
|
||||
spigotClassnames.put("net.minecraft.world.level.chunk.LevelChunk", "net.minecraft.world.level.chunk.Chunk");
|
||||
|
||||
spigotClassnames.put("net.minecraft.resources.ResourceLocation", "net.minecraft.resources.MinecraftKey");
|
||||
spigotClassnames.put("net.minecraft.world.level.material.FlowingFluid", "net.minecraft.world.level.material.FluidTypeFlowing");
|
||||
spigotClassnames.put("net.minecraft.world.level.material.Fluids", "net.minecraft.world.level.material.FluidTypes");
|
||||
spigotClassnames.put("net.minecraft.world.level.material.FluidState", "net.minecraft.world.level.material.Fluid");
|
||||
|
||||
spigotClassnames.put("net.minecraft.util.ProgressListener", "net.minecraft.util.IProgressUpdate");
|
||||
}
|
||||
spigotClassnames.put("net.minecraft.world.phys.BlockHitResult", "net.minecraft.world.phys.MovingObjectPositionBlock");
|
||||
spigotClassnames.put("net.minecraft.world.phys.Vec3", "net.minecraft.world.phys.Vec3D");
|
||||
|
||||
public static Class<?> getClass(String name) {
|
||||
try {
|
||||
if(name.startsWith("org.bukkit.craftbukkit")) {
|
||||
return Class.forName(ORG_BUKKIT_CRAFTBUKKIT + name.substring(22));
|
||||
} else if(MAJOR_VERSION < 17 && name.startsWith("net.minecraft")) {
|
||||
return Class.forName(LEGACY_NET_MINECRAFT_SERVER + "." + spigotClassnames.getOrDefault(name, name).split("[.](?=[^.]*$)")[1]);
|
||||
} else if(MAJOR_VERSION < 21 || MINOR_VERSION < 4) {
|
||||
return Class.forName(spigotClassnames.getOrDefault(name, name));
|
||||
} else {
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = Class.forName(name);
|
||||
} catch (ClassNotFoundException e) {}
|
||||
if (clazz != null && clazz.getName().equals(name)) {
|
||||
return clazz;
|
||||
}
|
||||
spigotClassnames.put("net.minecraft.resources.ResourceLocation", "net.minecraft.resources.MinecraftKey");
|
||||
|
||||
try {
|
||||
return Core.class.getClassLoader().getParent().loadClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
if (clazz == null) {
|
||||
throw e;
|
||||
}
|
||||
spigotClassnames.put("net.minecraft.util.ProgressListener", "net.minecraft.util.IProgressUpdate");
|
||||
}
|
||||
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalArgumentException("Cannot find " + name, e);
|
||||
}
|
||||
}
|
||||
public static Class<?> getClass(String name) {
|
||||
try {
|
||||
if (name.startsWith("org.bukkit.craftbukkit")) {
|
||||
return Class.forName(ORG_BUKKIT_CRAFTBUKKIT + name.substring(22));
|
||||
} else if (MAJOR_VERSION < 17 && name.startsWith("net.minecraft")) {
|
||||
return Class.forName(LEGACY_NET_MINECRAFT_SERVER + "." + spigotClassnames.getOrDefault(name, name).split("[.](?=[^.]*$)")[1]);
|
||||
} else if (MAJOR_VERSION < 21 || MINOR_VERSION < 4) {
|
||||
return Class.forName(spigotClassnames.getOrDefault(name, name));
|
||||
} else {
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = Class.forName(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
}
|
||||
if (clazz != null && clazz.getName().equals(name)) {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
public static class Field<T> {
|
||||
private final java.lang.reflect.Field f;
|
||||
try {
|
||||
return Core.class.getClassLoader().getParent().loadClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
if (clazz == null) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T get(Object target) {
|
||||
try {
|
||||
return (T) f.get(target);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalArgumentException("Cannot read field", e);
|
||||
}
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalArgumentException("Cannot find " + name, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void set(Object target, Object value) {
|
||||
try {
|
||||
f.set(target, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalArgumentException("Cannot write field", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@AllArgsConstructor
|
||||
public static class Field<T> {
|
||||
private final java.lang.reflect.Field f;
|
||||
|
||||
public static <T> Field<T> getField(Class<?> target, String name, Class<T> fieldType) {
|
||||
return getField(target, name, fieldType, 0);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public T get(Object target) {
|
||||
try {
|
||||
return (T) f.get(target);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalArgumentException("Cannot read field", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Field<T> getField(String className, String name, Class<T> fieldType) {
|
||||
return getField(getClass(className), name, fieldType, 0);
|
||||
}
|
||||
public void set(Object target, Object value) {
|
||||
try {
|
||||
f.set(target, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalArgumentException("Cannot write field", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Field<T> getField(Class<?> target, Class<T> fieldType, int index) {
|
||||
return getField(target, null, fieldType, index);
|
||||
}
|
||||
public static <T> Field<T> getField(Class<?> target, String name, Class<T> fieldType) {
|
||||
return getField(target, name, fieldType, 0);
|
||||
}
|
||||
|
||||
public static <T> Field<T> getField(String className, Class<T> fieldType, int index) {
|
||||
return getField(getClass(className), fieldType, index);
|
||||
}
|
||||
public static <T> Field<T> getField(Class<?> target, Class<T> fieldType, int index) {
|
||||
return getField(target, null, fieldType, index);
|
||||
}
|
||||
|
||||
public static <T> Field<T> getField(Class<?> target, Class<T> fieldType, int index, Class<?>... parameters) {
|
||||
return getField(target, null, fieldType, index, parameters);
|
||||
}
|
||||
public static <T> Field<T> getField(Class<?> target, Class<T> fieldType, int index, Class<?>... parameters) {
|
||||
return getField(target, null, fieldType, index, parameters);
|
||||
}
|
||||
|
||||
private static <T> Field<T> getField(Class<?> target, String name, Class<T> fieldType, int index, Class<?>... parameters) {
|
||||
for (final java.lang.reflect.Field field : target.getDeclaredFields()) {
|
||||
if(matching(field, name, fieldType, parameters) && index-- <= 0) {
|
||||
field.setAccessible(true);
|
||||
return new Field<>(field);
|
||||
}
|
||||
}
|
||||
private static <T> Field<T> getField(Class<?> target, String name, Class<T> fieldType, int index, Class<?>... parameters) {
|
||||
for (final java.lang.reflect.Field field : target.getDeclaredFields()) {
|
||||
if (matching(field, name, fieldType, parameters) && index-- <= 0) {
|
||||
field.setAccessible(true);
|
||||
return new Field<>(field);
|
||||
}
|
||||
}
|
||||
|
||||
// Search in parent classes
|
||||
if (target.getSuperclass() != null)
|
||||
return getField(target.getSuperclass(), name, fieldType, index);
|
||||
// Search in parent classes
|
||||
if (target.getSuperclass() != null) {
|
||||
return getField(target.getSuperclass(), name, fieldType, index);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Cannot find field with type " + fieldType);
|
||||
}
|
||||
throw new IllegalArgumentException("Cannot find field with type " + fieldType);
|
||||
}
|
||||
|
||||
private static <T> boolean matching(java.lang.reflect.Field field, String name, Class<T> fieldType, Class<?>... parameters) {
|
||||
if(name != null && !field.getName().equals(name))
|
||||
return false;
|
||||
private static <T> boolean matching(java.lang.reflect.Field field, String name, Class<T> fieldType, Class<?>... parameters) {
|
||||
if (name != null && !field.getName().equals(name)) return false;
|
||||
|
||||
if(!fieldType.isAssignableFrom(field.getType()))
|
||||
return false;
|
||||
if (!fieldType.isAssignableFrom(field.getType())) return false;
|
||||
|
||||
if(parameters.length > 0) {
|
||||
Type[] arguments = ((ParameterizedType)field.getGenericType()).getActualTypeArguments();
|
||||
if (parameters.length > 0) {
|
||||
Type[] arguments = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
|
||||
|
||||
for(int i = 0; i < parameters.length; i++) {
|
||||
if(arguments[i] instanceof ParameterizedType ? ((ParameterizedType) arguments[i]).getRawType() != parameters[i] : arguments[i] != parameters[i])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
if (arguments[i] instanceof ParameterizedType ? ((ParameterizedType) arguments[i]).getRawType() != parameters[i] : arguments[i] != parameters[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
public static class Method {
|
||||
private final java.lang.reflect.Method m;
|
||||
@AllArgsConstructor
|
||||
public static class Method {
|
||||
private final java.lang.reflect.Method m;
|
||||
|
||||
public Object invoke(Object target, Object... arguments) {
|
||||
try {
|
||||
return m.invoke(target, arguments);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Cannot invoke method " + m, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
public Object invoke(Object target, Object... arguments) {
|
||||
try {
|
||||
return m.invoke(target, arguments);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Cannot invoke method " + m, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Method getMethod(String className, String methodName, Class<?>... params) {
|
||||
return getTypedMethod(getClass(className), methodName, null, params);
|
||||
}
|
||||
public static Method getTypedMethod(Class<?> clazz, String methodName, Class<?> returnType, Class<?>... params) {
|
||||
for (final java.lang.reflect.Method method : clazz.getDeclaredMethods()) {
|
||||
if ((methodName == null || method.getName().equals(methodName))
|
||||
&& (returnType == null || method.getReturnType().equals(returnType))
|
||||
&& Arrays.equals(method.getParameterTypes(), params)) {
|
||||
method.setAccessible(true);
|
||||
return new Method(method);
|
||||
}
|
||||
}
|
||||
|
||||
public static Method getMethod(Class<?> clazz, String methodName, Class<?>... params) {
|
||||
return getTypedMethod(clazz, methodName, null, params);
|
||||
}
|
||||
// Search in every superclass
|
||||
if (clazz.getSuperclass() != null) {
|
||||
return getTypedMethod(clazz.getSuperclass(), methodName, returnType, params);
|
||||
}
|
||||
|
||||
public static Method getTypedMethod(Class<?> clazz, String methodName, Class<?> returnType, Class<?>... params) {
|
||||
for (final java.lang.reflect.Method method : clazz.getDeclaredMethods()) {
|
||||
if ((methodName == null || method.getName().equals(methodName))
|
||||
&& (returnType == null || method.getReturnType().equals(returnType))
|
||||
&& Arrays.equals(method.getParameterTypes(), params)) {
|
||||
method.setAccessible(true);
|
||||
return new Method(method);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(String.format("Cannot find method %s (%s).", methodName, Arrays.asList(params)));
|
||||
}
|
||||
|
||||
// Search in every superclass
|
||||
if (clazz.getSuperclass() != null)
|
||||
return getTypedMethod(clazz.getSuperclass(), methodName, returnType, params);
|
||||
@AllArgsConstructor
|
||||
public static class Constructor {
|
||||
private final java.lang.reflect.Constructor<?> c;
|
||||
|
||||
throw new IllegalArgumentException(String.format("Cannot find method %s (%s).", methodName, Arrays.asList(params)));
|
||||
}
|
||||
public Object invoke(Object... arguments) {
|
||||
try {
|
||||
return c.newInstance(arguments);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Cannot invoke constructor " + c, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
public static class Constructor {
|
||||
private final java.lang.reflect.Constructor<?> c;
|
||||
public static Constructor getConstructor(Class<?> clazz, Class<?>... params) {
|
||||
for (final java.lang.reflect.Constructor<?> constructor : clazz.getDeclaredConstructors()) {
|
||||
if (Arrays.equals(constructor.getParameterTypes(), params)) {
|
||||
constructor.setAccessible(true);
|
||||
return new Constructor(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
public Object invoke(Object... arguments) {
|
||||
try {
|
||||
return c.newInstance(arguments);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Cannot invoke constructor " + c, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException(String.format("Unable to find constructor for %s (%s).", clazz, Arrays.asList(params)));
|
||||
}
|
||||
|
||||
public static Constructor getConstructor(String className, Class<?>... params) {
|
||||
return getConstructor(getClass(className), params);
|
||||
}
|
||||
|
||||
public static Constructor getConstructor(Class<?> clazz, Class<?>... params) {
|
||||
for (final java.lang.reflect.Constructor<?> constructor : clazz.getDeclaredConstructors()) {
|
||||
if (Arrays.equals(constructor.getParameterTypes(), params)) {
|
||||
constructor.setAccessible(true);
|
||||
return new Constructor(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("Unable to find constructor for %s (%s).", clazz, Arrays.asList(params)));
|
||||
}
|
||||
|
||||
public static Object newInstance(Class<?> clazz) {
|
||||
try {
|
||||
if (Core.getVersion() > 15) {
|
||||
return Unsafe.getUnsafe().allocateInstance(clazz);
|
||||
} else {
|
||||
return clazz.newInstance();
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new SecurityException("Could not create object", e);
|
||||
}
|
||||
}
|
||||
public static Object newInstance(Class<?> clazz) {
|
||||
try {
|
||||
return Unsafe.getUnsafe().allocateInstance(clazz);
|
||||
} catch (InstantiationException e) {
|
||||
throw new SecurityException("Could not create object", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,8 @@ public class SWCommand extends AbstractSWCommand<CommandSender> {
|
||||
}
|
||||
if (args.length == 0 || atomicInteger.get() == commandList.size()) {
|
||||
commandList.forEach(subCommand -> {
|
||||
if (subCommand.validator == null || subCommand.validator.validate(p, p, (s, args1) -> {})) {
|
||||
if (subCommand.validator == null || subCommand.validator.validate(p, p, (s, args1) -> {
|
||||
})) {
|
||||
send(p, subCommand);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,8 +21,6 @@ package de.steamwar.command;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TypeMapper<T> extends AbstractTypeMapper<CommandSender, T> {
|
||||
/**
|
||||
* The CommandSender can be null!
|
||||
|
||||
@@ -19,28 +19,78 @@
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializer;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.world.entity.PositionMoveRotation;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BountifulWrapper {
|
||||
private BountifulWrapper() {}
|
||||
public static final BountifulWrapper impl = new BountifulWrapper();
|
||||
|
||||
public static final IBountifulWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
public void playPling(Player player) {
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1);
|
||||
}
|
||||
|
||||
public interface IBountifulWrapper {
|
||||
void playPling(Player player);
|
||||
public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) {
|
||||
if (type == ChatMessageType.CHAT) type = ChatMessageType.SYSTEM;
|
||||
player.spigot().sendMessage(type, msg);
|
||||
}
|
||||
|
||||
void sendMessage(Player player, ChatMessageType type, BaseComponent... msg);
|
||||
private static final Class<?> dataWatcherRegistry = EntityDataSerializers.class;
|
||||
private static final Class<?> dataWatcherSerializer = EntityDataSerializer.class;
|
||||
|
||||
Object getDataWatcherObject(int index, Class<?> type);
|
||||
Object getDataWatcherItem(Object dataWatcherObject, Object value);
|
||||
public Object getDataWatcherObject(int index, Class<?> type) {
|
||||
return new EntityDataAccessor<>(index, (EntityDataSerializer<Object>) Reflection.getField(dataWatcherRegistry, dataWatcherSerializer, 0, type).get(null));
|
||||
}
|
||||
|
||||
PositionSetter getPositionSetter(Class<?> packetClass, int fieldOffset);
|
||||
PositionSetter getRelMoveSetter(Class<?> packetClass);
|
||||
UUIDSetter getUUIDSetter(Class<?> packetClass);
|
||||
public Object getDataWatcherItem(Object dwo, Object value) {
|
||||
return new SynchedEntityData.DataItem<>((EntityDataAccessor<Object>) dwo, value);
|
||||
}
|
||||
|
||||
public BountifulWrapper.PositionSetter getPositionSetter(Class<?> packetClass, int fieldOffset) {
|
||||
try {
|
||||
Reflection.Field<PositionMoveRotation> field = Reflection.getField(packetClass, PositionMoveRotation.class, 0);
|
||||
|
||||
return (packet, x, y, z, pitch, yaw) -> {
|
||||
field.set(packet, new PositionMoveRotation(new Vec3(x, y, z), field.get(packet).deltaMovement(), yaw, pitch));
|
||||
};
|
||||
} catch (IllegalArgumentException e) {
|
||||
Reflection.Field<Double> posX = Reflection.getField(packetClass, double.class, fieldOffset);
|
||||
Reflection.Field<Double> posY = Reflection.getField(packetClass, double.class, fieldOffset + 1);
|
||||
Reflection.Field<Double> posZ = Reflection.getField(packetClass, double.class, fieldOffset + 2);
|
||||
boolean isByteClass = packetClass.getSimpleName().contains("PacketPlayOutEntityTeleport") || packetClass.getSimpleName().contains("PacketPlayOutNamedEntitySpawn");
|
||||
Class<?> pitchYawType = isByteClass ? byte.class : int.class;
|
||||
Reflection.Field<?> lookYaw = Reflection.getField(packetClass, pitchYawType, isByteClass ? 0 : 1);
|
||||
Reflection.Field<?> lookPitch = Reflection.getField(packetClass, pitchYawType, isByteClass ? 1 : 2);
|
||||
|
||||
return (packet, x, y, z, pitch, yaw) -> {
|
||||
posX.set(packet, x);
|
||||
posY.set(packet, y);
|
||||
posZ.set(packet, z);
|
||||
if (isByteClass) {
|
||||
lookYaw.set(packet, (byte) (yaw * 256 / 360));
|
||||
lookPitch.set(packet, (byte) (pitch * 256 / 360));
|
||||
} else {
|
||||
lookYaw.set(packet, (int) (yaw * 256 / 360));
|
||||
lookPitch.set(packet, (int) (pitch * 256 / 360));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public BountifulWrapper.UUIDSetter getUUIDSetter(Class<?> packetClass) {
|
||||
Reflection.Field<UUID> uuidField = Reflection.getField(packetClass, UUID.class, 0);
|
||||
|
||||
return uuidField::set;
|
||||
}
|
||||
|
||||
public interface PositionSetter {
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
public interface ChatWrapper {
|
||||
ChatWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
|
||||
|
||||
Object stringToChatComponent(String text);
|
||||
|
||||
Object getDataWatcherPacket(int entityId, Object... dataWatcherKeyValues);
|
||||
}
|
||||
@@ -20,7 +20,8 @@
|
||||
package de.steamwar.core;
|
||||
|
||||
public class CheckpointUtils {
|
||||
private CheckpointUtils() {}
|
||||
private CheckpointUtils() {
|
||||
}
|
||||
|
||||
public static void signalHandler() {
|
||||
try {
|
||||
|
||||
@@ -23,7 +23,10 @@ import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerConnectionListener;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.eclipse.openj9.criu.CRIUSupport;
|
||||
import org.eclipse.openj9.criu.JVMCRIUException;
|
||||
import sun.misc.Signal;
|
||||
@@ -41,7 +44,8 @@ import java.util.logging.Level;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class CheckpointUtilsJ9 {
|
||||
private CheckpointUtilsJ9() {}
|
||||
private CheckpointUtilsJ9() {
|
||||
}
|
||||
|
||||
static void signalHandler() {
|
||||
Signal.handle(new Signal("USR1"), signal -> Bukkit.getScheduler().runTask(Core.getInstance(), CheckpointUtils::freeze));
|
||||
@@ -49,15 +53,15 @@ class CheckpointUtilsJ9 {
|
||||
|
||||
static void freeze() {
|
||||
String checkpointFile = System.getProperty("checkpoint");
|
||||
if(!CRIUSupport.isCheckpointAllowed() || checkpointFile == null) {
|
||||
if (!CRIUSupport.isCheckpointAllowed() || checkpointFile == null) {
|
||||
Bukkit.shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach(player -> player.kickPlayer(null));
|
||||
|
||||
List<?> networkManagers = TinyProtocol.networkManagers.get(TinyProtocol.getServerConnection(Core.getInstance()));
|
||||
if(!Bukkit.getOnlinePlayers().isEmpty() || !networkManagers.isEmpty()) {
|
||||
List<?> networkManagers = TinyProtocol.instance.networkManagers;
|
||||
if (!Bukkit.getOnlinePlayers().isEmpty() || !networkManagers.isEmpty()) {
|
||||
Core.getInstance().getLogger().log(Level.INFO, "Waiting for players to disconnect for checkpointing");
|
||||
Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1);
|
||||
return;
|
||||
@@ -69,7 +73,7 @@ class CheckpointUtilsJ9 {
|
||||
freezeInternal(path);
|
||||
} catch (Exception e) {
|
||||
String message = e.getMessage() != null ? e.getMessage() : "";
|
||||
if(message.contains("Connected TCP socket")) {
|
||||
if (message.contains("Connected TCP socket")) {
|
||||
Core.getInstance().getLogger().log(Level.INFO, "Connected TCP socket, waiting for checkpointing");
|
||||
Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1);
|
||||
return;
|
||||
@@ -77,7 +81,7 @@ class CheckpointUtilsJ9 {
|
||||
|
||||
Bukkit.shutdown();
|
||||
|
||||
if(!message.contains("Can't dump ghost file") && !message.contains("Can't create link remap")) // File/Jar has been updated
|
||||
if (!message.contains("Can't dump ghost file") && !message.contains("Can't create link remap")) // File/Jar has been updated
|
||||
throw new SecurityException(e);
|
||||
} finally {
|
||||
// Delete checkpoint
|
||||
@@ -90,18 +94,20 @@ class CheckpointUtilsJ9 {
|
||||
}
|
||||
|
||||
|
||||
private static final Reflection.Field<List> channelFutures = Reflection.getField(TinyProtocol.serverConnection, List.class, 0, ChannelFuture.class);
|
||||
private static final Reflection.Method bind = Reflection.getMethod(TinyProtocol.serverConnection, null, InetAddress.class, int.class);
|
||||
private static final Reflection.Field<List> channelFutures = Reflection.getField(ServerConnectionListener.class, List.class, 0, ChannelFuture.class);
|
||||
|
||||
private static void freezeInternal(Path path) throws Exception {
|
||||
Bukkit.getPluginManager().callEvent(new CRIUSleepEvent());
|
||||
|
||||
Bukkit.getWorlds().forEach(FlatteningWrapper.impl::syncSave);
|
||||
Bukkit.getWorlds().forEach(world -> {
|
||||
((CraftWorld) world).getHandle().save(null, true, false);
|
||||
});
|
||||
Statement.closeAll();
|
||||
|
||||
// Close socket
|
||||
Object serverConnection = TinyProtocol.getServerConnection(Core.getInstance());
|
||||
ServerConnectionListener serverConnection = MinecraftServer.getServer().getConnection();
|
||||
List<?> channels = channelFutures.get(serverConnection);
|
||||
for(Object future : channels) {
|
||||
for (Object future : channels) {
|
||||
((ChannelFuture) future).channel().close().syncUninterruptibly();
|
||||
}
|
||||
channels.clear();
|
||||
@@ -121,7 +127,7 @@ class CheckpointUtilsJ9 {
|
||||
criu.checkpointJVM();
|
||||
} catch (JVMCRIUException e) {
|
||||
Path logfile = path.resolve("criu.log");
|
||||
if(logfile.toFile().exists()) {
|
||||
if (logfile.toFile().exists()) {
|
||||
throw new IllegalStateException("Could not create checkpoint, criu log:\n" + new String(Files.readAllBytes(logfile)), e);
|
||||
}
|
||||
|
||||
@@ -135,11 +141,9 @@ class CheckpointUtilsJ9 {
|
||||
}
|
||||
|
||||
// Reopen socket
|
||||
bind.invoke(serverConnection, InetAddress.getLoopbackAddress(), port);
|
||||
if(Core.getVersion() > 12) {
|
||||
for(Object future : channels) {
|
||||
((ChannelFuture) future).channel().config().setAutoRead(true);
|
||||
}
|
||||
serverConnection.startTcpServerListener(InetAddress.getLoopbackAddress(), port);
|
||||
for (Object future : channels) {
|
||||
((ChannelFuture) future).channel().config().setAutoRead(true);
|
||||
}
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new CRIUWakeupEvent());
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.SimpleCommandMap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@UtilityClass
|
||||
public class CommandRemover {
|
||||
private static final Reflection.Field<SimpleCommandMap> commandMap = Reflection.getField("org.bukkit.craftbukkit.CraftServer", "commandMap", SimpleCommandMap.class);
|
||||
private static final Reflection.Field<Map> knownCommands = Reflection.getField(SimpleCommandMap.class, "knownCommands", Map.class);
|
||||
public static void removeAll(String... cmds) {
|
||||
Map<String, Command> knownCmds = knownCommands.get(commandMap.get(Bukkit.getServer()));
|
||||
for (String cmd : cmds) {
|
||||
knownCmds.remove(cmd.toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,16 +21,11 @@ package de.steamwar.core;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.command.*;
|
||||
import de.steamwar.core.authlib.SteamwarGameProfileRepository;
|
||||
import de.steamwar.core.events.AntiNocom;
|
||||
import de.steamwar.core.events.ChattingEvent;
|
||||
import de.steamwar.core.events.PlayerJoinedEvent;
|
||||
import de.steamwar.core.events.WorldLoadEvent;
|
||||
import de.steamwar.command.SWCommandUtils;
|
||||
import de.steamwar.command.SWTypeMapperCreator;
|
||||
import de.steamwar.command.TabCompletionCache;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.core.authlib.SteamwarGameProfileRepository;
|
||||
import de.steamwar.linkage.AbstractLinker;
|
||||
import de.steamwar.linkage.SpigotLinker;
|
||||
import de.steamwar.message.Message;
|
||||
@@ -52,52 +47,53 @@ import java.util.logging.Level;
|
||||
|
||||
public class Core extends JavaPlugin {
|
||||
|
||||
public static final Message MESSAGE = new Message("SpigotCore", Core.class.getClassLoader());
|
||||
public static final Message MESSAGE = new Message("SpigotCore", Core.class.getClassLoader());
|
||||
|
||||
public static int getVersion(){
|
||||
return Reflection.MAJOR_VERSION;
|
||||
}
|
||||
@Deprecated
|
||||
public static int getVersion() {
|
||||
return Reflection.MAJOR_VERSION;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private static JavaPlugin instance;
|
||||
@Getter
|
||||
@Setter
|
||||
private static JavaPlugin instance;
|
||||
|
||||
@Getter
|
||||
private static String serverName = "";
|
||||
@Getter
|
||||
private static String serverName = "";
|
||||
|
||||
public static void setServerName(String serverName) {
|
||||
if (Core.serverName.isEmpty()) {
|
||||
Core.serverName = serverName;
|
||||
}
|
||||
}
|
||||
public static void setServerName(String serverName) {
|
||||
if (Core.serverName.isEmpty()) {
|
||||
Core.serverName = serverName;
|
||||
}
|
||||
}
|
||||
|
||||
private ErrorHandler errorHandler;
|
||||
private CrashDetector crashDetector;
|
||||
private ErrorHandler errorHandler;
|
||||
private CrashDetector crashDetector;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
setInstance(this);
|
||||
serverName = System.getProperty("serverName", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
new PlayerVersion();
|
||||
@Override
|
||||
public void onLoad() {
|
||||
setInstance(this);
|
||||
serverName = System.getProperty("serverName", "");
|
||||
}
|
||||
|
||||
errorHandler = new ErrorHandler();
|
||||
crashDetector = new CrashDetector();
|
||||
@Override
|
||||
public void onEnable() {
|
||||
new PlayerVersion();
|
||||
|
||||
SWCommandUtils.init((SWTypeMapperCreator<TypeMapper<Object>, CommandSender, Object>) (mapper, tabCompleter) -> new TypeMapper<Object>() {
|
||||
@Override
|
||||
public Object map(CommandSender commandSender, String[] previousArguments, String s) {
|
||||
return mapper.apply(s);
|
||||
}
|
||||
errorHandler = new ErrorHandler();
|
||||
crashDetector = new CrashDetector();
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(CommandSender sender, String[] previousArguments, String s) {
|
||||
return tabCompleter.apply(sender, s);
|
||||
}
|
||||
});
|
||||
SWCommandUtils.init((SWTypeMapperCreator<TypeMapper<Object>, CommandSender, Object>) (mapper, tabCompleter) -> new TypeMapper<Object>() {
|
||||
@Override
|
||||
public Object map(CommandSender commandSender, String[] previousArguments, String s) {
|
||||
return mapper.apply(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(CommandSender sender, String[] previousArguments, String s) {
|
||||
return tabCompleter.apply(sender, s);
|
||||
}
|
||||
});
|
||||
|
||||
SpigotLinker spigotLinker = new SpigotLinker(this, MESSAGE);
|
||||
try {
|
||||
@@ -108,36 +104,33 @@ public class Core extends JavaPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
Bukkit.getServer().getPluginManager().registerEvents(RecipeDiscoverWrapper.impl, this);
|
||||
if(!Statement.productionDatabase()) {
|
||||
getServer().getPluginManager().registerEvents(LocaleChangeWrapper.impl, this);
|
||||
}
|
||||
if (!Statement.productionDatabase()) {
|
||||
getServer().getPluginManager().registerEvents(new LocaleChangeWrapper(), this);
|
||||
}
|
||||
|
||||
getServer().getMessenger().registerIncomingPluginChannel(this, "sw:bridge", new NetworkReceiver());
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(this, "sw:bridge");
|
||||
getServer().getMessenger().registerIncomingPluginChannel(this, "sw:bridge", new NetworkReceiver());
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(this, "sw:bridge");
|
||||
|
||||
if (Core.getVersion() != 20)
|
||||
SteamwarGameProfileRepository.impl.inject();
|
||||
SteamwarGameProfileRepository.impl.inject();
|
||||
|
||||
TinyProtocol.init();
|
||||
CheckpointUtils.signalHandler();
|
||||
TinyProtocol.init();
|
||||
CheckpointUtils.signalHandler();
|
||||
|
||||
Bukkit.getScheduler().runTaskTimer(this, TabCompletionCache::invalidateOldEntries, 20, 20);
|
||||
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SteamwarUser::clear, 72000, 72000);
|
||||
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SchematicNode::clear, 20L * 30, 20L * 30);
|
||||
Bukkit.getScheduler().runTaskTimer(this, TabCompletionCache::invalidateOldEntries, 20, 20);
|
||||
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SteamwarUser::clear, 72000, 72000);
|
||||
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SchematicNode::clear, 20L * 30, 20L * 30);
|
||||
|
||||
try {
|
||||
getLogger().log(Level.INFO, "Running on: " + new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream())).readLine());
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not load Hostname", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
getLogger().log(Level.INFO, "Running on: " + new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream())).readLine());
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not load Hostname", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
TinyProtocol.instance.close();
|
||||
errorHandler.unregister();
|
||||
if(crashDetector.onMainThread())
|
||||
Statement.closeAll();
|
||||
}
|
||||
@Override
|
||||
public void onDisable() {
|
||||
TinyProtocol.instance.close();
|
||||
errorHandler.unregister();
|
||||
if (crashDetector.onMainThread()) Statement.closeAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,18 @@
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import org.bukkit.craftbukkit.CraftChunk;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@UtilityClass
|
||||
public class CraftbukkitWrapper {
|
||||
private CraftbukkitWrapper() {}
|
||||
|
||||
public static final ICraftbukkitWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
|
||||
public interface ICraftbukkitWrapper {
|
||||
void sendChunk(Player p, int chunkX, int chunkZ);
|
||||
public void sendChunk(Player p, int chunkX, int chunkZ) {
|
||||
LevelChunk chunk = (LevelChunk) ((CraftChunk) p.getWorld().getChunkAt(chunkX, chunkZ)).getHandle(ChunkStatus.FULL);
|
||||
TinyProtocol.instance.sendPacket(p, new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public class CrashDetector {
|
||||
|
||||
private boolean run = true;
|
||||
|
||||
public CrashDetector () {
|
||||
public CrashDetector() {
|
||||
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
|
||||
lastTick.set(System.nanoTime());
|
||||
lastMessage.set(System.nanoTime());
|
||||
@@ -60,11 +60,11 @@ public class CrashDetector {
|
||||
SWException.init();
|
||||
while (run) {
|
||||
long curTime = System.nanoTime();
|
||||
if(curTime - 4*TIMEOUT >= lastTick.get()) {
|
||||
if (curTime - 4 * TIMEOUT >= lastTick.get()) {
|
||||
SWException.log("Server did not recover in " + ((curTime - lastTick.get()) / 1000000.0) + "ms, unclean server stop", "");
|
||||
hardStop();
|
||||
} else if(curTime - TIMEOUT > lastMessage.get()) {
|
||||
if(mainThread.isAlive()) {
|
||||
} else if (curTime - TIMEOUT > lastMessage.get()) {
|
||||
if (mainThread.isAlive()) {
|
||||
SWException.log("Server hung for " + ((curTime - lastTick.get()) / 1000000.0) + "ms", Arrays.stream(mainThread.getStackTrace()).map(StackTraceElement::toString).collect(Collectors.joining("\n")));
|
||||
} else {
|
||||
SWException.log("Server thread already dead, unclean server stop", "Core enabled: " + Core.getInstance().isEnabled());
|
||||
@@ -81,7 +81,7 @@ public class CrashDetector {
|
||||
}
|
||||
|
||||
private void hardStop() {
|
||||
if(Core.getInstance().isEnabled()) {
|
||||
if (Core.getInstance().isEnabled()) {
|
||||
Core.getInstance().onDisable();
|
||||
}
|
||||
Statement.closeAll();
|
||||
|
||||
@@ -21,6 +21,7 @@ package de.steamwar.core;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.sql.SWException;
|
||||
import org.spigotmc.WatchdogThread;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
@@ -36,13 +37,11 @@ public class ErrorHandler extends Handler {
|
||||
|
||||
private final long watchdogThreadId;
|
||||
|
||||
public ErrorHandler(){
|
||||
public ErrorHandler() {
|
||||
Logger.getLogger("").addHandler(this);
|
||||
|
||||
Class<?> watchdogThread = Reflection.getClass("org.spigotmc.WatchdogThread");
|
||||
Reflection.Field<?> getInstance = Reflection.getField(watchdogThread, watchdogThread, 0);
|
||||
Thread watchdog = (Thread) getInstance.get(null);
|
||||
watchdogThreadId = watchdog.getId();
|
||||
Reflection.Field<WatchdogThread> getInstance = Reflection.getField(WatchdogThread.class, WatchdogThread.class, 0);
|
||||
watchdogThreadId = getInstance.get(null).getId();
|
||||
}
|
||||
|
||||
void unregister() {
|
||||
@@ -52,29 +51,30 @@ public class ErrorHandler extends Handler {
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void publish(LogRecord logRecord) {
|
||||
if(logRecord.getLevel().intValue() < Level.WARNING.intValue())
|
||||
return;
|
||||
if (logRecord.getLevel().intValue() < Level.WARNING.intValue()) return;
|
||||
|
||||
if(watchdogThreadId == logRecord.getThreadID())
|
||||
return;
|
||||
if (watchdogThreadId == logRecord.getThreadID()) return;
|
||||
|
||||
String message = logRecord.getMessage() != null ? logRecord.getMessage() : "";
|
||||
for(String reason : ignoreStartsWith)
|
||||
if(message.startsWith(reason))
|
||||
return;
|
||||
for(String reason : ignoreContains)
|
||||
if(message.contains(reason))
|
||||
return;
|
||||
for (String reason : ignoreStartsWith) {
|
||||
if (message.startsWith(reason)) return;
|
||||
}
|
||||
for (String reason : ignoreContains) {
|
||||
if (message.contains(reason)) return;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream stacktraceOutput = new ByteArrayOutputStream();
|
||||
if(logRecord.getThrown() != null)
|
||||
if (logRecord.getThrown() != null) {
|
||||
logRecord.getThrown().printStackTrace(new PrintStream(stacktraceOutput));
|
||||
}
|
||||
String stacktrace = stacktraceOutput.toString();
|
||||
if(stacktrace.contains("POI data mismatch") || stacktrace.contains("Newer version! Server downgrades are not supported!"))
|
||||
if (stacktrace.contains("POI data mismatch") || stacktrace.contains("Newer version! Server downgrades are not supported!")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(message.isEmpty() && stacktrace.isEmpty())
|
||||
if (message.isEmpty() && stacktrace.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
SWException.log(message, stacktrace);
|
||||
|
||||
@@ -19,45 +19,16 @@
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.contents.PlainTextContents;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@UtilityClass
|
||||
public class FlatteningWrapper {
|
||||
private FlatteningWrapper() {}
|
||||
|
||||
public static final Class<?> scoreboardObjective = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetObjectivePacket");
|
||||
public static final Class<?> scoreboardScore = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetScorePacket");
|
||||
|
||||
public static final IFlatteningWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
|
||||
public interface IFlatteningWrapper {
|
||||
void setScoreboardTitle(Object packet, String title);
|
||||
void setScoreAction(Object packet);
|
||||
|
||||
Material getMaterial(String material);
|
||||
Material getDye(int colorCode);
|
||||
ItemStack setSkullOwner(String player);
|
||||
|
||||
Object getPose(EntityPose pose);
|
||||
void setNamedSpawnPacketDataWatcher(Object packet);
|
||||
Object formatDisplayName(String displayName);
|
||||
|
||||
void setSpawnPacketType(Object packet, EntityType type);
|
||||
|
||||
int getViewDistance(Player player);
|
||||
|
||||
void syncSave(World world);
|
||||
}
|
||||
|
||||
public enum EntityPose {
|
||||
NORMAL,
|
||||
SNEAKING,
|
||||
SWIMMING,
|
||||
SHOOTING,
|
||||
;
|
||||
public Object formatDisplayName(String displayName) {
|
||||
return displayName != null ? Optional.of((Object) MutableComponent.create(PlainTextContents.create(displayName))) : Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,17 @@
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerLocaleChangeEvent;
|
||||
|
||||
public interface LocaleChangeWrapper extends Listener {
|
||||
LocaleChangeWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
import java.util.Locale;
|
||||
|
||||
public class LocaleChangeWrapper implements Listener {
|
||||
|
||||
@EventHandler
|
||||
private void onLocale(PlayerLocaleChangeEvent event) {
|
||||
SteamwarUser.get(event.getPlayer().getUniqueId()).setLocale(Locale.forLanguageTag(event.getLocale()), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,37 +19,30 @@
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import org.bukkit.GameMode;
|
||||
|
||||
import java.util.function.LongSupplier;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
|
||||
public interface ProtocolWrapper {
|
||||
@UtilityClass
|
||||
public class ProtocolWrapper {
|
||||
|
||||
Class<?> itemStack = Reflection.getClass("net.minecraft.world.item.ItemStack");
|
||||
Class<?> spawnPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundAddEntityPacket");
|
||||
Class<?> spawnLivingPacket = Core.getVersion() > 18 ? ProtocolWrapper.spawnPacket : Reflection.getClass("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntityLiving");
|
||||
Class<?> equipmentPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket");
|
||||
public Object playerInfoPacketConstructor(PlayerInfoAction action, GameProfile profile, GameMode mode) {
|
||||
if (action == PlayerInfoAction.REMOVE) {
|
||||
return new ClientboundPlayerInfoRemovePacket(Collections.singletonList(profile.getId()));
|
||||
}
|
||||
|
||||
Class<?> enumGamemode = Reflection.getClass(Core.getVersion() > 9 ? "net.minecraft.world.level.GameType" : "net.minecraft.WorldSettings$EnumGamemode");
|
||||
Reflection.Method getGameModeById = Reflection.getTypedMethod(enumGamemode, null, enumGamemode, int.class);
|
||||
|
||||
// 0: hand, 1: offhand, 2: feet, 3: legs, 4: chest, 5: head
|
||||
Object[] itemSlots = Core.getVersion() > 8 ? Reflection.getClass("net.minecraft.world.entity.EnumItemSlot").getEnumConstants() : new Integer[]{0, 0, 1, 2, 3, 4};
|
||||
|
||||
ProtocolWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
|
||||
void setEquipmentPacketStack(Object packet, Object slot, Object stack);
|
||||
|
||||
Object playerInfoPacketConstructor(PlayerInfoAction action, GameProfile profile, GameMode mode);
|
||||
|
||||
default void initTPSWarp(LongSupplier longSupplier) {
|
||||
Class<?> systemUtils = Reflection.getClass("net.minecraft.Util");
|
||||
Reflection.getField(systemUtils, LongSupplier.class, 0).set(systemUtils, (LongSupplier) () -> System.nanoTime() + longSupplier.getAsLong());
|
||||
return new ClientboundPlayerInfoUpdatePacket(action == PlayerInfoAction.ADD ?
|
||||
EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE) : EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE),
|
||||
Collections.singletonList(new ClientboundPlayerInfoUpdatePacket.Entry(profile.getId(), profile, false, 0, GameType.byId(mode.getValue()), null, false, 0, null)));
|
||||
}
|
||||
|
||||
enum PlayerInfoAction {
|
||||
public enum PlayerInfoAction {
|
||||
ADD,
|
||||
GAMEMODE,
|
||||
REMOVE
|
||||
|
||||
@@ -19,8 +19,15 @@
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import de.steamwar.linkage.Linked;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerRecipeDiscoverEvent;
|
||||
|
||||
public interface RecipeDiscoverWrapper extends Listener {
|
||||
RecipeDiscoverWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
@Linked
|
||||
public class RecipeDiscoverWrapper implements Listener {
|
||||
@EventHandler
|
||||
public void onRecipeDiscover(PlayerRecipeDiscoverEvent e) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import lombok.NonNull;
|
||||
import lombok.experimental.Delegate;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -145,7 +144,7 @@ public class SWPlayer {
|
||||
return this;
|
||||
}
|
||||
|
||||
private ThreadLocal<Message> messageThreadLocal = ThreadLocal.withInitial(() -> null);
|
||||
private ThreadLocal<Message> messageThreadLocal = ThreadLocal.withInitial(() -> null);
|
||||
|
||||
public SWPlayer using(Message message) {
|
||||
this.messageThreadLocal.set(message);
|
||||
@@ -154,7 +153,9 @@ public class SWPlayer {
|
||||
|
||||
private Message getMessage() {
|
||||
Message message = this.messageThreadLocal.get();
|
||||
if (message == null) throw new IllegalStateException("Use #using(Message) before sending or parsing a message!");
|
||||
if (message == null) {
|
||||
throw new IllegalStateException("Use #using(Message) before sending or parsing a message!");
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
@UtilityClass
|
||||
public class TPSWarpUtils {
|
||||
|
||||
private static long nanoOffset = 0;
|
||||
private static long nanoDOffset = 0;
|
||||
private static BukkitTask bukkitTask = null;
|
||||
|
||||
static {
|
||||
ProtocolWrapper.impl.initTPSWarp(() -> nanoOffset);
|
||||
}
|
||||
|
||||
public static void warp(double tps) {
|
||||
double d = 50 - (50 / (tps / 20.0));
|
||||
nanoDOffset = Math.max(0, (long) (d * 1000000));
|
||||
if (nanoDOffset == 0) {
|
||||
if (bukkitTask == null) return;
|
||||
bukkitTask.cancel();
|
||||
bukkitTask = null;
|
||||
} else if (bukkitTask == null) {
|
||||
bukkitTask = Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> nanoOffset += nanoDOffset, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isWarping() {
|
||||
return nanoDOffset > 0;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class TPSWatcher {
|
||||
@@ -36,8 +36,9 @@ public class TPSWatcher {
|
||||
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
if (currentTime > lastTime)
|
||||
if (currentTime > lastTime) {
|
||||
tps = (timeInterval / (double) (currentTime - lastTime)) * TICK_DEFAULT;
|
||||
}
|
||||
|
||||
lastTime = currentTime;
|
||||
}, timeInterval / 50, timeInterval / 50);
|
||||
@@ -68,24 +69,17 @@ public class TPSWatcher {
|
||||
case TEN_SECONDS:
|
||||
return round(tps_TenSecond.tps);
|
||||
case ONE_MINUTE:
|
||||
return round(getSpigotTPS()[0]);
|
||||
return round(MinecraftServer.getServer().tps1.getAverage());
|
||||
case FIVE_MINUTES:
|
||||
return round(getSpigotTPS()[1]);
|
||||
return round(MinecraftServer.getServer().tps5.getAverage());
|
||||
case TEN_MINUTES:
|
||||
return round(getSpigotTPS()[2]);
|
||||
return round(MinecraftServer.getServer().tps15.getAverage());
|
||||
case ONE_SECOND:
|
||||
default:
|
||||
return round(tps_OneSecond.tps);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> minecraftServer = Reflection.getClass("net.minecraft.server.MinecraftServer");
|
||||
private static final Reflection.Method getServer = Reflection.getTypedMethod(minecraftServer, "getServer", minecraftServer);
|
||||
private static final Reflection.Field<double[]> recentTps = Reflection.getField(minecraftServer, "recentTps", double[].class);
|
||||
private static double[] getSpigotTPS() {
|
||||
return recentTps.get(getServer.invoke(null));
|
||||
}
|
||||
|
||||
private static double round(double d) {
|
||||
return Math.round(d * 10) / 10.0;
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
|
||||
public interface TrickyParticleWrapper {
|
||||
public TrickyParticleWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
|
||||
Particle getVillagerHappy();
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
public interface TrickyTrialsWrapper {
|
||||
TrickyTrialsWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
|
||||
EntityType getTntEntityType();
|
||||
|
||||
Enchantment getUnbreakingEnchantment();
|
||||
|
||||
Material getTurtleScute();
|
||||
|
||||
String getValue(Property property);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class VersionDependent {
|
||||
private VersionDependent() {}
|
||||
|
||||
public static <T> T getVersionImpl(Plugin plugin) {
|
||||
return getVersionImpl(plugin, (new Exception()).getStackTrace()[1].getClassName());
|
||||
}
|
||||
|
||||
public static <T> T getVersionImpl(Plugin plugin, String className){
|
||||
return getVersionImpl(plugin, Core.getVersion(), className);
|
||||
}
|
||||
|
||||
public static <T> T getVersionImpl(Plugin plugin, int fromVersion){
|
||||
return getVersionImpl(plugin, fromVersion, (new Exception()).getStackTrace()[1].getClassName());
|
||||
}
|
||||
|
||||
public static <T> T getVersionImpl(Plugin plugin, int fromVersion, String className){
|
||||
ClassLoader loader = plugin.getClass().getClassLoader();
|
||||
for(int version = fromVersion; version >= 8; version--) {
|
||||
try {
|
||||
return ((Class<? extends T>) Class.forName(className + version, true, loader)).getDeclaredConstructor().newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
throw new SecurityException("Could not load version dependent class", e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// try next version
|
||||
}
|
||||
}
|
||||
throw new SecurityException("Unable to find version dependent implementation for " + className);
|
||||
}
|
||||
}
|
||||
@@ -40,12 +40,12 @@ import org.bukkit.event.player.*;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
@Linked
|
||||
@PluginCheck("WorldEdit")
|
||||
@PluginCheck("FastAsyncWorldEdit")
|
||||
public class WorldEditRenderer implements Listener {
|
||||
|
||||
private static WorldEditRenderer INSTANCE;
|
||||
|
||||
private static final Material WAND = FlatteningWrapper.impl.getMaterial("WOOD_AXE");
|
||||
private static final Material WAND = Material.WOODEN_AXE;
|
||||
|
||||
private final WorldEditPlugin we;
|
||||
|
||||
@@ -89,7 +89,7 @@ public class WorldEditRenderer implements Listener {
|
||||
|
||||
private void renderRegion(Player player, LocalSession session, boolean scheduled) {
|
||||
World world = session.getSelectionWorld();
|
||||
if(world != null) {
|
||||
if (world != null) {
|
||||
RegionSelector regionSelector = session.getRegionSelector(world);
|
||||
try {
|
||||
Region region = regionSelector.getRegion();
|
||||
@@ -102,7 +102,7 @@ public class WorldEditRenderer implements Listener {
|
||||
|
||||
private void drawCuboid(Vector min, Vector max, boolean scheduled, boolean clipboard, Player owner) {
|
||||
//noinspection deprecation
|
||||
if(owner.getItemInHand().getType() != WAND) {
|
||||
if (owner.getItemInHand().getType() != WAND) {
|
||||
WorldEditRendererWrapper.impl.hide(owner, true, true);
|
||||
WorldEditRendererWrapper.impl.hide(owner, false, true);
|
||||
} else {
|
||||
@@ -114,7 +114,7 @@ public class WorldEditRenderer implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
if(event.getPlayer().getItemInHand().getType() == WAND) {
|
||||
if (event.getPlayer().getItemInHand().getType() == WAND) {
|
||||
WorldEditRendererWrapper.impl.tick(event.getPlayer());
|
||||
}
|
||||
renderClipboard(event.getPlayer(), we.getSession(event.getPlayer()), false);
|
||||
|
||||
@@ -104,10 +104,10 @@ public class WorldEditRendererCUIEditor implements Listener {
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum Width {
|
||||
HUGE(15, "WORLDEDIT_CUI_WIDTH_HUGE", 2/16f),
|
||||
LARGE(8, "WORLDEDIT_CUI_WIDTH_LARGE", 1/16f),
|
||||
MEDIUM(4, "WORLDEDIT_CUI_WIDTH_MEDIUM", 1/32f),
|
||||
SLIM(0, "WORLDEDIT_CUI_WIDTH_SLIM", 1/64f);
|
||||
HUGE(15, "WORLDEDIT_CUI_WIDTH_HUGE", 2 / 16f),
|
||||
LARGE(8, "WORLDEDIT_CUI_WIDTH_LARGE", 1 / 16f),
|
||||
MEDIUM(4, "WORLDEDIT_CUI_WIDTH_MEDIUM", 1 / 32f),
|
||||
SLIM(0, "WORLDEDIT_CUI_WIDTH_SLIM", 1 / 64f);
|
||||
|
||||
public final int lightLevel;
|
||||
public final String name;
|
||||
@@ -116,9 +116,7 @@ public class WorldEditRendererCUIEditor implements Listener {
|
||||
|
||||
public WorldEditRendererCUIEditor() {
|
||||
Bukkit.getPluginManager().registerEvents(this, Core.getInstance());
|
||||
if (Core.getVersion() >= 20) {
|
||||
new Command();
|
||||
}
|
||||
new Command();
|
||||
}
|
||||
|
||||
private static class Command extends SWCommand {
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class WorldEditRendererFallback {
|
||||
|
||||
private static final int VIEW_DISTANCE = 64;
|
||||
private static final int SQ_VIEW_DISTANCE = VIEW_DISTANCE * VIEW_DISTANCE;
|
||||
|
||||
private static final double STEP_SIZE = 0.5;
|
||||
private static final Vector ONES = new Vector(1, 1, 1);
|
||||
private static final Vector STEPS = new Vector(STEP_SIZE, STEP_SIZE, STEP_SIZE);
|
||||
|
||||
public void draw(Player player, boolean scheduled, boolean clipboard, Vector min, Vector max) {
|
||||
if (!scheduled) return;
|
||||
|
||||
max = max.clone().add(ONES);
|
||||
drawLine(player, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(max.getX(), min.getY(), min.getZ()));
|
||||
drawLine(player, clipboard, new Vector(min.getX(), max.getY(), min.getZ()), new Vector(max.getX(), max.getY(), min.getZ()));
|
||||
drawLine(player, clipboard, new Vector(min.getX(), min.getY(), max.getZ()), new Vector(max.getX(), min.getY(), max.getZ()));
|
||||
drawLine(player, clipboard, new Vector(min.getX(), max.getY(), max.getZ()), new Vector(max.getX(), max.getY(), max.getZ()));
|
||||
|
||||
drawLine(player, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(min.getX(), max.getY(), min.getZ()));
|
||||
drawLine(player, clipboard, new Vector(max.getX(), min.getY(), min.getZ()), new Vector(max.getX(), max.getY(), min.getZ()));
|
||||
drawLine(player, clipboard, new Vector(min.getX(), min.getY(), max.getZ()), new Vector(min.getX(), max.getY(), max.getZ()));
|
||||
drawLine(player, clipboard, new Vector(max.getX(), min.getY(), max.getZ()), new Vector(max.getX(), max.getY(), max.getZ()));
|
||||
|
||||
drawLine(player, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(min.getX(), min.getY(), max.getZ()));
|
||||
drawLine(player, clipboard, new Vector(max.getX(), min.getY(), min.getZ()), new Vector(max.getX(), min.getY(), max.getZ()));
|
||||
drawLine(player, clipboard, new Vector(min.getX(), max.getY(), min.getZ()), new Vector(min.getX(), max.getY(), max.getZ()));
|
||||
drawLine(player, clipboard, new Vector(max.getX(), max.getY(), min.getZ()), new Vector(max.getX(), max.getY(), max.getZ()));
|
||||
}
|
||||
|
||||
private void drawLine(Player player, boolean clipboard, Vector min, Vector max) {
|
||||
Particle particle;
|
||||
if (clipboard) {
|
||||
particle = Particle.HAPPY_VILLAGER;
|
||||
} else {
|
||||
particle = Particle.DRAGON_BREATH;
|
||||
}
|
||||
|
||||
Vector stepSize = max.clone().subtract(min).normalize().multiply(STEPS);
|
||||
while (min.getX() <= max.getX() && min.getY() <= max.getY() && min.getZ() <= max.getZ()) {
|
||||
Location location = player.getLocation();
|
||||
double dx = min.getX() - location.getX();
|
||||
double dy = min.getY() - location.getY();
|
||||
double dz = min.getZ() - location.getZ();
|
||||
if (dx * dx + dy * dy + dz * dz > SQ_VIEW_DISTANCE) {
|
||||
min.add(stepSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
player.spawnParticle(particle, min.getX(), min.getY(), min.getZ(), 1, 0.0, 0.0, 0.0, 0.0);
|
||||
min.add(stepSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,19 @@
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import de.steamwar.entity.CWireframe;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public interface WorldEditRendererWrapper {
|
||||
WorldEditRendererWrapper fallback = VersionDependent.getVersionImpl(Core.getInstance(), 9);
|
||||
WorldEditRendererWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class WorldEditRendererWrapper {
|
||||
public static final WorldEditRendererFallback fallback = new WorldEditRendererFallback();
|
||||
public static final WorldEditRendererWrapper impl = new WorldEditRendererWrapper();
|
||||
|
||||
static void safeDraw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) {
|
||||
if (PlayerVersion.isBedrock(player) || PlayerVersion.getVersion(player) < 20) {
|
||||
@@ -34,11 +41,83 @@ public interface WorldEditRendererWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2);
|
||||
private static final class BoxPair {
|
||||
private CWireframe regionBox;
|
||||
private CWireframe clipboardBox;
|
||||
|
||||
void tick(Player player);
|
||||
public CWireframe get(boolean clipboard) {
|
||||
if (clipboard) {
|
||||
return clipboardBox;
|
||||
} else {
|
||||
return regionBox;
|
||||
}
|
||||
}
|
||||
|
||||
void hide(Player player, boolean clipboard, boolean hide);
|
||||
public void set(boolean clipboard, CWireframe box) {
|
||||
if (clipboard) {
|
||||
this.clipboardBox = box;
|
||||
} else {
|
||||
this.regionBox = box;
|
||||
}
|
||||
}
|
||||
|
||||
void remove(Player player);
|
||||
public void die() {
|
||||
if (clipboardBox != null) {
|
||||
clipboardBox.die();
|
||||
}
|
||||
if (regionBox != null) {
|
||||
regionBox.die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<Player, REntityServer> servers = new HashMap<>();
|
||||
private static final Map<Player, BoxPair> boxes = new HashMap<>();
|
||||
|
||||
public void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) {
|
||||
REntityServer server = servers.computeIfAbsent(player, __ -> {
|
||||
REntityServer entityServer = new REntityServer();
|
||||
entityServer.addPlayer(player);
|
||||
return entityServer;
|
||||
});
|
||||
|
||||
WorldEditRendererCUIEditor.Type type = clipboard ? WorldEditRendererCUIEditor.Type.CLIPBOARD : WorldEditRendererCUIEditor.Type.SELECTION;
|
||||
float width = type.getWidth(player).value;
|
||||
Material material = type.getMaterial(player);
|
||||
if (material == Material.BARRIER) {
|
||||
hide(player, clipboard, true);
|
||||
return;
|
||||
}
|
||||
BlockData block = material.createBlockData();
|
||||
|
||||
BoxPair boxPair = boxes.computeIfAbsent(player, __ -> new BoxPair());
|
||||
CWireframe box = boxPair.get(clipboard);
|
||||
if (box == null) {
|
||||
box = new CWireframe(server);
|
||||
boxPair.set(clipboard, box);
|
||||
}
|
||||
box.setPos1And2(pos1.toLocation(player.getWorld()), pos2.toLocation(player.getWorld()));
|
||||
box.setWidth(width);
|
||||
box.setBlock(block);
|
||||
}
|
||||
|
||||
public void tick(Player player) {
|
||||
REntityServer server = servers.get(player);
|
||||
if (server != null) server.tick();
|
||||
}
|
||||
|
||||
public void hide(Player player, boolean clipboard, boolean hide) {
|
||||
BoxPair boxPair = boxes.get(player);
|
||||
if (boxPair == null) return;
|
||||
CWireframe box = boxPair.get(clipboard);
|
||||
if (box == null) return;
|
||||
box.hide(hide);
|
||||
}
|
||||
|
||||
public void remove(Player player) {
|
||||
BoxPair boxPair = boxes.remove(player);
|
||||
if (boxPair != null) boxPair.die();
|
||||
REntityServer server = servers.remove(player);
|
||||
if (server != null) server.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,18 @@
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV3;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.worldedit.EmptyClipboardException;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.*;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV1Reader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Reader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
@@ -30,25 +39,140 @@ import de.steamwar.sql.NodeData;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.enginehub.linbus.stream.LinBinaryIO;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public interface WorldEditWrapper {
|
||||
WorldEditWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
public class WorldEditWrapper {
|
||||
public static final WorldEditWrapper impl = new WorldEditWrapper();
|
||||
|
||||
InputStream getPlayerClipboard(Player player);
|
||||
public InputStream getPlayerClipboard(Player player) {
|
||||
return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) -> {
|
||||
ClipboardWriter writer = BuiltInClipboardFormat.FAST_V3.getWriter(outputStream);
|
||||
writer.write(clipboard);
|
||||
writer.close();
|
||||
});
|
||||
}
|
||||
|
||||
void setPlayerClipboard(Player player, Clipboard clipboard);
|
||||
Clipboard getClipboard(NodeData data) throws IOException;
|
||||
Clipboard getClipboard(InputStream inputStream) throws IOException;
|
||||
public void setPlayerClipboard(Player player, Clipboard clipboard) {
|
||||
Actor actor = WorldEditWrapper.getWorldEditPlugin().wrapCommandSender(player);
|
||||
WorldEditWrapper.getWorldEditPlugin().getWorldEdit().getSessionManager().get(actor).setClipboard(new ClipboardHolder(clipboard));
|
||||
}
|
||||
|
||||
Vector getOrigin(Clipboard clipboard);
|
||||
Vector getMinimum(Region region);
|
||||
Vector getMaximum(Region region);
|
||||
Vector applyTransform(Vector vector, Transform transform);
|
||||
public Clipboard getClipboard(NodeData data) throws IOException {
|
||||
ResetableInputStream is = new ResetableInputStream(data.schemData(false));
|
||||
for (ClipboardFormat clipboardFormat : ClipboardFormats.getAll()) {
|
||||
FilterInputStream fis = new FilterInputStream(is) {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// Ignore close call!
|
||||
}
|
||||
};
|
||||
boolean canBeRead = clipboardFormat.isFormat(fis);
|
||||
is.reset();
|
||||
if (!canBeRead) continue;
|
||||
return clipboardFormat.load(is);
|
||||
}
|
||||
throw new IOException("No clipboard found");
|
||||
}
|
||||
|
||||
NodeData.SchematicFormat getNativeFormat();
|
||||
private static final Function<InputStream, ClipboardReader> FastV3 = FastSchematicReaderV3::new;
|
||||
@SuppressWarnings("removal")
|
||||
private static final Function<InputStream, ClipboardReader> FastV2 = inputStream -> new FastSchematicReaderV2(new NBTInputStream(inputStream));
|
||||
@SuppressWarnings("removal")
|
||||
private static final Function<InputStream, ClipboardReader> McEdit = inputStream -> new MCEditSchematicReader(new NBTInputStream(inputStream));
|
||||
private static final Function<InputStream, ClipboardReader> SpongeV3 = inputStream -> new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
|
||||
private static final Function<InputStream, ClipboardReader> SpongeV2 = inputStream -> new SpongeSchematicV2Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
|
||||
private static final Function<InputStream, ClipboardReader> SpongeV1 = inputStream -> new SpongeSchematicV1Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
|
||||
|
||||
private static final Function<InputStream, ClipboardReader>[] READERS = new Function[]{
|
||||
FastV3,
|
||||
FastV2,
|
||||
SpongeV3,
|
||||
SpongeV2,
|
||||
SpongeV1,
|
||||
McEdit
|
||||
};
|
||||
|
||||
public Clipboard getClipboard(InputStream inputStream) throws IOException {
|
||||
ResetableInputStream is = new ResetableInputStream(inputStream);
|
||||
for (Function<InputStream, ClipboardReader> reader : READERS) {
|
||||
FilterInputStream fis = new FilterInputStream(is) {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// Ignore close call!
|
||||
}
|
||||
};
|
||||
try {
|
||||
return reader.apply(fis).read();
|
||||
} catch (Exception e) {
|
||||
is.reset();
|
||||
}
|
||||
}
|
||||
is.close();
|
||||
throw new IOException("No clipboard found");
|
||||
}
|
||||
|
||||
private static class ResetableInputStream extends InputStream {
|
||||
|
||||
private InputStream inputStream;
|
||||
private int pointer = 0;
|
||||
private List<Integer> list = new ArrayList<>();
|
||||
|
||||
public ResetableInputStream(InputStream in) {
|
||||
this.inputStream = in;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (pointer >= list.size()) {
|
||||
int data = inputStream.read();
|
||||
list.add(data);
|
||||
pointer++;
|
||||
return data;
|
||||
}
|
||||
int data = list.get(pointer);
|
||||
pointer++;
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() throws IOException {
|
||||
pointer = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
list.clear();
|
||||
pointer = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public org.bukkit.util.Vector getOrigin(Clipboard clipboard) {
|
||||
return new org.bukkit.util.Vector(clipboard.getOrigin().x(), clipboard.getOrigin().y(), clipboard.getOrigin().z());
|
||||
}
|
||||
|
||||
public Vector getMinimum(Region region) {
|
||||
return new Vector(region.getMinimumPoint().x(), region.getMinimumPoint().y(), region.getMinimumPoint().z());
|
||||
}
|
||||
|
||||
public Vector getMaximum(Region region) {
|
||||
return new Vector(region.getMaximumPoint().x(), region.getMaximumPoint().y(), region.getMaximumPoint().z());
|
||||
}
|
||||
|
||||
public Vector applyTransform(Vector vector, Transform transform) {
|
||||
Vector3 v = Vector3.at(vector.getX(), vector.getY(), vector.getZ());
|
||||
v = transform.apply(v);
|
||||
return new org.bukkit.util.Vector(v.x(), v.y(), v.z());
|
||||
}
|
||||
|
||||
public NodeData.SchematicFormat getNativeFormat() {
|
||||
return NodeData.SchematicFormat.SPONGE_V3;
|
||||
}
|
||||
|
||||
static WorldEditPlugin getWorldEditPlugin() {
|
||||
return (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit");
|
||||
@@ -63,8 +187,7 @@ public interface WorldEditWrapper {
|
||||
}
|
||||
|
||||
Clipboard clipboard = clipboardHolder.getClipboard();
|
||||
if(clipboard == null)
|
||||
throw new NoClipboardException();
|
||||
if (clipboard == null) throw new NoClipboardException();
|
||||
|
||||
PipedOutputStream outputStream = new PipedOutputStream();
|
||||
PipedInputStream inputStream;
|
||||
|
||||
@@ -19,15 +19,57 @@
|
||||
|
||||
package de.steamwar.core;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import net.minecraft.network.protocol.game.ClientboundLoginPacket;
|
||||
import net.minecraft.network.protocol.game.CommonPlayerSpawnInfo;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
@Linked
|
||||
public class WorldIdentifier {
|
||||
|
||||
private static final IWorldIdentifier impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
private static ResourceKey<Level> resourceKey = null;
|
||||
|
||||
private static final Class<?> resourceKeyClass = ResourceKey.class;
|
||||
private static final Class<?> minecraftKeyClass = ResourceLocation.class;
|
||||
private static final Reflection.Constructor resourceKeyConstructor = Reflection.getConstructor(resourceKeyClass, minecraftKeyClass, minecraftKeyClass);
|
||||
private static final Reflection.Constructor minecraftKeyConstructor = Reflection.getConstructor(minecraftKeyClass, String.class, String.class);
|
||||
|
||||
public static void set(String name) {
|
||||
impl.setResourceKey(name);
|
||||
resourceKey = (ResourceKey<Level>) resourceKeyConstructor.invoke(minecraftKeyConstructor.invoke("minecraft", "dimension"), minecraftKeyConstructor.invoke("steamwar", name));
|
||||
}
|
||||
|
||||
protected interface IWorldIdentifier {
|
||||
void setResourceKey(String name);
|
||||
public WorldIdentifier() {
|
||||
TinyProtocol.instance.addFilter(ClientboundLoginPacket.class, (player, o) -> {
|
||||
if (resourceKey == null) return o;
|
||||
ClientboundLoginPacket packet = (ClientboundLoginPacket) o;
|
||||
|
||||
return new ClientboundLoginPacket(packet.playerId(),
|
||||
packet.hardcore(),
|
||||
packet.levels(),
|
||||
packet.maxPlayers(),
|
||||
packet.chunkRadius(),
|
||||
packet.simulationDistance(),
|
||||
packet.reducedDebugInfo(),
|
||||
packet.showDeathScreen(),
|
||||
packet.doLimitedCrafting(),
|
||||
new CommonPlayerSpawnInfo(
|
||||
packet.commonPlayerSpawnInfo().dimensionType(),
|
||||
resourceKey,
|
||||
packet.commonPlayerSpawnInfo().seed(),
|
||||
packet.commonPlayerSpawnInfo().gameType(),
|
||||
packet.commonPlayerSpawnInfo().previousGameType(),
|
||||
packet.commonPlayerSpawnInfo().isDebug(),
|
||||
packet.commonPlayerSpawnInfo().isFlat(),
|
||||
packet.commonPlayerSpawnInfo().lastDeathLocation(),
|
||||
packet.commonPlayerSpawnInfo().portalCooldown(),
|
||||
packet.commonPlayerSpawnInfo().seaLevel()
|
||||
),
|
||||
packet.enforcesSecureChat()
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+49
-5
@@ -19,12 +19,56 @@
|
||||
|
||||
package de.steamwar.core.authlib;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.GameProfileRepository;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.VersionDependent;
|
||||
import com.mojang.authlib.ProfileLookupCallback;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.Services;
|
||||
|
||||
public abstract class SteamwarGameProfileRepository implements GameProfileRepository {
|
||||
public static final SteamwarGameProfileRepository impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract void inject();
|
||||
public class SteamwarGameProfileRepository implements GameProfileRepository {
|
||||
public static final SteamwarGameProfileRepository impl = new SteamwarGameProfileRepository();
|
||||
|
||||
private static final GameProfileRepository fallback;
|
||||
private static final Reflection.Field<Services> field;
|
||||
private static final Services current;
|
||||
|
||||
static {
|
||||
Class<?> clazz = MinecraftServer.getServer().getClass();
|
||||
field = Reflection.getField(clazz, Services.class, 0);
|
||||
current = field.get(MinecraftServer.getServer());
|
||||
fallback = current.profileRepository();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findProfilesByNames(String[] strings, ProfileLookupCallback profileLookupCallback) {
|
||||
List<String> unknownNames = new ArrayList<>();
|
||||
for (String name : strings) {
|
||||
SteamwarUser user = SteamwarUser.get(name);
|
||||
if (user == null) {
|
||||
unknownNames.add(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
profileLookupCallback.onProfileLookupSucceeded(new GameProfile(user.getUUID(), user.getUserName()));
|
||||
}
|
||||
if (!unknownNames.isEmpty()) {
|
||||
fallback.findProfilesByNames(unknownNames.toArray(new String[0]), profileLookupCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameProfile> findProfileByName(String s) {
|
||||
return fallback.findProfileByName(s);
|
||||
}
|
||||
|
||||
public void inject() {
|
||||
Services newServices = new Services(current.sessionService(), current.servicesKeySet(), this, current.profileCache(), current.paperConfigurations());
|
||||
field.set(MinecraftServer.getServer(), newServices);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ import de.steamwar.core.Core;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import de.steamwar.sql.SWException;
|
||||
import de.steamwar.techhider.ProtocolUtils;
|
||||
import de.steamwar.techhider.TechHider;
|
||||
import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket;
|
||||
import net.minecraft.network.protocol.game.ServerboundUseItemOnPacket;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -42,9 +46,7 @@ public class AntiNocom implements Listener {
|
||||
|
||||
public AntiNocom() {
|
||||
TinyProtocol.instance.addFilter(blockDig, this::onDig);
|
||||
if(Core.getVersion() > 8) {
|
||||
registerUseItem();
|
||||
}
|
||||
registerUseItem();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -53,18 +55,13 @@ public class AntiNocom implements Listener {
|
||||
}
|
||||
|
||||
private void registerUseItem() {
|
||||
Class<?> useItem = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundUseItemOnPacket");
|
||||
Class<?> useItem = ServerboundUseItemOnPacket.class;
|
||||
|
||||
Function<Object, Object> getPosition;
|
||||
if(Core.getVersion() > 12) {
|
||||
Class<?> movingObjectPositionBlock = Reflection.getClass("net.minecraft.world.phys.BlockHitResult");
|
||||
Reflection.Field<?> useItemPosition = Reflection.getField(useItem, movingObjectPositionBlock, 0);
|
||||
Reflection.Field<?> movingBlockPosition = Reflection.getField(movingObjectPositionBlock, TechHider.blockPosition, 0);
|
||||
Class<?> movingObjectPositionBlock = BlockHitResult.class;
|
||||
Reflection.Field<?> useItemPosition = Reflection.getField(useItem, movingObjectPositionBlock, 0);
|
||||
Reflection.Field<?> movingBlockPosition = Reflection.getField(movingObjectPositionBlock, TechHider.blockPosition, 0);
|
||||
|
||||
getPosition = (packet) -> movingBlockPosition.get(useItemPosition.get(packet));
|
||||
} else {
|
||||
getPosition = Reflection.getField(useItem, TechHider.blockPosition, 0)::get;
|
||||
}
|
||||
Function<Object, Object> getPosition = (packet) -> movingBlockPosition.get(useItemPosition.get(packet));
|
||||
|
||||
TinyProtocol.instance.addFilter(useItem, (player, packet) -> {
|
||||
Object pos = getPosition.apply(packet);
|
||||
@@ -72,21 +69,25 @@ public class AntiNocom implements Listener {
|
||||
});
|
||||
}
|
||||
|
||||
private static final Class<?> blockDig = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundPlayerActionPacket");
|
||||
private static final Class<?> blockDig = ServerboundPlayerActionPacket.class;
|
||||
private static final Reflection.Field<?> digPosition = Reflection.getField(blockDig, TechHider.blockPosition, 0);
|
||||
|
||||
private Object onDig(Player player, Object packet) {
|
||||
Object pos = digPosition.get(packet);
|
||||
return isValid(player, "Dig", TechHider.blockPositionX.get(pos), TechHider.blockPositionZ.get(pos)) ? packet : null;
|
||||
}
|
||||
|
||||
private boolean isValid(Player player, String type, int x, int z) {
|
||||
if((x == 0 && z == 0) || player.getWorld().isChunkLoaded(ProtocolUtils.posToChunk(x), ProtocolUtils.posToChunk(z)))
|
||||
if ((x == 0 && z == 0) || player.getWorld().isChunkLoaded(ProtocolUtils.posToChunk(x), ProtocolUtils.posToChunk(z))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int amount = flags.compute(player, (p, a) -> a == null ? 1 : a+1);
|
||||
if(amount % 8 == 0) { // Only after 8 and every 8 to reduce false flags and spam
|
||||
if(amount == 8) // Schedule player kick only once
|
||||
int amount = flags.compute(player, (p, a) -> a == null ? 1 : a + 1);
|
||||
if (amount % 8 == 0) { // Only after 8 and every 8 to reduce false flags and spam
|
||||
if (amount == 8) {
|
||||
// Schedule player kick only once
|
||||
Bukkit.getScheduler().runTask(Core.getInstance(), () -> player.kickPlayer(null));
|
||||
}
|
||||
|
||||
SWException.log(player.getName() + " kicked for potential NoCom-DOS attack", x + " " + z + " " + type + " " + amount);
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
@Linked
|
||||
public class ChattingEvent implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
private void onChat(AsyncPlayerChatEvent event) {
|
||||
event.setCancelled(true);
|
||||
Core.MESSAGE.broadcastPrefixless("LOCAL_CHAT", event.getPlayer().getDisplayName(), event.getMessage());
|
||||
}
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
private void onChat(AsyncPlayerChatEvent event) {
|
||||
event.setCancelled(true);
|
||||
Core.MESSAGE.broadcastPrefixless("LOCAL_CHAT", event.getPlayer().getDisplayName(), event.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,28 +34,29 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
@Linked
|
||||
public class PlayerJoinedEvent implements Listener{
|
||||
public class PlayerJoinedEvent implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
private void onJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
SteamwarUser user = Statement.productionDatabase() ? SteamwarUser.get(player.getUniqueId()) : SteamwarUser.getOrCreate(player.getUniqueId(), player.getName(), uuid -> {});
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
private void onJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
SteamwarUser user = Statement.productionDatabase() ? SteamwarUser.get(player.getUniqueId()) : SteamwarUser.getOrCreate(player.getUniqueId(), player.getName(), uuid -> {
|
||||
});
|
||||
|
||||
UserPerm.Prefix prefix = user.prefix();
|
||||
if(prefix != UserPerm.emptyPrefix) {
|
||||
player.setDisplayName(prefix.getColorCode() + prefix.getChatPrefix() + " " + player.getName() + "§r");
|
||||
} else
|
||||
player.setDisplayName(prefix.getColorCode() + player.getName() + "§r");
|
||||
UserPerm.Prefix prefix = user.prefix();
|
||||
if (prefix != UserPerm.emptyPrefix) {
|
||||
player.setDisplayName(prefix.getColorCode() + prefix.getChatPrefix() + " " + player.getName() + "§r");
|
||||
} else
|
||||
player.setDisplayName(prefix.getColorCode() + player.getName() + "§r");
|
||||
|
||||
event.setJoinMessage("§a§l» §r" + player.getDisplayName());
|
||||
AuditLog.createJoin(Core.getServerName(), BauServerInfo.getOwnerUser(), user);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
private void onQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
event.setJoinMessage("§a§l» §r" + player.getDisplayName());
|
||||
AuditLog.createJoin(Core.getServerName(), BauServerInfo.getOwnerUser(), user);
|
||||
}
|
||||
|
||||
event.setQuitMessage("§c§l« §r" + player.getDisplayName());
|
||||
AuditLog.createLeave(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(player.getUniqueId()));
|
||||
}
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
private void onQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
event.setQuitMessage("§c§l« §r" + player.getDisplayName());
|
||||
AuditLog.createLeave(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(player.getUniqueId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ import org.bukkit.event.world.WorldInitEvent;
|
||||
public class WorldLoadEvent implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onWorldInit(WorldInitEvent e){
|
||||
if(Integer.parseInt(System.getProperty("fightID", "0")) != -1) // On testarenas not
|
||||
public void onWorldInit(WorldInitEvent e) {
|
||||
if (Integer.parseInt(System.getProperty("fightID", "0")) != -1) // On testarenas not
|
||||
e.getWorld().setKeepSpawnInMemory(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ public class CLine extends CEntity {
|
||||
}
|
||||
|
||||
private RBlockDisplay startLine;
|
||||
|
||||
private void updateStart() {
|
||||
Vector vec = to.clone().subtract(from).toVector();
|
||||
if (vec.length() > 35) vec.normalize().multiply(35);
|
||||
@@ -145,6 +146,7 @@ public class CLine extends CEntity {
|
||||
}
|
||||
|
||||
private RBlockDisplay middleLine;
|
||||
|
||||
private void updateMiddle() {
|
||||
Vector vec = to.clone().subtract(from).toVector();
|
||||
if (vec.length() <= 70) {
|
||||
@@ -228,6 +230,7 @@ public class CLine extends CEntity {
|
||||
}
|
||||
|
||||
private RBlockDisplay endLine;
|
||||
|
||||
private void updateEnd() {
|
||||
Vector vec = to.clone().subtract(from).toVector();
|
||||
if (vec.length() <= 35) {
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.VersionDependent;
|
||||
|
||||
public interface PacketConstructor {
|
||||
PacketConstructor impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
|
||||
Object teleportPacket(int entityId, double x, double y, double z, float yaw, float pitch);
|
||||
Object createRPlayerSpawn(RPlayer player);
|
||||
}
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import de.steamwar.core.Core;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
@@ -29,26 +29,7 @@ import java.util.function.Consumer;
|
||||
|
||||
public class RArmorStand extends REntity {
|
||||
|
||||
private static int sizeIndex() {
|
||||
switch(Core.getVersion()) {
|
||||
case 8:
|
||||
case 9:
|
||||
return 10;
|
||||
case 10:
|
||||
case 12:
|
||||
return 11;
|
||||
case 14:
|
||||
return 13;
|
||||
case 15:
|
||||
return 14;
|
||||
case 18:
|
||||
case 19:
|
||||
default:
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Object sizeWatcher = BountifulWrapper.impl.getDataWatcherObject(sizeIndex(), Byte.class);
|
||||
private static final EntityDataAccessor<Byte> sizeWatcher = new EntityDataAccessor<>(15, EntityDataSerializers.BYTE);
|
||||
|
||||
@Getter
|
||||
private final Size size;
|
||||
@@ -63,8 +44,9 @@ public class RArmorStand extends REntity {
|
||||
void spawn(Consumer<Object> packetSink) {
|
||||
super.spawn(packetSink);
|
||||
|
||||
if(size != null && size != Size.NORMAL)
|
||||
if (size != null && size != Size.NORMAL) {
|
||||
packetSink.accept(getDataWatcherPacket(sizeWatcher, size.value));
|
||||
}
|
||||
}
|
||||
|
||||
public enum Size {
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import de.steamwar.core.Core;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -58,12 +59,11 @@ public class RBlockDisplay extends RDisplay {
|
||||
sendPacket(updatePacketSink, this::getBlock);
|
||||
}
|
||||
|
||||
private static final Class<?> iBlockDataClass = Reflection.getClass("net.minecraft.world.level.block.state.BlockState");
|
||||
private static final Reflection.Method getState = Reflection.getTypedMethod(Reflection.getClass("org.bukkit.craftbukkit.block.data.CraftBlockData"), "getState", iBlockDataClass);
|
||||
private static final Object blockWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 23 : 22, iBlockDataClass);
|
||||
private static final EntityDataAccessor<BlockState> blockWatcher = new EntityDataAccessor<>(23, EntityDataSerializers.BLOCK_STATE);
|
||||
|
||||
private void getBlock(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || !block.getAsString(true).equals(DEFAULT_BLOCK.getAsString(true))) {
|
||||
packetSink.accept(blockWatcher, getState.invoke(block));
|
||||
packetSink.accept(blockWatcher, ((CraftBlockData) block).getState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import de.steamwar.core.Core;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Display;
|
||||
@@ -36,9 +36,6 @@ import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* !! This class cannot be used in Versions lower than or equal to 1.19.4 !!
|
||||
*/
|
||||
@Getter
|
||||
public abstract class RDisplay extends REntity {
|
||||
|
||||
@@ -111,10 +108,10 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getTransformData);
|
||||
}
|
||||
|
||||
private static final Object translationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 11 : 10, Vector3f.class);
|
||||
private static final Object leftRotationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 13 : 12, Quaternionf.class);
|
||||
private static final Object scaleWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 12 : 11, Vector3f.class);
|
||||
private static final Object rightRotationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 14 : 13, Quaternionf.class);
|
||||
private static final EntityDataAccessor<Vector3f> translationWatcher = new EntityDataAccessor<>(11, EntityDataSerializers.VECTOR3);
|
||||
private static final EntityDataAccessor<Quaternionf> leftRotationWatcher = new EntityDataAccessor<>(13, EntityDataSerializers.QUATERNION);
|
||||
private static final EntityDataAccessor<Vector3f> scaleWatcher = new EntityDataAccessor<>(12, EntityDataSerializers.VECTOR3);
|
||||
private static final EntityDataAccessor<Quaternionf> rightRotationWatcher = new EntityDataAccessor<>(14, EntityDataSerializers.QUATERNION);
|
||||
|
||||
private void getTransformData(boolean ignoreDefault, BiConsumer<Object, Object> dataSink) {
|
||||
if (ignoreDefault || !transform.equals(DEFAULT_TRANSFORM)) {
|
||||
@@ -130,8 +127,8 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getInterpolationDuration);
|
||||
}
|
||||
|
||||
private static final Object transformationInterpolationDurationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 9 : 8, Integer.class);
|
||||
private static final Object positionOrRotationInterpolationDurationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 10 : 9, Integer.class);
|
||||
private static final EntityDataAccessor<Integer> transformationInterpolationDurationWatcher = new EntityDataAccessor<>(9, EntityDataSerializers.INT);
|
||||
private static final EntityDataAccessor<Integer> positionOrRotationInterpolationDurationWatcher = new EntityDataAccessor<>(10, EntityDataSerializers.INT);
|
||||
|
||||
private void getInterpolationDuration(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || interpolationDelay != 0) {
|
||||
@@ -145,7 +142,7 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getViewRange);
|
||||
}
|
||||
|
||||
private static final Object viewRangeWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 17 : 16, Float.class);
|
||||
private static final EntityDataAccessor<Float> viewRangeWatcher = new EntityDataAccessor<>(17, EntityDataSerializers.FLOAT);
|
||||
|
||||
private void getViewRange(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || viewRange != 1.0F) {
|
||||
@@ -158,7 +155,7 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getShadowRadius);
|
||||
}
|
||||
|
||||
private static final Object shadowRadiusWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 18 : 17, Float.class);
|
||||
private static final EntityDataAccessor<Float> shadowRadiusWatcher = new EntityDataAccessor<>(18, EntityDataSerializers.FLOAT);
|
||||
|
||||
private void getShadowRadius(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || shadowRadius != 0.0F) {
|
||||
@@ -171,7 +168,7 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getShadowStrength);
|
||||
}
|
||||
|
||||
private static final Object shadowStrengthWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 19 : 18, Float.class);
|
||||
private static final EntityDataAccessor<Float> shadowStrengthWatcher = new EntityDataAccessor<>(19, EntityDataSerializers.FLOAT);
|
||||
|
||||
private void getShadowStrength(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || shadowStrength != 1.0F) {
|
||||
@@ -184,7 +181,7 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getDisplayWidth);
|
||||
}
|
||||
|
||||
private static final Object displayWidthWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 20 : 19, Float.class);
|
||||
private static final EntityDataAccessor<Float> displayWidthWatcher = new EntityDataAccessor<>(20, EntityDataSerializers.FLOAT);
|
||||
|
||||
private void getDisplayWidth(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || displayWidth != 0.0F) {
|
||||
@@ -197,7 +194,7 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getDisplayHeight);
|
||||
}
|
||||
|
||||
private static final Object displayHeightWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 21 : 20, Float.class);
|
||||
private static final EntityDataAccessor<Float> displayHeightWatcher = new EntityDataAccessor<>(21, EntityDataSerializers.FLOAT);
|
||||
|
||||
private void getDisplayHeight(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || displayHeight != 0.0F) {
|
||||
@@ -210,7 +207,7 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getInterpolationDelay);
|
||||
}
|
||||
|
||||
private static final Object interpolationDelayWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 8 : 7, Integer.class);
|
||||
private static final EntityDataAccessor<Integer> interpolationDelayWatcher = new EntityDataAccessor<>(8, EntityDataSerializers.INT);
|
||||
|
||||
private void getInterpolationDelay(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || interpolationDelay != 0) {
|
||||
@@ -223,7 +220,7 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getBillboard);
|
||||
}
|
||||
|
||||
private static final Object billboardWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 15 : 14, Byte.class);
|
||||
private static final EntityDataAccessor<Byte> billboardWatcher = new EntityDataAccessor<>(15, EntityDataSerializers.BYTE);
|
||||
|
||||
private void getBillboard(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || billboard != Display.Billboard.FIXED) {
|
||||
@@ -236,7 +233,7 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getGlowColorOverride);
|
||||
}
|
||||
|
||||
private static final Object glowColorOverrideWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 22 : 21, Integer.class);
|
||||
private static final EntityDataAccessor<Integer> glowColorOverrideWatcher = new EntityDataAccessor<>(22, EntityDataSerializers.INT);
|
||||
|
||||
private void getGlowColorOverride(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || glowColorOverride != null) {
|
||||
@@ -249,7 +246,7 @@ public abstract class RDisplay extends REntity {
|
||||
sendPacket(updatePacketSink, this::getBrightness);
|
||||
}
|
||||
|
||||
private static final Object brightnessWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 16 : 15, Integer.class);
|
||||
private static final EntityDataAccessor<Integer> brightnessWatcher = new EntityDataAccessor<>(16, EntityDataSerializers.INT);
|
||||
|
||||
private void getBrightness(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || brightness != null) {
|
||||
|
||||
@@ -19,12 +19,26 @@
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.core.*;
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import de.steamwar.core.FlatteningWrapper;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.game.*;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.Pose;
|
||||
import net.minecraft.world.entity.PositionMoveRotation;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@@ -34,13 +48,11 @@ import java.util.function.Function;
|
||||
|
||||
public class REntity {
|
||||
|
||||
private static final Object entityStatusWatcher = BountifulWrapper.impl.getDataWatcherObject(0, Byte.class);
|
||||
private static final Object sneakingDataWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() > 12 ? 6 : 0, FlatteningWrapper.impl.getPose(FlatteningWrapper.EntityPose.NORMAL).getClass());
|
||||
private static final Object bowDrawnWatcher = Core.getVersion() >= 21 ? BountifulWrapper.impl.getDataWatcherObject(6, FlatteningWrapper.impl.getPose(FlatteningWrapper.EntityPose.NORMAL).getClass()) : BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() > 12 ? 7 : 6, Byte.class);
|
||||
private static final Object nameWatcher = BountifulWrapper.impl.getDataWatcherObject(2, Core.getVersion() > 12 ? Optional.class : String.class); // Optional<IChatBaseComponent>
|
||||
private static final Object nameVisibleWatcher = BountifulWrapper.impl.getDataWatcherObject(3, Boolean.class);
|
||||
|
||||
private static final Object noGravityDataWatcher = BountifulWrapper.impl.getDataWatcherObject(5,Boolean.class);
|
||||
private static final EntityDataAccessor<Byte> entityStatusWatcher = new EntityDataAccessor<>(0, EntityDataSerializers.BYTE);
|
||||
private static final EntityDataAccessor<Pose> poseDataWatcher = new EntityDataAccessor<>(6, EntityDataSerializers.POSE);
|
||||
private static final EntityDataAccessor<Optional<Component>> nameWatcher = new EntityDataAccessor<>(2, EntityDataSerializers.OPTIONAL_COMPONENT);
|
||||
private static final EntityDataAccessor<Boolean> nameVisibleWatcher = new EntityDataAccessor<>(3, EntityDataSerializers.BOOLEAN);
|
||||
private static final EntityDataAccessor<Boolean> noGravityDataWatcher = new EntityDataAccessor<>(5, EntityDataSerializers.BOOLEAN);
|
||||
|
||||
private static int entityIdCounter = -1;
|
||||
private static final Random random = new Random();
|
||||
@@ -67,11 +79,12 @@ public class REntity {
|
||||
@Getter
|
||||
private boolean invisible;
|
||||
@Getter
|
||||
private FlatteningWrapper.EntityPose pose = FlatteningWrapper.EntityPose.NORMAL;
|
||||
private Pose pose = Pose.STANDING;
|
||||
@Getter
|
||||
private boolean bowDrawn;
|
||||
@Getter
|
||||
private boolean noGravity;
|
||||
@Getter
|
||||
private boolean isGlowing;
|
||||
private int fireTick;
|
||||
|
||||
@@ -81,15 +94,15 @@ public class REntity {
|
||||
protected final Map<Object, ItemStack> itemSlots;
|
||||
|
||||
public REntity(REntityServer server, EntityType entityType, Location location) {
|
||||
this(server,entityType,location,0);
|
||||
this(server, entityType, location, 0);
|
||||
server.addEntity(this);
|
||||
}
|
||||
|
||||
protected REntity(REntityServer server, EntityType entityType, Location location,int objectData) {
|
||||
this(server, entityType, new UUID(random.nextLong() & -61441L | 16384L, random.nextLong() & 4611686018427387903L | -9223372036854775808L), location,objectData);
|
||||
protected REntity(REntityServer server, EntityType entityType, Location location, int objectData) {
|
||||
this(server, entityType, new UUID(random.nextLong() & -61441L | 16384L, random.nextLong() & 4611686018427387903L | -9223372036854775808L), location, objectData);
|
||||
}
|
||||
|
||||
protected REntity(REntityServer server, EntityType entityType, UUID uuid, Location location,int objectData) {
|
||||
protected REntity(REntityServer server, EntityType entityType, UUID uuid, Location location, int objectData) {
|
||||
this.server = server;
|
||||
this.entityType = entityType;
|
||||
this.entityId = entityIdCounter--;
|
||||
@@ -110,10 +123,9 @@ public class REntity {
|
||||
}
|
||||
|
||||
public void hide(boolean hide) {
|
||||
if(hidden == hide)
|
||||
return;
|
||||
if (hidden == hide) return;
|
||||
|
||||
if(hide) {
|
||||
if (hide) {
|
||||
despawn(packet -> server.updateEntity(this, packet));
|
||||
hidden = true;
|
||||
} else {
|
||||
@@ -126,7 +138,8 @@ public class REntity {
|
||||
move(location.getX(), location.getY(), location.getZ(), location.getPitch(), location.getYaw(), rotToByte(location.getYaw()));
|
||||
}
|
||||
|
||||
private static final double MAX_REL_MOVE = Core.getVersion() > 8 ? 8.0 : 4.0;
|
||||
private static final double MAX_REL_MOVE = 8.0;
|
||||
|
||||
public void move(double locX, double locY, double locZ, float pitch, float yaw, byte headYaw) {
|
||||
server.preEntityMove(this, locX, locZ);
|
||||
|
||||
@@ -143,16 +156,17 @@ public class REntity {
|
||||
this.yaw = rotToByte(yaw);
|
||||
this.pitch = rotToByte(pitch);
|
||||
|
||||
if(Math.abs(diffX) < MAX_REL_MOVE && Math.abs(diffY) < MAX_REL_MOVE && Math.abs(diffZ) < MAX_REL_MOVE) {
|
||||
Object packet = getMoveLookPacket(diffX, diffY, diffZ,rotEq);
|
||||
if (Math.abs(diffX) < MAX_REL_MOVE && Math.abs(diffY) < MAX_REL_MOVE && Math.abs(diffZ) < MAX_REL_MOVE) {
|
||||
Object packet = getMoveLookPacket(diffX, diffY, diffZ, rotEq);
|
||||
|
||||
if(packet != null)
|
||||
if (packet != null) {
|
||||
server.updateEntity(this, packet);
|
||||
}
|
||||
} else {
|
||||
server.updateEntity(this, getTeleportPacket());
|
||||
}
|
||||
|
||||
if(this.headYaw != headYaw) {
|
||||
if (this.headYaw != headYaw) {
|
||||
this.headYaw = headYaw;
|
||||
server.updateEntity(this, getHeadRotationPacket());
|
||||
}
|
||||
@@ -160,9 +174,10 @@ public class REntity {
|
||||
server.postEntityMove(this, fromX, fromZ);
|
||||
}
|
||||
|
||||
private static final Class<?> animationPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundAnimatePacket");
|
||||
private static final Reflection.Field<Integer> animationEntity = Reflection.getField(animationPacket, int.class, Core.getVersion() > 15 ? (Core.getVersion() > 19 ? 5 : 6) : 0);
|
||||
private static final Reflection.Field<Integer> animationAnimation = Reflection.getField(animationPacket, int.class, Core.getVersion() > 15 ? (Core.getVersion() > 19 ? 6 : 7) : 1);
|
||||
private static final Class<?> animationPacket = ClientboundAnimatePacket.class;
|
||||
private static final Reflection.Field<Integer> animationEntity = Reflection.getField(animationPacket, int.class, 5);
|
||||
private static final Reflection.Field<Integer> animationAnimation = Reflection.getField(animationPacket, int.class, 6);
|
||||
|
||||
public void showAnimation(byte animation) {
|
||||
Object packet = Reflection.newInstance(animationPacket);
|
||||
animationEntity.set(packet, entityId);
|
||||
@@ -170,23 +185,14 @@ public class REntity {
|
||||
server.updateEntity(this, packet);
|
||||
}
|
||||
|
||||
private static final Class<?> velocityPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket");
|
||||
private static final Reflection.Field<Integer> velocityEntity = Reflection.getField(velocityPacket, int.class, 0);
|
||||
private static final Reflection.Field<Integer> velocityX = Reflection.getField(velocityPacket, int.class, 1);
|
||||
private static final Reflection.Field<Integer> velocityY = Reflection.getField(velocityPacket, int.class, 2);
|
||||
private static final Reflection.Field<Integer> velocityZ = Reflection.getField(velocityPacket, int.class, 3);
|
||||
public void setVelocity(double dX, double dY, double dZ) {
|
||||
Object packet = Reflection.newInstance(velocityPacket);
|
||||
velocityEntity.set(packet, entityId);
|
||||
velocityX.set(packet, calcVelocity(dX));
|
||||
velocityY.set(packet, calcVelocity(dY));
|
||||
velocityZ.set(packet, calcVelocity(dZ));
|
||||
server.updateEntity(this, packet);
|
||||
server.updateEntity(this, new ClientboundSetEntityMotionPacket(entityId, new Vec3(calcVelocity(dX), calcVelocity(dY), calcVelocity(dZ))));
|
||||
}
|
||||
|
||||
private static final Class<?> statusPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundEntityEventPacket");
|
||||
private static final Class<?> statusPacket = ClientboundEntityEventPacket.class;
|
||||
private static final Reflection.Field<Integer> statusEntity = Reflection.getField(statusPacket, int.class, 0);
|
||||
private static final Reflection.Field<Byte> statusStatus = Reflection.getField(statusPacket, byte.class, 0);
|
||||
|
||||
public void showDamage() {
|
||||
Object packet = Reflection.newInstance(statusPacket);
|
||||
statusEntity.set(packet, entityId);
|
||||
@@ -194,13 +200,9 @@ public class REntity {
|
||||
server.updateEntity(this, packet);
|
||||
}
|
||||
|
||||
public void setPose(FlatteningWrapper.EntityPose pose) {
|
||||
public void setPose(Pose pose) {
|
||||
this.pose = pose;
|
||||
if(Core.getVersion() > 12) {
|
||||
server.updateEntity(this, getDataWatcherPacket(sneakingDataWatcher, FlatteningWrapper.impl.getPose(pose)));
|
||||
} else {
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
server.updateEntity(this, getDataWatcherPacket(poseDataWatcher, pose));
|
||||
}
|
||||
|
||||
public void setOnFire(boolean perma) {
|
||||
@@ -219,19 +221,13 @@ public class REntity {
|
||||
|
||||
public void setBowDrawn(boolean drawn, boolean offHand) {
|
||||
bowDrawn = drawn;
|
||||
if (Core.getVersion() >= 21) {
|
||||
server.updateEntity(this, getDataWatcherPacket(bowDrawnWatcher, FlatteningWrapper.impl.getPose(FlatteningWrapper.EntityPose.SHOOTING)));
|
||||
} else if(Core.getVersion() > 8){
|
||||
server.updateEntity(this, getDataWatcherPacket(bowDrawnWatcher, (byte) ((drawn ? 1 : 0) + (offHand ? 2 : 0))));
|
||||
}else{
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
server.updateEntity(this, getDataWatcherPacket(poseDataWatcher, Pose.SHOOTING));
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
server.updateEntity(this, getDataWatcherPacket(
|
||||
nameWatcher, FlatteningWrapper.impl.formatDisplayName(displayName),
|
||||
nameWatcher, FlatteningWrapper.formatDisplayName(displayName),
|
||||
nameVisibleWatcher, displayName != null
|
||||
));
|
||||
}
|
||||
@@ -247,55 +243,18 @@ public class REntity {
|
||||
|
||||
public void setNoGravity(boolean noGravity) {
|
||||
this.noGravity = noGravity;
|
||||
if(Core.getVersion() > 8)
|
||||
server.updateEntity(this,getDataWatcherPacket(noGravityDataWatcher,noGravity));
|
||||
server.updateEntity(this, getDataWatcherPacket(noGravityDataWatcher, noGravity));
|
||||
}
|
||||
|
||||
public void setGlowing(boolean glowing) {
|
||||
this.isGlowing = glowing;
|
||||
if(Core.getVersion() > 8) {
|
||||
server.updateEntity(this,getDataWatcherPacket(entityStatusWatcher,getEntityStatus()));
|
||||
}
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
|
||||
public boolean isGlowing() {
|
||||
return isGlowing;
|
||||
}
|
||||
private static final Function<REntity, Object> spawnPacketGenerator = entitySpawnPacketGenerator(ClientboundAddEntityPacket.class, 2);
|
||||
|
||||
private static final Reflection.Field<Integer> additionalData = Reflection.getField(ClientboundAddEntityPacket.class, int.class, 4);
|
||||
|
||||
private static int spawnPacketOffset() {
|
||||
switch (Core.getVersion()) {
|
||||
case 8:
|
||||
case 18:
|
||||
return 1;
|
||||
case 9:
|
||||
case 10:
|
||||
case 12:
|
||||
case 14:
|
||||
case 15:
|
||||
return 0;
|
||||
case 19:
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
private static final Function<REntity, Object> spawnPacketGenerator = entitySpawnPacketGenerator(ProtocolWrapper.spawnPacket, spawnPacketOffset());
|
||||
private static int objectDataOffset() {
|
||||
switch (Core.getVersion()) {
|
||||
case 8:
|
||||
return 9;
|
||||
case 9:
|
||||
case 14:
|
||||
case 12:
|
||||
case 10:
|
||||
case 15:
|
||||
case 18:
|
||||
return 6;
|
||||
case 19:
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
private static final Reflection.Field<Integer> additionalData = Reflection.getField(ProtocolWrapper.spawnPacket, int.class, objectDataOffset());
|
||||
private Object spawnPacketGenerator() {
|
||||
Object packet = spawnPacketGenerator.apply(this);
|
||||
additionalData.set(packet, objectData);
|
||||
@@ -306,60 +265,45 @@ public class REntity {
|
||||
// empty for regular entity
|
||||
}
|
||||
|
||||
private static final Function<REntity, Object> livingSpawnPacketGenerator = Core.getVersion() >= 19 ? REntity::spawnPacketGenerator : entitySpawnPacketGenerator(ProtocolWrapper.spawnLivingPacket, Core.getVersion() == 8 ? 2 : 0);
|
||||
void spawn(Consumer<Object> packetSink) {
|
||||
if(entityType.isAlive()) {
|
||||
packetSink.accept(livingSpawnPacketGenerator.apply(this));
|
||||
} else {
|
||||
packetSink.accept(spawnPacketGenerator());
|
||||
}
|
||||
|
||||
packetSink.accept(spawnPacketGenerator());
|
||||
postSpawn(packetSink);
|
||||
}
|
||||
|
||||
protected void postSpawn(Consumer<Object> packetSink) {
|
||||
if(headYaw != 0) {
|
||||
if (headYaw != 0) {
|
||||
packetSink.accept(getHeadRotationPacket());
|
||||
}
|
||||
|
||||
if(Core.getVersion() > 12 && pose != FlatteningWrapper.EntityPose.NORMAL) {
|
||||
packetSink.accept(getDataWatcherPacket(sneakingDataWatcher, FlatteningWrapper.impl.getPose(pose)));
|
||||
if (pose != Pose.STANDING) {
|
||||
packetSink.accept(getDataWatcherPacket(poseDataWatcher, pose));
|
||||
}
|
||||
|
||||
byte status = getEntityStatus();
|
||||
if(status != 0) {
|
||||
if (status != 0) {
|
||||
packetSink.accept(getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
|
||||
if(displayName != null) {
|
||||
packetSink.accept(getDataWatcherPacket(nameWatcher, FlatteningWrapper.impl.formatDisplayName(displayName), nameVisibleWatcher, true));
|
||||
if (displayName != null) {
|
||||
packetSink.accept(getDataWatcherPacket(nameWatcher, FlatteningWrapper.formatDisplayName(displayName), nameVisibleWatcher, true));
|
||||
}
|
||||
|
||||
if(Core.getVersion() > 8 && noGravity)
|
||||
if (noGravity) {
|
||||
packetSink.accept(getDataWatcherPacket(noGravityDataWatcher, true));
|
||||
}
|
||||
}
|
||||
|
||||
void tick() {
|
||||
if(fireTick > 0) {
|
||||
if (fireTick > 0) {
|
||||
fireTick--;
|
||||
if(fireTick == 0) {
|
||||
if (fireTick == 0) {
|
||||
server.updateEntity(this, getDataWatcherPacket(entityStatusWatcher, getEntityStatus()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> destroyPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket");
|
||||
private static final Reflection.Field<?> destroyEntities;
|
||||
static {
|
||||
if(Core.getVersion() > 15)
|
||||
destroyEntities = Reflection.getField(destroyPacket, IntList.class, 0);
|
||||
else
|
||||
destroyEntities = Reflection.getField(destroyPacket, int[].class, 0);
|
||||
}
|
||||
void despawn(Consumer<Object> packetSink){
|
||||
Object packet = Reflection.newInstance(destroyPacket);
|
||||
destroyEntities.set(packet, Core.getVersion() > 15 ? new IntArrayList(new int[]{entityId}) : new int[]{entityId});
|
||||
packetSink.accept(packet);
|
||||
void despawn(Consumer<Object> packetSink) {
|
||||
packetSink.accept(new ClientboundRemoveEntitiesPacket(new IntArrayList(new int[]{entityId})));
|
||||
}
|
||||
|
||||
void delist(Consumer<Object> packetSink) {
|
||||
@@ -377,86 +321,61 @@ public class REntity {
|
||||
private byte getEntityStatus() {
|
||||
byte status = 0;
|
||||
|
||||
if(fireTick != 0)
|
||||
status |= 1;
|
||||
if(pose == FlatteningWrapper.EntityPose.SNEAKING)
|
||||
status |= 2;
|
||||
if(Core.getVersion() == 8 && bowDrawn)
|
||||
status |= 0x10;
|
||||
if(invisible)
|
||||
status |= 0x20;
|
||||
if(Core.getVersion() > 8 && isGlowing)
|
||||
status |= 0x40;
|
||||
|
||||
if (fireTick != 0) status |= 1;
|
||||
if (pose == Pose.CROUCHING) status |= 2;
|
||||
if (invisible) status |= 0x20;
|
||||
if (isGlowing) status |= 0x40;
|
||||
return status;
|
||||
}
|
||||
|
||||
protected Object getDataWatcherPacket(Object... dataWatcherKeyValues) {
|
||||
return ChatWrapper.impl.getDataWatcherPacket(entityId, dataWatcherKeyValues);
|
||||
}
|
||||
|
||||
public static final Class<?> teleportPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket");
|
||||
public static final Reflection.Field<Integer> teleportEntity = Reflection.getField(teleportPacket, int.class, 0);
|
||||
public static final BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, Core.getVersion() == 8 ? 1 : 0);
|
||||
private Object getTeleportPacket(){
|
||||
if (Core.getVersion() >= 21) {
|
||||
return PacketConstructor.impl.teleportPacket(entityId, x, y, z, pitch, yaw);
|
||||
ArrayList<SynchedEntityData.DataValue<?>> nativeWatchers = new ArrayList<>(1);
|
||||
for (int i = 0; i < dataWatcherKeyValues.length; i += 2) {
|
||||
nativeWatchers.add(((SynchedEntityData.DataItem<?>) BountifulWrapper.impl.getDataWatcherItem(dataWatcherKeyValues[i], dataWatcherKeyValues[i + 1])).value());
|
||||
}
|
||||
|
||||
Object packet = Reflection.newInstance(teleportPacket);
|
||||
teleportEntity.set(packet, entityId);
|
||||
teleportPosition.set(packet, x, y, z, pitch, yaw);
|
||||
return packet;
|
||||
return new ClientboundSetEntityDataPacket(entityId, nativeWatchers);
|
||||
}
|
||||
|
||||
private Object getTeleportPacket() {
|
||||
PositionMoveRotation rot = new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, pitch, yaw);
|
||||
return new ClientboundTeleportEntityPacket(entityId, rot, Collections.emptySet(), false);
|
||||
}
|
||||
|
||||
private static final Class<?> entityPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket");
|
||||
private static final Reflection.Field<Integer> moveEntityId = Reflection.getField(entityPacket, int.class, 0);
|
||||
private static final BountifulWrapper.PositionSetter movePosition = BountifulWrapper.impl.getRelMoveSetter(entityPacket);
|
||||
private static final Class<?> lookPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Rot");
|
||||
private static final Class<?> movePacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Pos");
|
||||
private static final Class<?> moveLookPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$PosRot");
|
||||
private Object getMoveLookPacket(double diffX, double diffY, double diffZ, boolean rotEq) {
|
||||
Class<?> clazz;
|
||||
if(diffX == 0 && diffY == 0 && diffZ == 0) {
|
||||
if(rotEq)
|
||||
return null;
|
||||
short x = (short) (this.x * 4096);
|
||||
short y = (short) (this.y * 4096);
|
||||
short z = (short) (this.z * 4096);
|
||||
byte yaw = (byte) (this.yaw * 256 / 360);
|
||||
byte pitch = (byte) (this.pitch * 256 / 360);
|
||||
|
||||
clazz = lookPacket;
|
||||
if (diffX == 0 && diffY == 0 && diffZ == 0) {
|
||||
if (rotEq) return null;
|
||||
return new ClientboundMoveEntityPacket.Rot(entityId, pitch, yaw, false);
|
||||
} else if (rotEq) {
|
||||
clazz = movePacket;
|
||||
return new ClientboundMoveEntityPacket.Pos(entityId, x, y, z, false);
|
||||
} else {
|
||||
clazz = moveLookPacket;
|
||||
return new ClientboundMoveEntityPacket.PosRot(entityId, x, y, z, pitch, yaw, false);
|
||||
}
|
||||
|
||||
Object packet = Reflection.newInstance(clazz);
|
||||
moveEntityId.set(packet, entityId);
|
||||
movePosition.set(packet, diffX, diffY, diffZ, pitch, yaw);
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static final Class<?> headRotationPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundRotateHeadPacket");
|
||||
private static final Class<?> headRotationPacket = ClientboundRotateHeadPacket.class;
|
||||
private static final Reflection.Field<Integer> headRotationEntity = Reflection.getField(headRotationPacket, int.class, 0);
|
||||
private static final Reflection.Field<Byte> headRotationYaw = Reflection.getField(headRotationPacket, byte.class, 0);
|
||||
private Object getHeadRotationPacket(){
|
||||
|
||||
private Object getHeadRotationPacket() {
|
||||
Object packet = Reflection.newInstance(headRotationPacket);
|
||||
headRotationEntity.set(packet, entityId);
|
||||
headRotationYaw.set(packet, headYaw);
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static final Reflection.Field<Integer> equipmentEntity = Reflection.getField(ProtocolWrapper.equipmentPacket, int.class, 0);
|
||||
private static final Reflection.Field<List> equipmentSlots = Reflection.getField(ProtocolWrapper.equipmentPacket, List.class, 0);
|
||||
|
||||
private static final Class<?> craftItemStack = Reflection.getClass("org.bukkit.craftbukkit.inventory.CraftItemStack");
|
||||
protected static final Reflection.Method asNMSCopy = Reflection.getTypedMethod(REntity.craftItemStack, "asNMSCopy", ProtocolWrapper.itemStack, ItemStack.class);
|
||||
protected Object getEquipmentPacket(Object slot, ItemStack stack){
|
||||
Object packet = Reflection.newInstance(ProtocolWrapper.equipmentPacket);
|
||||
equipmentEntity.set(packet, entityId);
|
||||
equipmentSlots.set(packet, new ArrayList<>());
|
||||
ProtocolWrapper.impl.setEquipmentPacketStack(packet, slot, asNMSCopy.invoke(null, stack));
|
||||
return packet;
|
||||
protected Object getEquipmentPacket(Object slot, ItemStack stack) {
|
||||
return new ClientboundSetEquipmentPacket(entityId, Collections.singletonList(Pair.of((EquipmentSlot) slot, CraftItemStack.asNMSCopy(stack))));
|
||||
}
|
||||
|
||||
private static final Reflection.Field<net.minecraft.world.entity.EntityType> spawnType = Reflection.getField(ClientboundAddEntityPacket.class, net.minecraft.world.entity.EntityType.class, 0);
|
||||
|
||||
private static Function<REntity, Object> entitySpawnPacketGenerator(Class<?> spawnPacket, int posOffset) {
|
||||
BountifulWrapper.UUIDSetter uuid = BountifulWrapper.impl.getUUIDSetter(spawnPacket);
|
||||
Function<REntity, Object> packetGenerator = spawnPacketGenerator(spawnPacket, posOffset);
|
||||
@@ -464,7 +383,8 @@ public class REntity {
|
||||
return entity -> {
|
||||
Object packet = packetGenerator.apply(entity);
|
||||
uuid.set(packet, entity.uuid);
|
||||
FlatteningWrapper.impl.setSpawnPacketType(packet, entity.entityType);
|
||||
ResourceLocation key = CraftNamespacedKey.toMinecraft(entity.entityType.getKey());
|
||||
spawnType.set(packet, BuiltInRegistries.ENTITY_TYPE.get(key).get().value());
|
||||
return packet;
|
||||
};
|
||||
}
|
||||
@@ -482,10 +402,10 @@ public class REntity {
|
||||
}
|
||||
|
||||
private byte rotToByte(float rot) {
|
||||
return (byte)((int)(rot * 256.0F / 360.0F));
|
||||
return (byte) ((int) (rot * 256.0F / 360.0F));
|
||||
}
|
||||
|
||||
private int calcVelocity(double value) {
|
||||
return (int)(Math.max(-3.9, Math.min(value, 3.9)) * 8000);
|
||||
return (int) (Math.max(-3.9, Math.min(value, 3.9)) * 8000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,9 @@
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.FlatteningWrapper;
|
||||
import net.minecraft.network.protocol.game.ServerboundInteractPacket;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -38,7 +37,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@@ -47,21 +45,6 @@ public class REntityServer implements Listener {
|
||||
private static final HashSet<REntity> emptyEntities = new HashSet<>(0);
|
||||
private static final HashSet<Player> emptyPlayers = new HashSet<>(0);
|
||||
|
||||
private static final Class<?> useEntity = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundInteractPacket");
|
||||
private static final Reflection.Field<Integer> useEntityTarget = Reflection.getField(useEntity, int.class, 0);
|
||||
private static final Class<?> useEntityEnumAction = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundInteractPacket$Action");
|
||||
private static final Reflection.Field<?> useEntityAction = Reflection.getField(useEntity, useEntityEnumAction, 0);
|
||||
private static final Function<Object, Integer> getEntityAction;
|
||||
static {
|
||||
if(Core.getVersion() > 15) {
|
||||
Class<?> useEntityEnumActionType = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundInteractPacket$ActionType");
|
||||
Reflection.Method useEntityGetAction = Reflection.getTypedMethod(useEntityEnumAction, null, useEntityEnumActionType);
|
||||
getEntityAction = value -> ((Enum<?>) useEntityGetAction.invoke(value)).ordinal();
|
||||
} else {
|
||||
getEntityAction = value -> ((Enum<?>) value).ordinal();
|
||||
}
|
||||
}
|
||||
|
||||
private final ConcurrentHashMap<Integer, REntity> entityMap = new ConcurrentHashMap<>();
|
||||
private final HashMap<Long, HashSet<REntity>> entities = new HashMap<>();
|
||||
private final HashMap<Long, Set<Player>> players = new HashMap<>();
|
||||
@@ -71,16 +54,14 @@ public class REntityServer implements Listener {
|
||||
private EntityActionListener callback = null;
|
||||
private final Set<Player> playersThatClicked = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
private final BiFunction<Player, Object, Object> filter = (player, packet) -> {
|
||||
REntity entity = entityMap.get(useEntityTarget.get(packet));
|
||||
if (entity == null)
|
||||
return packet;
|
||||
private final BiFunction<Player, ServerboundInteractPacket, Object> filter = (player, packet) -> {
|
||||
REntity entity = entityMap.get(packet.getEntityId());
|
||||
if (entity == null) return packet;
|
||||
|
||||
if (playersThatClicked.contains(player))
|
||||
return null;
|
||||
if (playersThatClicked.contains(player)) return null;
|
||||
|
||||
playersThatClicked.add(player);
|
||||
EntityAction action = getEntityAction.apply(useEntityAction.get(packet)) == 1 ? EntityAction.ATTACK : EntityAction.INTERACT;
|
||||
EntityAction action = packet.isAttack() ? EntityAction.ATTACK : EntityAction.INTERACT;
|
||||
Bukkit.getScheduler().runTask(Core.getInstance(), () -> {
|
||||
playersThatClicked.remove(player);
|
||||
callback.onAction(player, entity, action);
|
||||
@@ -96,8 +77,9 @@ public class REntityServer implements Listener {
|
||||
boolean uninitialized = this.callback == null;
|
||||
this.callback = callback;
|
||||
|
||||
if(uninitialized)
|
||||
TinyProtocol.instance.addFilter(useEntity, filter);
|
||||
if (uninitialized) {
|
||||
TinyProtocol.instance.addTypedFilter(ServerboundInteractPacket.class, filter);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPlayer(Player player) {
|
||||
@@ -120,8 +102,8 @@ public class REntityServer implements Listener {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
TinyProtocol.instance.removeFilter(useEntity, filter);
|
||||
for(Player player : lastLocation.keySet().toArray(new Player[0])) {
|
||||
TinyProtocol.instance.removeFilter(ServerboundInteractPacket.class, filter);
|
||||
for (Player player : lastLocation.keySet().toArray(new Player[0])) {
|
||||
removePlayer(player);
|
||||
}
|
||||
HandlerList.unregisterAll(this);
|
||||
@@ -137,11 +119,11 @@ public class REntityServer implements Listener {
|
||||
void preEntityMove(REntity entity, double toX, double toZ) {
|
||||
long fromId = entityToId(entity);
|
||||
long toId = posToId(toX, toZ);
|
||||
if(fromId == toId)
|
||||
return;
|
||||
if (fromId == toId) return;
|
||||
|
||||
if(!entity.isHidden())
|
||||
if (!entity.isHidden()) {
|
||||
onMissing(players.get(fromId), players.get(toId), entity::despawn);
|
||||
}
|
||||
onMissing(players.get(fromId), players.get(toId), entity::delist);
|
||||
removeEntityFromChunk(entity);
|
||||
}
|
||||
@@ -149,20 +131,19 @@ public class REntityServer implements Listener {
|
||||
void postEntityMove(REntity entity, double fromX, double fromZ) {
|
||||
long fromId = posToId(fromX, fromZ);
|
||||
long toId = entityToId(entity);
|
||||
if(fromId == toId)
|
||||
return;
|
||||
if (fromId == toId) return;
|
||||
|
||||
addEntityToChunk(entity);
|
||||
onMissing(players.get(toId), players.get(fromId), entity::list);
|
||||
if(!entity.isHidden())
|
||||
if (!entity.isHidden()) {
|
||||
onMissing(players.get(toId), players.get(fromId), entity::spawn);
|
||||
}
|
||||
}
|
||||
|
||||
void updateEntity(REntity entity, Object packet) {
|
||||
if(entity.isHidden())
|
||||
return;
|
||||
if (entity.isHidden()) return;
|
||||
|
||||
for(Player player : players.getOrDefault(entityToId(entity), emptyPlayers)) {
|
||||
for (Player player : players.getOrDefault(entityToId(entity), emptyPlayers)) {
|
||||
TinyProtocol.instance.sendPacket(player, packet);
|
||||
}
|
||||
}
|
||||
@@ -191,8 +172,7 @@ public class REntityServer implements Listener {
|
||||
HashSet<REntity> entitiesInChunk = entities.get(id);
|
||||
if (entitiesInChunk == null) return;
|
||||
entitiesInChunk.remove(entity);
|
||||
if(entitiesInChunk.isEmpty())
|
||||
entities.remove(id);
|
||||
if (entitiesInChunk.isEmpty()) entities.remove(id);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
@@ -200,28 +180,26 @@ public class REntityServer implements Listener {
|
||||
Player player = e.getPlayer();
|
||||
Location from = lastLocation.get(player);
|
||||
Location to = e.getTo();
|
||||
if(from == null || to == null)
|
||||
return;
|
||||
if (from == null || to == null) return;
|
||||
|
||||
int fromX = posToChunk(from.getX());
|
||||
int fromZ = posToChunk(from.getZ());
|
||||
int toX = posToChunk(to.getX());
|
||||
int toZ = posToChunk(to.getZ());
|
||||
if(fromX == toX && fromZ == toZ)
|
||||
return;
|
||||
if (fromX == toX && fromZ == toZ) return;
|
||||
|
||||
lastLocation.put(player, to);
|
||||
|
||||
int toViewDistance = viewRadius(player);
|
||||
forChunkInView(player, from, (x, z) -> {
|
||||
if(Math.abs(x - toX) > toViewDistance || Math.abs(z - toZ) > toViewDistance) {
|
||||
if (Math.abs(x - toX) > toViewDistance || Math.abs(z - toZ) > toViewDistance) {
|
||||
removePlayerFromChunk(player, x, z);
|
||||
}
|
||||
});
|
||||
|
||||
int fromViewDistance = this.viewDistance.put(player, toViewDistance);
|
||||
forChunkInView(player, to, (x, z) -> {
|
||||
if(Math.abs(x - fromX) > fromViewDistance || Math.abs(z - fromZ) > fromViewDistance) {
|
||||
if (Math.abs(x - fromX) > fromViewDistance || Math.abs(z - fromZ) > fromViewDistance) {
|
||||
addPlayerToChunk(player, x, z);
|
||||
}
|
||||
});
|
||||
@@ -231,25 +209,22 @@ public class REntityServer implements Listener {
|
||||
public void onQuit(PlayerQuitEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
Location location = lastLocation.remove(player);
|
||||
if(location == null)
|
||||
return;
|
||||
if (location == null) return;
|
||||
|
||||
forChunkInView(player, location, (x, z) -> {
|
||||
long id = chunkToId(x, z);
|
||||
Set<Player> playersInChunk = players.get(id);
|
||||
playersInChunk.remove(player);
|
||||
if(playersInChunk.isEmpty())
|
||||
players.remove(id);
|
||||
if (playersInChunk.isEmpty()) players.remove(id);
|
||||
});
|
||||
viewDistance.remove(player);
|
||||
}
|
||||
|
||||
private void onMissing(Set<Player> of, Set<Player> in, Consumer<Consumer<Object>> packetProvider) {
|
||||
if(of == null)
|
||||
return;
|
||||
if (of == null) return;
|
||||
|
||||
for(Player player : of) {
|
||||
if(in == null || !in.contains(player)) {
|
||||
for (Player player : of) {
|
||||
if (in == null || !in.contains(player)) {
|
||||
packetProvider.accept(packet -> TinyProtocol.instance.sendPacket(player, packet));
|
||||
}
|
||||
}
|
||||
@@ -260,8 +235,8 @@ public class REntityServer implements Listener {
|
||||
int chunkZ = posToChunk(location.getZ());
|
||||
int viewDistance = this.viewDistance.get(player);
|
||||
|
||||
for(int x = chunkX - viewDistance; x <= chunkX + viewDistance; x++) {
|
||||
for(int z = chunkZ - viewDistance; z <= chunkZ + viewDistance; z++) {
|
||||
for (int x = chunkX - viewDistance; x <= chunkX + viewDistance; x++) {
|
||||
for (int z = chunkZ - viewDistance; z <= chunkZ + viewDistance; z++) {
|
||||
func.accept(x, z);
|
||||
}
|
||||
}
|
||||
@@ -270,10 +245,11 @@ public class REntityServer implements Listener {
|
||||
private void addPlayerToChunk(Player player, int x, int z) {
|
||||
long id = chunkToId(x, z);
|
||||
players.computeIfAbsent(id, i -> new HashSet<>()).add(player);
|
||||
for(REntity entity : entities.getOrDefault(id, emptyEntities)) {
|
||||
for (REntity entity : entities.getOrDefault(id, emptyEntities)) {
|
||||
entity.list(packet -> TinyProtocol.instance.sendPacket(player, packet));
|
||||
if(!entity.isHidden())
|
||||
if (!entity.isHidden()) {
|
||||
entity.spawn(packet -> TinyProtocol.instance.sendPacket(player, packet));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,12 +258,12 @@ public class REntityServer implements Listener {
|
||||
|
||||
Set<Player> playersInChunk = players.get(id);
|
||||
playersInChunk.remove(player);
|
||||
if(playersInChunk.isEmpty())
|
||||
players.remove(id);
|
||||
if (playersInChunk.isEmpty()) players.remove(id);
|
||||
|
||||
for(REntity entity : entities.getOrDefault(id, emptyEntities)) {
|
||||
if(!entity.isHidden())
|
||||
for (REntity entity : entities.getOrDefault(id, emptyEntities)) {
|
||||
if (!entity.isHidden()) {
|
||||
entity.despawn(packet -> TinyProtocol.instance.sendPacket(player, packet));
|
||||
}
|
||||
entity.delist(packet -> TinyProtocol.instance.sendPacket(player, packet));
|
||||
}
|
||||
}
|
||||
@@ -299,11 +275,11 @@ public class REntityServer implements Listener {
|
||||
}
|
||||
|
||||
private int posToChunk(double coord) {
|
||||
return (int)(coord / 16) - (coord < 0 ? 1 : 0);
|
||||
return (int) (coord / 16) - (coord < 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
private int viewRadius(Player player) {
|
||||
return FlatteningWrapper.impl.getViewDistance(player) / 2;
|
||||
return player.getClientViewDistance() / 2;
|
||||
}
|
||||
|
||||
private long entityToId(REntity entity) {
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.techhider.BlockIds;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Location;
|
||||
@@ -27,12 +26,12 @@ import org.bukkit.Material;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
@Getter
|
||||
public class RFallingBlockEntity extends REntity{
|
||||
public class RFallingBlockEntity extends REntity {
|
||||
|
||||
private final Material material;
|
||||
|
||||
public RFallingBlockEntity(REntityServer server, Location location, Material material) {
|
||||
super(server, EntityType.FALLING_BLOCK, location, BlockIds.impl.materialToId(material) >> (Core.getVersion() <= 12 ? 4 : 0));
|
||||
super(server, EntityType.FALLING_BLOCK, location, BlockIds.impl.materialToId(material));
|
||||
this.material = material;
|
||||
server.addEntity(this);
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.ProtocolWrapper;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.ItemDisplay;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -61,14 +61,16 @@ public class RItemDisplay extends RDisplay {
|
||||
sendPacket(updatePacketSink, this::getItemStack);
|
||||
}
|
||||
|
||||
private static final Object itemStackWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 23 : 22, ProtocolWrapper.itemStack);
|
||||
private static final EntityDataAccessor<net.minecraft.world.item.ItemStack> itemStackWatcher = new EntityDataAccessor<>(23, EntityDataSerializers.ITEM_STACK);
|
||||
|
||||
private void getItemStack(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || !itemStack.equals(DEFAULT_ITEM_STACK)) {
|
||||
packetSink.accept(itemStackWatcher, asNMSCopy.invoke(null, itemStack));
|
||||
packetSink.accept(itemStackWatcher, CraftItemStack.asNMSCopy(itemStack));
|
||||
}
|
||||
}
|
||||
|
||||
private static final Object itemDisplayTransformWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 24 : 23, Byte.class);
|
||||
private static final EntityDataAccessor<Byte> itemDisplayTransformWatcher = new EntityDataAccessor<>(24, EntityDataSerializers.BYTE);
|
||||
|
||||
public void setItemDisplayTransform(ItemDisplay.ItemDisplayTransform itemDisplayTransform) {
|
||||
this.itemDisplayTransform = itemDisplayTransform;
|
||||
sendPacket(updatePacketSink, this::getItemDisplayTransform);
|
||||
|
||||
@@ -21,12 +21,14 @@ package de.steamwar.entity;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.core.*;
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import de.steamwar.core.ProtocolWrapper;
|
||||
import de.steamwar.network.CoreNetworkHandler;
|
||||
import de.steamwar.network.NetworkSender;
|
||||
import de.steamwar.network.packets.common.PlayerSkinRequestPacket;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
@@ -36,31 +38,10 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class RPlayer extends REntity {
|
||||
|
||||
private static int skinPartsIndex() {
|
||||
switch(Core.getVersion()) {
|
||||
case 8:
|
||||
return 10;
|
||||
case 9:
|
||||
return 12;
|
||||
case 10:
|
||||
case 12:
|
||||
return 13;
|
||||
case 14:
|
||||
return 15;
|
||||
case 15:
|
||||
return 16;
|
||||
case 18:
|
||||
case 19:
|
||||
default:
|
||||
return 17;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Object skinPartsDataWatcher = BountifulWrapper.impl.getDataWatcherObject(skinPartsIndex(), Byte.class);
|
||||
private static final Object skinPartsDataWatcher = BountifulWrapper.impl.getDataWatcherObject(17, Byte.class);
|
||||
|
||||
@Getter
|
||||
private final UUID actualUUID;
|
||||
@@ -68,7 +49,7 @@ public class RPlayer extends REntity {
|
||||
private final String name;
|
||||
|
||||
public RPlayer(REntityServer server, UUID uuid, String name, Location location) {
|
||||
super(server, EntityType.PLAYER, UUID.nameUUIDFromBytes(uuid.toString().getBytes(StandardCharsets.UTF_8)), location,0);
|
||||
super(server, EntityType.PLAYER, UUID.nameUUIDFromBytes(uuid.toString().getBytes(StandardCharsets.UTF_8)), location, 0);
|
||||
this.actualUUID = uuid;
|
||||
this.name = name;
|
||||
server.addEntity(this);
|
||||
@@ -79,7 +60,7 @@ public class RPlayer extends REntity {
|
||||
NetworkSender.sendOrQueue(new PlayerSkinRequestPacket(actualUUID));
|
||||
return new Property("textures", null, null);
|
||||
});
|
||||
if (TrickyTrialsWrapper.impl.getValue(skinData) != null) {
|
||||
if (skinData.value() != null) {
|
||||
GameProfile gameProfile = new GameProfile(uuid, name);
|
||||
gameProfile.getProperties().put("textures", skinData);
|
||||
return gameProfile;
|
||||
@@ -93,7 +74,7 @@ public class RPlayer extends REntity {
|
||||
@Override
|
||||
void list(Consumer<Object> packetSink) {
|
||||
saved = getGameProfile();
|
||||
packetSink.accept(ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.ADD, saved, GameMode.CREATIVE));
|
||||
packetSink.accept(ProtocolWrapper.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.ADD, saved, GameMode.CREATIVE));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -111,27 +92,22 @@ public class RPlayer extends REntity {
|
||||
@Override
|
||||
void delist(Consumer<Object> packetSink) {
|
||||
if (saved == null) saved = getGameProfile();
|
||||
packetSink.accept(ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.REMOVE, saved, GameMode.CREATIVE));
|
||||
}
|
||||
|
||||
private static Class<?> namedSpawnPacket = null;
|
||||
private static Function<REntity, Object> namedSpawnPacketGenerator = null;
|
||||
private static Reflection.Field<UUID> namedSpawnUUID = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
namedSpawnPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundAddPlayerPacket");
|
||||
namedSpawnPacketGenerator = spawnPacketGenerator(namedSpawnPacket, Core.getVersion() == 8 ? 1 : 0);
|
||||
namedSpawnUUID = Reflection.getField(namedSpawnPacket, UUID.class, 0);
|
||||
} catch (IllegalArgumentException e) { }
|
||||
packetSink.accept(ProtocolWrapper.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.REMOVE, saved, GameMode.CREATIVE));
|
||||
}
|
||||
|
||||
private Object getNamedSpawnPacket() {
|
||||
if (Core.getVersion() >= 21) return PacketConstructor.impl.createRPlayerSpawn(this);
|
||||
|
||||
Object packet = namedSpawnPacketGenerator.apply(this);
|
||||
namedSpawnUUID.set(packet, uuid);
|
||||
FlatteningWrapper.impl.setNamedSpawnPacketDataWatcher(packet);
|
||||
return packet;
|
||||
return new ClientboundAddEntityPacket(
|
||||
entityId,
|
||||
uuid,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
yaw,
|
||||
pitch,
|
||||
net.minecraft.world.entity.EntityType.PLAYER,
|
||||
0,
|
||||
Vec3.ZERO,
|
||||
headYaw
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import de.steamwar.core.ChatWrapper;
|
||||
import de.steamwar.core.Core;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.contents.PlainTextContents;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.TextDisplay;
|
||||
@@ -74,11 +75,11 @@ public class RTextDisplay extends RDisplay {
|
||||
sendPacket(updatePacketSink, this::getText);
|
||||
}
|
||||
|
||||
private static final Class<?> iChatBaseComponent = Reflection.getClass("net.minecraft.network.chat.Component");
|
||||
private static final Object textWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 23 : 22, iChatBaseComponent);
|
||||
private static final EntityDataAccessor<Component> textWatcher = new EntityDataAccessor<>(23, EntityDataSerializers.COMPONENT);
|
||||
|
||||
private void getText(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || !text.isEmpty()) {
|
||||
packetSink.accept(textWatcher, ChatWrapper.impl.stringToChatComponent(text));
|
||||
packetSink.accept(textWatcher, MutableComponent.create(PlainTextContents.create(text)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +88,8 @@ public class RTextDisplay extends RDisplay {
|
||||
sendPacket(updatePacketSink, this::getLineWidth);
|
||||
}
|
||||
|
||||
private static final Object lineWidthWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 24 : 23, Integer.class);
|
||||
private static final EntityDataAccessor<Integer> lineWidthWatcher = new EntityDataAccessor<>(24, EntityDataSerializers.INT);
|
||||
|
||||
private void getLineWidth(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || lineWidth != 200) {
|
||||
packetSink.accept(lineWidthWatcher, lineWidth);
|
||||
@@ -99,7 +101,8 @@ public class RTextDisplay extends RDisplay {
|
||||
sendPacket(updatePacketSink, this::getTextOpacity);
|
||||
}
|
||||
|
||||
private static final Object textOpacityWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 26 : 25, Byte.class);
|
||||
private static final EntityDataAccessor<Byte> textOpacityWatcher = new EntityDataAccessor<>(26, EntityDataSerializers.BYTE);
|
||||
|
||||
private void getTextOpacity(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || textOpacity != (byte) -1) {
|
||||
packetSink.accept(textOpacityWatcher, textOpacity);
|
||||
@@ -121,7 +124,8 @@ public class RTextDisplay extends RDisplay {
|
||||
sendPacket(updatePacketSink, this::getTextStatus, this::getBackgroundColor);
|
||||
}
|
||||
|
||||
private static final Object backgroundColorWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 25 : 24, Integer.class);
|
||||
private static final EntityDataAccessor<Integer> backgroundColorWatcher = new EntityDataAccessor<>(25, EntityDataSerializers.INT);
|
||||
|
||||
private void getBackgroundColor(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
if (ignoreDefault || backgroundColor != null) {
|
||||
packetSink.accept(backgroundColorWatcher, backgroundColor);
|
||||
@@ -140,7 +144,8 @@ public class RTextDisplay extends RDisplay {
|
||||
sendPacket(updatePacketSink, this::getTextStatus);
|
||||
}
|
||||
|
||||
private static final Object textStatusWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 27 : 26, Byte.class);
|
||||
private static final EntityDataAccessor<Byte> textStatusWatcher = new EntityDataAccessor<>(27, EntityDataSerializers.BYTE);
|
||||
|
||||
private void getTextStatus(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
|
||||
byte status = 0;
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ public class SWAnvilInv {
|
||||
}
|
||||
|
||||
public void setItem(Material m, List<String> lore, boolean e) {
|
||||
setItem(m, (byte)0, lore, e);
|
||||
setItem(m, (byte) 0, lore, e);
|
||||
}
|
||||
|
||||
public void setItem(Material m, byte meta, List<String> lore, boolean e) {
|
||||
@@ -82,16 +82,14 @@ public class SWAnvilInv {
|
||||
}
|
||||
|
||||
private List<AnvilGUI.ResponseAction> onResult(Integer slot, AnvilGUI.StateSnapshot state) {
|
||||
if(slot != AnvilGUI.Slot.OUTPUT) {
|
||||
if(slot == AnvilGUI.Slot.INPUT_LEFT && leftCallback != null)
|
||||
leftCallback.run();
|
||||
if (slot != AnvilGUI.Slot.OUTPUT) {
|
||||
if (slot == AnvilGUI.Slot.INPUT_LEFT && leftCallback != null) leftCallback.run();
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String s = state.getText();
|
||||
if(s.startsWith("»"))
|
||||
s = s.substring(1);
|
||||
if (s.startsWith("»")) s = s.substring(1);
|
||||
callback.accept(s);
|
||||
player.setLevel(0);
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.close());
|
||||
|
||||
@@ -79,7 +79,7 @@ public class SWInventory implements Listener {
|
||||
|
||||
public void setItem(int pos, ItemStack itemStack, InvCallback c) {
|
||||
inventory.setItem(pos, itemStack);
|
||||
if(c != null) {
|
||||
if (c != null) {
|
||||
callbacks.put(pos, inventoryClickEvent -> c.clicked(inventoryClickEvent.getClick()));
|
||||
} else {
|
||||
callbacks.remove(pos);
|
||||
@@ -94,11 +94,11 @@ public class SWInventory implements Listener {
|
||||
setItem(pos, item.getItemStack(), item.getCallback());
|
||||
}
|
||||
|
||||
public void setItem(int pos, Material m, String name, InvCallback c){
|
||||
public void setItem(int pos, Material m, String name, InvCallback c) {
|
||||
setItem(pos, m, name, new ArrayList<>(), false, c);
|
||||
}
|
||||
|
||||
public void setItem(int pos, Material m, byte meta, String name, InvCallback c){
|
||||
public void setItem(int pos, Material m, byte meta, String name, InvCallback c) {
|
||||
setItem(pos, m, meta, name, new ArrayList<>(), false, c);
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ public class SWInventory implements Listener {
|
||||
InventoryView view = player.openInventory(inventory);
|
||||
title = view.getTitle();
|
||||
Core.getInstance().getLogger().info("[SWINV] Opened " + title + " for " + player.getName());
|
||||
if(!open) {
|
||||
if (!open) {
|
||||
Bukkit.getPluginManager().registerEvents(this, Core.getInstance());
|
||||
open = true;
|
||||
}
|
||||
@@ -156,8 +156,7 @@ public class SWInventory implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent e) {
|
||||
if (!player.equals(e.getWhoClicked()))
|
||||
return;
|
||||
if (!player.equals(e.getWhoClicked())) return;
|
||||
|
||||
if (callbacks.containsKey(e.getRawSlot()) && callbacks.get(e.getRawSlot()) != null) {
|
||||
e.setCancelled(true);
|
||||
@@ -168,14 +167,13 @@ public class SWInventory implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClose(InventoryCloseEvent e){
|
||||
if(!player.equals(e.getPlayer()))
|
||||
return;
|
||||
public void onInventoryClose(InventoryCloseEvent e) {
|
||||
if (!player.equals(e.getPlayer())) return;
|
||||
|
||||
InventoryClickEvent.getHandlerList().unregister(this);
|
||||
InventoryCloseEvent.getHandlerList().unregister(this);
|
||||
Core.getInstance().getLogger().info("[SWINV] " + player.getName() + " closed " + title);
|
||||
if(callbacks.containsKey(-1)) {
|
||||
if (callbacks.containsKey(-1)) {
|
||||
callbacks.get(-1).accept(null);
|
||||
}
|
||||
open = false;
|
||||
|
||||
@@ -19,16 +19,17 @@
|
||||
|
||||
package de.steamwar.inventory;
|
||||
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.FlatteningWrapper;
|
||||
import de.steamwar.core.TrickyTrialsWrapper;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -42,64 +43,66 @@ public class SWItem {
|
||||
private ItemMeta itemMeta;
|
||||
private InvCallback callback;
|
||||
|
||||
public static SWItem getPlayerSkull(OfflinePlayer player){
|
||||
public static SWItem getPlayerSkull(OfflinePlayer player) {
|
||||
return getPlayerSkull(player.getName());
|
||||
}
|
||||
|
||||
public static SWItem getPlayerSkull(String playerName){
|
||||
public static SWItem getPlayerSkull(String playerName) {
|
||||
SWItem p = new SWItem();
|
||||
ItemStack head = FlatteningWrapper.impl.setSkullOwner(playerName);
|
||||
ItemStack head = new ItemStack(Material.PLAYER_HEAD, 1);
|
||||
head.editMeta(SkullMeta.class, skullMeta -> {
|
||||
try {
|
||||
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerName.startsWith(".") ? playerName.substring(1) : playerName);
|
||||
PlayerProfile playerProfile = offlinePlayer.getPlayerProfile();
|
||||
playerProfile.complete();
|
||||
skullMeta.setPlayerProfile(playerProfile);
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
});
|
||||
p.setItemStack(head);
|
||||
return p;
|
||||
}
|
||||
|
||||
public static Material getMaterial(String material){
|
||||
try{
|
||||
Material m = FlatteningWrapper.impl.getMaterial(material);
|
||||
if(m == null)
|
||||
return Material.BARRIER;
|
||||
|
||||
return m;
|
||||
}catch(IllegalArgumentException e){
|
||||
return Material.STONE;
|
||||
public static Material getMaterial(String material) {
|
||||
try {
|
||||
return Material.valueOf(material);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Material.BARRIER;
|
||||
}
|
||||
}
|
||||
|
||||
public static Material getDye(int colorCode){
|
||||
return FlatteningWrapper.impl.getDye(colorCode);
|
||||
}
|
||||
|
||||
public SWItem() {
|
||||
itemStack = new ItemStack(Material.AIR);
|
||||
itemMeta = itemStack.getItemMeta();
|
||||
hideAttributes();
|
||||
}
|
||||
|
||||
public SWItem(Material material, String name){
|
||||
this(material, (byte)0, name, new ArrayList<>(), false, null);
|
||||
public SWItem(Material material, String name) {
|
||||
this(material, (byte) 0, name, new ArrayList<>(), false, null);
|
||||
}
|
||||
|
||||
public SWItem(Material material, String name, InvCallback c){
|
||||
this(material, (byte)0, name, new ArrayList<>(), false, c);
|
||||
public SWItem(Material material, String name, InvCallback c) {
|
||||
this(material, (byte) 0, name, new ArrayList<>(), false, c);
|
||||
}
|
||||
|
||||
public SWItem(Material material, byte meta, String name){
|
||||
public SWItem(Material material, byte meta, String name) {
|
||||
this(material, meta, name, new ArrayList<>(), false, null);
|
||||
}
|
||||
|
||||
public SWItem(Material material, byte meta, String name, InvCallback c){
|
||||
public SWItem(Material material, byte meta, String name, InvCallback c) {
|
||||
this(material, meta, name, new ArrayList<>(), false, c);
|
||||
}
|
||||
|
||||
public SWItem(Material material, String name, List<String> lore, boolean enchanted, InvCallback c) {
|
||||
this(material, (byte)0, name, lore, enchanted, c);
|
||||
this(material, (byte) 0, name, lore, enchanted, c);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public SWItem(Material material, byte meta, String name, List<String> lore, boolean enchanted, InvCallback c) {
|
||||
|
||||
try {
|
||||
itemStack = new ItemStack(material, 1, (short)0, meta);
|
||||
itemStack = new ItemStack(material, 1, (short) 0, meta);
|
||||
} catch (IllegalArgumentException e) {
|
||||
itemStack = new ItemStack(material, 1);
|
||||
}
|
||||
@@ -111,7 +114,7 @@ public class SWItem {
|
||||
|
||||
itemMeta.setDisplayName(name);
|
||||
if (lore != null && !lore.isEmpty()) itemMeta.setLore(lore);
|
||||
if (enchanted) itemMeta.addEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment(), 10, true);
|
||||
if (enchanted) itemMeta.addEnchant(Enchantment.UNBREAKING, 10, true);
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
}
|
||||
callback = c;
|
||||
@@ -120,32 +123,28 @@ public class SWItem {
|
||||
public static SWItem getItemFromJson(JsonObject itemJson) {
|
||||
SWItem item = null;
|
||||
try {
|
||||
if(itemJson.has("color")) {
|
||||
item = new SWItem(SWItem.getDye(itemJson.get("color").getAsInt()),
|
||||
itemJson.has("color")?itemJson.get("color").getAsByte():0,
|
||||
itemJson.get("title").getAsString());
|
||||
}else {
|
||||
item = new SWItem(SWItem.getMaterial(itemJson.get("material").getAsString()), itemJson.get("title").getAsString());
|
||||
}
|
||||
}catch (IllegalArgumentException e) {
|
||||
item = new SWItem(SWItem.getMaterial(itemJson.get("material").getAsString()), itemJson.get("title").getAsString());
|
||||
} catch (IllegalArgumentException e) {
|
||||
item = new SWItem(Material.STONE, itemJson.get("title").getAsString());
|
||||
}
|
||||
if(itemJson.has("skullOwner")) {
|
||||
if (itemJson.has("skullOwner")) {
|
||||
item = SWItem.getPlayerSkull(itemJson.get("skullOwner").getAsString());
|
||||
item.setName(itemJson.get("title").getAsString());
|
||||
}
|
||||
|
||||
if(itemJson.has("enchanted"))
|
||||
if (itemJson.has("enchanted")) {
|
||||
item.setEnchanted(true);
|
||||
if(itemJson.has("lore")) {
|
||||
}
|
||||
if (itemJson.has("lore")) {
|
||||
List<String> lore = new ArrayList<>();
|
||||
JsonArray loreArray = itemJson.getAsJsonArray("lore");
|
||||
loreArray.forEach(jsonElement -> lore.add(jsonElement.getAsString()));
|
||||
item.setLore(lore);
|
||||
}
|
||||
|
||||
if (itemJson.has("customModelData"))
|
||||
if (itemJson.has("customModelData")) {
|
||||
item.setCustomModelData(itemJson.get("customModelData").getAsInt());
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -207,20 +206,18 @@ public class SWItem {
|
||||
}
|
||||
|
||||
public SWItem setEnchanted(boolean enchanted) {
|
||||
if (enchanted){
|
||||
itemMeta.addEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment() , 10, true);
|
||||
if (enchanted) {
|
||||
itemMeta.addEnchant(Enchantment.UNBREAKING, 10, true);
|
||||
} else {
|
||||
itemMeta.removeEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment());
|
||||
itemMeta.removeEnchant(Enchantment.UNBREAKING);
|
||||
}
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SWItem setCustomModelData(int customModelData) {
|
||||
if (Core.getVersion() > 12) {
|
||||
itemMeta.setCustomModelData(customModelData);
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
}
|
||||
itemMeta.setCustomModelData(customModelData);
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ public class SWListInv<T> extends SWInventory {
|
||||
private int page;
|
||||
private boolean opened = false;
|
||||
|
||||
public SWListInv(Player p, String t, List<SWListEntry<T>> l, ListCallback<T> c){
|
||||
public SWListInv(Player p, String t, List<SWListEntry<T>> l, ListCallback<T> c) {
|
||||
this(p, t, true, l, c);
|
||||
}
|
||||
|
||||
public SWListInv(Player p, String t, boolean dynamicSize, List<SWListEntry<T>> l, ListCallback<T> c){
|
||||
public SWListInv(Player p, String t, boolean dynamicSize, List<SWListEntry<T>> l, ListCallback<T> c) {
|
||||
super(p, dynamicSize ? dynamicSize(l.size()) : 54, t);
|
||||
callback = c;
|
||||
elements = l;
|
||||
@@ -54,37 +54,37 @@ public class SWListInv<T> extends SWInventory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(){
|
||||
public void open() {
|
||||
opened = true;
|
||||
inventory.clear();
|
||||
callbacks.keySet().stream().filter(i -> i >= 0).collect(Collectors.toList()).forEach(callbacks::remove);
|
||||
if(!callbacks.containsKey(-999)) {
|
||||
if (!callbacks.containsKey(-999)) {
|
||||
setCallback(-999, (ClickType click) -> player.closeInventory());
|
||||
}
|
||||
|
||||
if (sizeBiggerMax()) {
|
||||
if (page != 0) {
|
||||
setItem(45, new SWItem(SWItem.getDye(10), (byte) 10, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_ACTIVE", player), (ClickType click) -> {
|
||||
setItem(45, new SWItem(Material.LIME_DYE, (byte) 10, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_ACTIVE", player), (ClickType click) -> {
|
||||
page--;
|
||||
open();
|
||||
}).setCustomModelData(CMDs.PREVIOUS_PAGE));
|
||||
} else {
|
||||
setItem(45, new SWItem(SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_INACTIVE", player), (ClickType click) -> {
|
||||
setItem(45, new SWItem(Material.GRAY_DYE, (byte) 8, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_INACTIVE", player), (ClickType click) -> {
|
||||
}).setCustomModelData(CMDs.PREVIOUS_PAGE));
|
||||
}
|
||||
if (page < elements.size() / 45 - (elements.size() % 45 == 0 ? 1 : 0)) {
|
||||
setItem(53, new SWItem(SWItem.getDye(10), (byte) 10, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_ACTIVE", player), (ClickType click) -> {
|
||||
setItem(53, new SWItem(Material.LIME_DYE, (byte) 10, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_ACTIVE", player), (ClickType click) -> {
|
||||
page++;
|
||||
open();
|
||||
}).setCustomModelData(CMDs.NEXT_PAGE));
|
||||
} else {
|
||||
setItem(53, new SWItem(SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_INACTIVE", player), (ClickType click) -> {
|
||||
setItem(53, new SWItem(Material.GRAY_DYE, (byte) 8, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_INACTIVE", player), (ClickType click) -> {
|
||||
}).setCustomModelData(CMDs.NEXT_PAGE));
|
||||
}
|
||||
} else if (!dynamicSize) {
|
||||
setItem(45, new SWItem(SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_INACTIVE", player), (ClickType click) -> {
|
||||
setItem(45, new SWItem(Material.GRAY_DYE, (byte) 8, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_INACTIVE", player), (ClickType click) -> {
|
||||
}).setCustomModelData(CMDs.PREVIOUS_PAGE));
|
||||
setItem(53, new SWItem(SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_INACTIVE", player), (ClickType click) -> {
|
||||
setItem(53, new SWItem(Material.GRAY_DYE, (byte) 8, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_INACTIVE", player), (ClickType click) -> {
|
||||
}).setCustomModelData(CMDs.NEXT_PAGE));
|
||||
}
|
||||
|
||||
@@ -109,75 +109,75 @@ public class SWListInv<T> extends SWInventory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(int pos, SWItem item){
|
||||
public void setItem(int pos, SWItem item) {
|
||||
super.setItem(pos, item);
|
||||
if(!opened)
|
||||
customItems.put(pos, item);
|
||||
if (!opened) customItems.put(pos, item);
|
||||
}
|
||||
|
||||
public void setCallback(ListCallback<T> c){
|
||||
public void setCallback(ListCallback<T> c) {
|
||||
callback = c;
|
||||
}
|
||||
|
||||
public static List<SWListEntry<UUID>> createPlayerList(UUID without){
|
||||
public static List<SWListEntry<UUID>> createPlayerList(UUID without) {
|
||||
List<SWListEntry<UUID>> onlinePlayers = new ArrayList<>();
|
||||
for(Player player : Bukkit.getOnlinePlayers()){
|
||||
if(without != null && player.getUniqueId().equals(without))
|
||||
continue;
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (without != null && player.getUniqueId().equals(without)) continue;
|
||||
|
||||
onlinePlayers.add(new SWListEntry<>(SWItem.getPlayerSkull(player), player.getUniqueId()));
|
||||
}
|
||||
return onlinePlayers;
|
||||
}
|
||||
|
||||
public static List<SWListEntry<SchematicNode>> getSchemnodeList(SchematicType type, int steamwarUserId){
|
||||
public static List<SWListEntry<SchematicNode>> getSchemnodeList(SchematicType type, int steamwarUserId) {
|
||||
List<SWListEntry<SchematicNode>> schemList = new ArrayList<>();
|
||||
|
||||
List<SchematicNode> schems;
|
||||
if(type == null)
|
||||
if (type == null) {
|
||||
schems = SchematicNode.getAllSchematicsAccessibleByUser(steamwarUserId);
|
||||
else
|
||||
} else {
|
||||
schems = SchematicNode.getAllAccessibleSchematicsOfType(steamwarUserId, type.toDB());
|
||||
}
|
||||
|
||||
for(SchematicNode s : schems){
|
||||
for (SchematicNode s : schems) {
|
||||
Material m;
|
||||
if(s.getItem().isEmpty())
|
||||
m = SWItem.getMaterial("CAULDRON_ITEM");
|
||||
else
|
||||
if (s.getItem().isEmpty()) {
|
||||
m = Material.CAULDRON;
|
||||
} else {
|
||||
m = SWItem.getMaterial(s.getItem());
|
||||
SWItem item = new SWItem(m,"§e" + s.getName());
|
||||
}
|
||||
SWItem item = new SWItem(m, "§e" + s.getName());
|
||||
item.setEnchanted(s.isDir());
|
||||
schemList.add(new SWListEntry<>(item, s));
|
||||
}
|
||||
return schemList;
|
||||
}
|
||||
|
||||
private boolean sizeBiggerMax(){
|
||||
|
||||
private boolean sizeBiggerMax() {
|
||||
return dynamicSize ? elements.size() > 54 : elements.size() > 45;
|
||||
}
|
||||
|
||||
private static int dynamicSize(int size){
|
||||
return (size>45) ? 54 : (size + 9-size%9);
|
||||
private static int dynamicSize(int size) {
|
||||
return (size > 45) ? 54 : (size + 9 - size % 9);
|
||||
}
|
||||
|
||||
public interface ListCallback<T>{
|
||||
public interface ListCallback<T> {
|
||||
void clicked(ClickType click, T element);
|
||||
}
|
||||
|
||||
public static class SWListEntry<T>{
|
||||
public static class SWListEntry<T> {
|
||||
final SWItem item;
|
||||
final T object;
|
||||
|
||||
public SWListEntry(SWItem item, T object){
|
||||
public SWListEntry(SWItem item, T object) {
|
||||
this.item = item;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public SWItem getItem(){
|
||||
public SWItem getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
public T getObject(){
|
||||
public T getObject() {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public class SchematicSelector {
|
||||
|
||||
public void open() {
|
||||
injectable.onSelectorCreate(this);
|
||||
if(publicMode == PublicMode.PUBLIC_ONLY) {
|
||||
if (publicMode == PublicMode.PUBLIC_ONLY) {
|
||||
this.user = SteamwarUser.byId(0);
|
||||
}
|
||||
openList(null);
|
||||
@@ -103,9 +103,9 @@ public class SchematicSelector {
|
||||
|
||||
private void openList(SchematicNode parent) {
|
||||
lastParent = parent;
|
||||
List<SchematicNode> nodes = applySorting(filter != null?getFilteredSchematics():getSchematicList(parent));
|
||||
List<SchematicNode> nodes = applySorting(filter != null ? getFilteredSchematics() : getSchematicList(parent));
|
||||
|
||||
if(sdoTrigger) {
|
||||
if (sdoTrigger) {
|
||||
sdoTrigger = false;
|
||||
openList(nodes.get(0));
|
||||
return;
|
||||
@@ -113,18 +113,19 @@ public class SchematicSelector {
|
||||
|
||||
List<SWListInv.SWListEntry<SchematicNode>> list = new ArrayList<>();
|
||||
|
||||
if(depth != 0) {
|
||||
list.add(new SWListInv.SWListEntry<>(new SWItem(Material.ARROW, Core.MESSAGE.parse("SCHEM_SELECTOR_BACK", player), clickType -> {}).setCustomModelData(CMDs.BACK), null));
|
||||
if (depth != 0) {
|
||||
list.add(new SWListInv.SWListEntry<>(new SWItem(Material.ARROW, Core.MESSAGE.parse("SCHEM_SELECTOR_BACK", player), clickType -> {
|
||||
}).setCustomModelData(CMDs.BACK), null));
|
||||
}
|
||||
|
||||
for (SchematicNode node : nodes) {
|
||||
if(node.getName().equals("//copy")) continue;
|
||||
if (node.getName().equals("//copy")) continue;
|
||||
list.add(renderItem(node));
|
||||
}
|
||||
|
||||
SWListInv<SchematicNode> inv = new SWListInv<>(player, MessageFormat.format(injectable.createTitle(player), target.target.getName(player), (filter == null || filter.getName() == null)?(parent == null?"/":parent.generateBreadcrumbs(user)):filter.getName()), false, list, (clickType, node) -> handleClick(node, parent));
|
||||
if(publicMode == PublicMode.ALL) {
|
||||
if(user.getId() == 0) {
|
||||
SWListInv<SchematicNode> inv = new SWListInv<>(player, MessageFormat.format(injectable.createTitle(player), target.target.getName(player), (filter == null || filter.getName() == null) ? (parent == null ? "/" : parent.generateBreadcrumbs(user)) : filter.getName()), false, list, (clickType, node) -> handleClick(node, parent));
|
||||
if (publicMode == PublicMode.ALL) {
|
||||
if (user.getId() == 0) {
|
||||
inv.setItem(48, new SWItem(Material.BUCKET, Core.MESSAGE.parse("SCHEM_SELECTOR_OWN", player), clickType -> {
|
||||
this.user = SteamwarUser.get(player.getUniqueId());
|
||||
openList(null);
|
||||
@@ -136,21 +137,21 @@ public class SchematicSelector {
|
||||
}).setCustomModelData(CMDs.Schematic.PUBLIC_SCHEMS));
|
||||
}
|
||||
}
|
||||
if(target.target.dirs) {
|
||||
inv.setItem(49, SWItem.getDye(10), Core.MESSAGE.parse("SCHEM_SELECTOR_SEL_DIR", player), clickType -> {
|
||||
if (target.target.dirs) {
|
||||
inv.setItem(49, Material.LIME_DYE, Core.MESSAGE.parse("SCHEM_SELECTOR_SEL_DIR", player), clickType -> {
|
||||
player.closeInventory();
|
||||
callback.accept(parent);
|
||||
});
|
||||
}
|
||||
if(user.getId() != 0) {
|
||||
if (user.getId() != 0) {
|
||||
inv.setItem(50, new SWItem(Material.CHEST, Core.MESSAGE.parse("SCHEM_SELECTOR_NEW_DIR", player), clickType -> createFolderIn(parent)).setCustomModelData(CMDs.Schematic.NEW_DIR));
|
||||
}
|
||||
inv.setItem(51, new SWItem(Material.NAME_TAG, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER", player), clickType -> openFilter()).setCustomModelData(CMDs.Schematic.FILTER));
|
||||
inv.setItem(47, new SWItem(sorting.mat, Core.MESSAGE.parse("SCHEM_SELECTOR_SORTING", player), Arrays.asList(
|
||||
Core.MESSAGE.parse("SCHEM_SELECTOR_SORTING_CURRENT", player, sorting.parseName(player)),
|
||||
Core.MESSAGE.parse("SCHEM_SELECTOR_SORTING_DIRECTION", player, Core.MESSAGE.parse(invertSorting?"SCHEM_SELECTOR_SORTING_DSC":"SCHEM_SELECTOR_SORTING_ASC", player))
|
||||
Core.MESSAGE.parse("SCHEM_SELECTOR_SORTING_DIRECTION", player, Core.MESSAGE.parse(invertSorting ? "SCHEM_SELECTOR_SORTING_DSC" : "SCHEM_SELECTOR_SORTING_ASC", player))
|
||||
), invertSorting, click -> {
|
||||
if(click.isLeftClick()) {
|
||||
if (click.isLeftClick()) {
|
||||
cycleSorting();
|
||||
} else {
|
||||
invertSorting = !invertSorting;
|
||||
@@ -163,13 +164,13 @@ public class SchematicSelector {
|
||||
}
|
||||
|
||||
private SchematicNode dirUp(SchematicNode parent) {
|
||||
if(parent == null) {
|
||||
if (parent == null) {
|
||||
// Gracefully handle unexpected Updir in Root Folder
|
||||
depth = 0;
|
||||
return null;
|
||||
}
|
||||
if(!singleDirOpen) {
|
||||
if(NodeMember.getNodeMember(parent.getId(), user.getId()) != null) {
|
||||
if (!singleDirOpen) {
|
||||
if (NodeMember.getNodeMember(parent.getId(), user.getId()) != null) {
|
||||
return NodeMember.getNodeMember(parent.getId(), user.getId()).getParent().map(integer -> SchematicNode.byIdAndUser(user, integer)).orElse(null);
|
||||
} else {
|
||||
return getParent(parent).orElse(null);
|
||||
@@ -179,7 +180,7 @@ public class SchematicSelector {
|
||||
do {
|
||||
sdoTrigger = false;
|
||||
currentParent = currentParent.flatMap(this::getParent);
|
||||
if(!currentParent.isPresent()) {
|
||||
if (!currentParent.isPresent()) {
|
||||
break;
|
||||
}
|
||||
getSchematicList(currentParent.get());
|
||||
@@ -189,13 +190,13 @@ public class SchematicSelector {
|
||||
}
|
||||
|
||||
private void handleClick(SchematicNode node, SchematicNode parent) {
|
||||
if(node == null) {
|
||||
if (node == null) {
|
||||
depth--;
|
||||
openList(dirUp(parent));
|
||||
return;
|
||||
}
|
||||
if(node.isDir()) {
|
||||
if(filter != null && target.target.dirs) {
|
||||
if (node.isDir()) {
|
||||
if (filter != null && target.target.dirs) {
|
||||
player.closeInventory();
|
||||
callback.accept(node);
|
||||
return;
|
||||
@@ -211,19 +212,19 @@ public class SchematicSelector {
|
||||
|
||||
private void cycleSorting() {
|
||||
int next = sorting.ordinal() + 1;
|
||||
if(next >= all_sortings.length) {
|
||||
if (next >= all_sortings.length) {
|
||||
next = 0;
|
||||
}
|
||||
sorting = all_sortings[next];
|
||||
}
|
||||
|
||||
private List<SchematicNode> applySorting(List<SchematicNode> nodes) {
|
||||
if(sorting == Sorting.NAME && !invertSorting) {
|
||||
if (sorting == Sorting.NAME && !invertSorting) {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
Comparator<SchematicNode> comparator = sorting.comparator;
|
||||
if(invertSorting) {
|
||||
if (invertSorting) {
|
||||
comparator = comparator.reversed();
|
||||
}
|
||||
|
||||
@@ -234,15 +235,15 @@ public class SchematicSelector {
|
||||
private SWListInv.SWListEntry<SchematicNode> renderItem(SchematicNode node) {
|
||||
Material m = SWItem.getMaterial(node.getItem());
|
||||
|
||||
String name = Core.MESSAGE.parse((filter != null && filter.name == null)?"SCHEM_SELECTOR_ITEM_NAME":"SCHEM_SELECTOR_ITEM_NAME_FILTER", player, node.getName());
|
||||
String name = Core.MESSAGE.parse((filter != null && filter.name == null) ? "SCHEM_SELECTOR_ITEM_NAME" : "SCHEM_SELECTOR_ITEM_NAME_FILTER", player, node.getName());
|
||||
|
||||
if(filter != null && filter.getName() != null) {
|
||||
if (filter != null && filter.getName() != null) {
|
||||
name = name.replace(filter.getName(), Core.MESSAGE.parse("SCHEM_SELECTOR_ITEM_REPLACE", player, filter.getName()));
|
||||
}
|
||||
|
||||
SWItem item = new SWItem(m, name, Collections.singletonList(node.isDir() ? (Core.MESSAGE.parse("SCHEM_SELECTOR_DIR", player)) : Core.MESSAGE.parse("SCHEM_SELECTOR_ITEM_LORE_TYPE", player, node.getSchemtype().name())), !node.isDir() && !node.getSchemtype().writeable(), click -> {
|
||||
});
|
||||
if(!node.isDir() && node.getRank() > 0) {
|
||||
if (!node.isDir() && node.getRank() > 0) {
|
||||
item.setLore(Arrays.asList(Core.MESSAGE.parse("SCHEM_SELECTOR_ITEM_LORE_TYPE", player, node.getSchemtype().name()), Core.MESSAGE.parse("SCHEM_SELECTOR_RANK", player, node.getRank())));
|
||||
}
|
||||
return new SWListInv.SWListEntry<>(item, node);
|
||||
@@ -251,7 +252,7 @@ public class SchematicSelector {
|
||||
private void addLeftCloseAction(SWAnvilInv inv, Runnable runnable) {
|
||||
AtomicBoolean wasLeft = new AtomicBoolean(false);
|
||||
inv.addCloseCallback(() -> {
|
||||
if(injectable.onAnvilInvCloseAction(this) == SchematicSelectorInjectable.AnvilInvCloseAction.REOPEN && !wasLeft.get()) {
|
||||
if (injectable.onAnvilInvCloseAction(this) == SchematicSelectorInjectable.AnvilInvCloseAction.REOPEN && !wasLeft.get()) {
|
||||
player.closeInventory();
|
||||
Bukkit.getScheduler().runTaskLater(Core.getInstance(), runnable, 1);
|
||||
}
|
||||
@@ -266,9 +267,9 @@ public class SchematicSelector {
|
||||
SWAnvilInv inv = new SWAnvilInv(player, Core.MESSAGE.parse("SCHEM_SELECTOR_CREATE_DIR_TITLE", player));
|
||||
inv.setItem(Material.CHEST, Collections.singletonList(Core.MESSAGE.parse("SCHEM_SELECTOR_CLICK_BACK", player)), false);
|
||||
inv.setCallback(s -> {
|
||||
if(!SchematicNode.invalidSchemName(new String[] {s})) {
|
||||
if(injectable.onFolderCreate(this, s)) {
|
||||
SchematicNode.createSchematicDirectory(user.getId(), s, parent==null?0:parent.getId());
|
||||
if (!SchematicNode.invalidSchemName(new String[]{s})) {
|
||||
if (injectable.onFolderCreate(this, s)) {
|
||||
SchematicNode.createSchematicDirectory(user.getId(), s, parent == null ? 0 : parent.getId());
|
||||
openList(parent);
|
||||
}
|
||||
return;
|
||||
@@ -286,7 +287,7 @@ public class SchematicSelector {
|
||||
|
||||
SWInventory inv = new SWInventory(player, 9 * 2, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_TITLE", player));
|
||||
InvCallback nameCallback = clickType -> {
|
||||
if(clickType.isRightClick()) {
|
||||
if (clickType.isRightClick()) {
|
||||
filter = filter.withName(null);
|
||||
openFilter();
|
||||
} else {
|
||||
@@ -300,21 +301,21 @@ public class SchematicSelector {
|
||||
swAnvilInv.open();
|
||||
}
|
||||
};
|
||||
if(filter.getName() == null) {
|
||||
if (filter.getName() == null) {
|
||||
inv.setItem(0, Material.NAME_TAG, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_NAME", player), nameCallback);
|
||||
} else {
|
||||
inv.setItem(0, Material.NAME_TAG, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_NAME", player), Collections.singletonList(Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_NAME_SEARCH", player, filter.getName())), true, nameCallback);
|
||||
}
|
||||
|
||||
InvCallback ownerCallback = clickType -> {
|
||||
if(clickType.isRightClick()) {
|
||||
if (clickType.isRightClick()) {
|
||||
filter = filter.withOwner(null);
|
||||
openFilter();
|
||||
} else {
|
||||
SWAnvilInv swAnvilInv = new SWAnvilInv(player, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_ENTER_OWNER", player));
|
||||
swAnvilInv.setItem(SWItem.getMaterial("SKULL_ITEM"), (byte) 3, Collections.singletonList(Core.MESSAGE.parse("SCHEM_SELECTOR_CLICK_BACK", player)), false);
|
||||
swAnvilInv.setItem(Material.SKELETON_SKULL, (byte) 3, Collections.singletonList(Core.MESSAGE.parse("SCHEM_SELECTOR_CLICK_BACK", player)), false);
|
||||
swAnvilInv.setCallback(s -> {
|
||||
if(SteamwarUser.get(s) != null) {
|
||||
if (SteamwarUser.get(s) != null) {
|
||||
filter = filter.withOwner(SteamwarUser.get(s).getId());
|
||||
}
|
||||
openFilter();
|
||||
@@ -323,8 +324,8 @@ public class SchematicSelector {
|
||||
swAnvilInv.open();
|
||||
}
|
||||
};
|
||||
if(filter.getOwner() == null) {
|
||||
inv.setItem(1, SWItem.getMaterial("SKULL_ITEM"), (byte) 3, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_OWNER", player), ownerCallback);
|
||||
if (filter.getOwner() == null) {
|
||||
inv.setItem(1, Material.SKELETON_SKULL, (byte) 3, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_OWNER", player), ownerCallback);
|
||||
} else {
|
||||
SteamwarUser tUser = SteamwarUser.byId(filter.getOwner());
|
||||
SWItem item = SWItem.getPlayerSkull(tUser.getUserName());
|
||||
@@ -335,14 +336,15 @@ public class SchematicSelector {
|
||||
inv.setItem(1, item);
|
||||
}
|
||||
|
||||
if(target.target != Target.SCHEMATIC_TYPE) {
|
||||
if (target.target != Target.SCHEMATIC_TYPE) {
|
||||
InvCallback schemTypeCallback = clickType -> {
|
||||
if(clickType.isRightClick()) {
|
||||
if (clickType.isRightClick()) {
|
||||
filter = filter.withType(null);
|
||||
openFilter();
|
||||
} else {
|
||||
List<SWListInv.SWListEntry<SchematicType>> types = new ArrayList<>();
|
||||
SchematicType.values().forEach(schematicType -> types.add(new SWListInv.SWListEntry<>(new SWItem(SWItem.getMaterial(schematicType.getMaterial()), "§e" + schematicType.name(), Collections.emptyList(), schematicType.fightType(), n -> {}), schematicType)));
|
||||
SchematicType.values().forEach(schematicType -> types.add(new SWListInv.SWListEntry<>(new SWItem(SWItem.getMaterial(schematicType.getMaterial()), "§e" + schematicType.name(), Collections.emptyList(), schematicType.fightType(), n -> {
|
||||
}), schematicType)));
|
||||
SWListInv<SchematicType> listInv = new SWListInv<>(player, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_SEL_TYPE", player), types, (clickType1, schematicType) -> {
|
||||
filter = filter.withType(schematicType);
|
||||
openFilter();
|
||||
@@ -351,7 +353,7 @@ public class SchematicSelector {
|
||||
}
|
||||
};
|
||||
|
||||
if(filter.getType() == null) {
|
||||
if (filter.getType() == null) {
|
||||
inv.setItem(2, SWItem.getMaterial(SchematicType.Normal.getMaterial()), Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_TYPE", player), schemTypeCallback);
|
||||
} else {
|
||||
inv.setItem(2, SWItem.getMaterial(filter.getType().getMaterial()), Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_TYPE", player), Collections.singletonList(Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_TYPE_SEARCH", player, filter.getType().name())), true, schemTypeCallback);
|
||||
@@ -359,7 +361,7 @@ public class SchematicSelector {
|
||||
}
|
||||
|
||||
InvCallback materialCallback = clickType -> {
|
||||
if(clickType.isRightClick()) {
|
||||
if (clickType.isRightClick()) {
|
||||
filter = filter.withItem(null);
|
||||
openFilter();
|
||||
} else {
|
||||
@@ -370,9 +372,9 @@ public class SchematicSelector {
|
||||
}
|
||||
};
|
||||
|
||||
final int iSlot = target.target == Target.SCHEMATIC_TYPE?2:3;
|
||||
final int iSlot = target.target == Target.SCHEMATIC_TYPE ? 2 : 3;
|
||||
|
||||
if(filter.getItem() == null) {
|
||||
if (filter.getItem() == null) {
|
||||
inv.setItem(iSlot, Material.STONE, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_MAT", player), materialCallback);
|
||||
} else {
|
||||
inv.setItem(iSlot, filter.getItem(), Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_MAT", player), Collections.singletonList(Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_MAT_SEARCH", player, filter.getItem().name())), true, materialCallback);
|
||||
@@ -397,7 +399,8 @@ public class SchematicSelector {
|
||||
for (int i = 0; i < filters.length; i++) {
|
||||
SelectorFilter filterCached = filters[i];
|
||||
if (filterCached == null) {
|
||||
inv.setItem(i + 9, new SWItem(Material.BARRIER, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_EMPTY", player), click -> {}));
|
||||
inv.setItem(i + 9, new SWItem(Material.BARRIER, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_EMPTY", player), click -> {
|
||||
}));
|
||||
} else {
|
||||
SWItem item = filterCached.toItemStack(player);
|
||||
item.setEnchanted(filterCached.equals(filter));
|
||||
@@ -408,19 +411,19 @@ public class SchematicSelector {
|
||||
}
|
||||
}
|
||||
|
||||
inv.setItem(7, SWItem.getDye(1), Core.MESSAGE.parse("SCHEM_SELECTOR_CANCEL", player), clickType -> {
|
||||
inv.setItem(7, Material.RED_DYE, Core.MESSAGE.parse("SCHEM_SELECTOR_CANCEL", player), clickType -> {
|
||||
filter = null;
|
||||
depth = 0;
|
||||
openList(null);
|
||||
});
|
||||
inv.setItem(8, SWItem.getDye(10), Core.MESSAGE.parse("SCHEM_SELECTOR_GO", player), clickType -> {
|
||||
inv.setItem(8, Material.LIME_DYE, Core.MESSAGE.parse("SCHEM_SELECTOR_GO", player), clickType -> {
|
||||
if (!filter.equals(filters[0])) {
|
||||
for (int i = filters.length - 1; i > 0; i--) {
|
||||
filters[i] = filters[i-1];
|
||||
filters[i] = filters[i - 1];
|
||||
if (filter.equals(filters[i])) {
|
||||
filters[i] = null;
|
||||
for (int j = i; j < filters.length - 1; j++) {
|
||||
filters[j] = filters[j+1];
|
||||
filters[j] = filters[j + 1];
|
||||
}
|
||||
filters[filters.length - 1] = null;
|
||||
}
|
||||
@@ -455,10 +458,10 @@ public class SchematicSelector {
|
||||
injectable.onNodeFilter(this, node);
|
||||
return !filter.matches(node);
|
||||
});
|
||||
if(target.target == Target.DIRECTORY) {
|
||||
if (target.target == Target.DIRECTORY) {
|
||||
nodes.removeIf(node -> !node.isDir());
|
||||
}
|
||||
if(target.target == Target.SCHEMATIC_TYPE) {
|
||||
if (target.target == Target.SCHEMATIC_TYPE) {
|
||||
nodes.removeIf(node -> node.isDir() || !node.getSchemtype().equals(target.type));
|
||||
}
|
||||
return nodes;
|
||||
@@ -472,13 +475,13 @@ public class SchematicSelector {
|
||||
nodes.removeIf(node -> !node.isDir());
|
||||
break;
|
||||
case SCHEMATIC_TYPE:
|
||||
nodes.addAll(SchematicNode.accessibleByUserTypeParent(user, target.type, parent==null?null:parent.getId()));
|
||||
nodes.addAll(SchematicNode.accessibleByUserTypeParent(user, target.type, parent == null ? null : parent.getId()));
|
||||
break;
|
||||
default:
|
||||
nodes.addAll(SchematicNode.list(user, parent == null?null:parent.getId()));
|
||||
nodes.addAll(SchematicNode.list(user, parent == null ? null : parent.getId()));
|
||||
}
|
||||
|
||||
if(singleDirOpen && nodes.size() == 1 && nodes.get(0).isDir()) {
|
||||
if (singleDirOpen && nodes.size() == 1 && nodes.get(0).isDir()) {
|
||||
sdoTrigger = true;
|
||||
}
|
||||
return nodes;
|
||||
@@ -553,22 +556,22 @@ public class SchematicSelector {
|
||||
public boolean matches(SchematicNode node) {
|
||||
boolean matches = name == null || node.getName().contains(name);
|
||||
|
||||
if(owner != null && node.getOwner() != owner) {
|
||||
if (owner != null && node.getOwner() != owner) {
|
||||
matches = false;
|
||||
}
|
||||
|
||||
if(type != null && (node.isDir() || !node.getSchemtype().equals(type))) {
|
||||
if (type != null && (node.isDir() || !node.getSchemtype().equals(type))) {
|
||||
matches = false;
|
||||
}
|
||||
|
||||
if(item != null) {
|
||||
if (item != null) {
|
||||
String i;
|
||||
if(node.getItem().isEmpty()) {
|
||||
i = node.isDir()?"CHEST":"CAULDRON";
|
||||
if (node.getItem().isEmpty()) {
|
||||
i = node.isDir() ? "CHEST" : "CAULDRON";
|
||||
} else {
|
||||
i = node.getItem();
|
||||
}
|
||||
if(!item.name().equals(i)) {
|
||||
if (!item.name().equals(i)) {
|
||||
matches = false;
|
||||
}
|
||||
}
|
||||
@@ -581,16 +584,16 @@ public class SchematicSelector {
|
||||
|
||||
public List<String> getItemLore(Player player) {
|
||||
List<String> lore = new ArrayList<>(4);
|
||||
if(name != null) {
|
||||
if (name != null) {
|
||||
lore.add(Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_NAME_SEARCH", player, name));
|
||||
}
|
||||
if(owner != null) {
|
||||
if (owner != null) {
|
||||
lore.add(Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_OWNER_SEARCH", player, SteamwarUser.byId(owner).getUserName()));
|
||||
}
|
||||
if(type != null) {
|
||||
if (type != null) {
|
||||
lore.add(Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_TYPE_SEARCH", player, type.name()));
|
||||
}
|
||||
if(item != null) {
|
||||
if (item != null) {
|
||||
lore.add(Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_MAT_SEARCH", player, item.name()));
|
||||
}
|
||||
|
||||
@@ -604,18 +607,22 @@ public class SchematicSelector {
|
||||
List<String> lore = getItemLore(player);
|
||||
|
||||
if (name != null) {
|
||||
return new SWItem(Material.NAME_TAG, itemName, lore, false, click -> {});
|
||||
return new SWItem(Material.NAME_TAG, itemName, lore, false, click -> {
|
||||
});
|
||||
} else if (owner != null) {
|
||||
SWItem playerSkull = SWItem.getPlayerSkull(SteamwarUser.byId(owner).getUserName());
|
||||
playerSkull.setName(itemName);
|
||||
playerSkull.setLore(lore);
|
||||
return playerSkull;
|
||||
} else if (type != null) {
|
||||
return new SWItem(SWItem.getMaterial(type.getMaterial()), itemName, lore, false, n -> {});
|
||||
return new SWItem(SWItem.getMaterial(type.getMaterial()), itemName, lore, false, n -> {
|
||||
});
|
||||
} else if (item != null) {
|
||||
return new SWItem(item, itemName, lore, false, click -> {});
|
||||
return new SWItem(item, itemName, lore, false, click -> {
|
||||
});
|
||||
} else {
|
||||
return new SWItem(Material.BARRIER, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_TITLE_EMPTY", player), Collections.emptyList(), false, click -> {});
|
||||
return new SWItem(Material.BARRIER, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER_TITLE_EMPTY", player), Collections.emptyList(), false, click -> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,8 +630,8 @@ public class SchematicSelector {
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("name", name);
|
||||
object.addProperty("owner", owner);
|
||||
object.addProperty("type", type == null?null:type.toDB());
|
||||
object.addProperty("item", item == null?null:item.name());
|
||||
object.addProperty("type", type == null ? null : type.toDB());
|
||||
object.addProperty("item", item == null ? null : item.name());
|
||||
|
||||
return object;
|
||||
}
|
||||
@@ -640,13 +647,13 @@ public class SchematicSelector {
|
||||
private enum Sorting {
|
||||
NAME(Material.PAPER, "SCHEM_SELECTOR_SORTING_NAME", Comparator.comparing(SchematicNode::getName)),
|
||||
TYPE(Material.CAULDRON, "SCHEM_SELECTOR_SORTING_TYPE", (o1, o2) -> {
|
||||
if(o1.isDir() || o2.isDir()) {
|
||||
if (o1.isDir() || o2.isDir()) {
|
||||
return Boolean.compare(o1.isDir(), o2.isDir());
|
||||
} else {
|
||||
return o1.getSchemtype().name().compareTo(o2.getSchemtype().name());
|
||||
}
|
||||
}),
|
||||
LAST_UPDATED(SWItem.getMaterial("WATCH"), "SCHEM_SELECTOR_SORTING_UPDATE", Comparator.comparing(SchematicNode::getLastUpdate));
|
||||
LAST_UPDATED(Material.CLOCK, "SCHEM_SELECTOR_SORTING_UPDATE", Comparator.comparing(SchematicNode::getLastUpdate));
|
||||
|
||||
private final Material mat;
|
||||
private final String name;
|
||||
|
||||
+20
-9
@@ -25,27 +25,38 @@ import org.bukkit.entity.Player;
|
||||
|
||||
public interface SchematicSelectorInjectable {
|
||||
|
||||
SchematicSelectorInjectable DEFAULT = new SchematicSelectorInjectable() {};
|
||||
SchematicSelectorInjectable DEFAULT = new SchematicSelectorInjectable() {
|
||||
};
|
||||
|
||||
default String createTitle(Player player) {
|
||||
return Core.MESSAGE.parse("SCHEM_SELECTOR_TITLE", player);
|
||||
}
|
||||
|
||||
default void onSelectorCreate(SchematicSelector selector) {}
|
||||
default void onSelectorCreate(SchematicSelector selector) {
|
||||
}
|
||||
|
||||
default void onListRender(SchematicSelector selector, SWListInv<SchematicNode> inv, SchematicNode parent) {}
|
||||
default void onListRender(SchematicSelector selector, SWListInv<SchematicNode> inv, SchematicNode parent) {
|
||||
}
|
||||
|
||||
default void onFilterRender(SchematicSelector selector, SWInventory inventory) {}
|
||||
default void onFilterRender(SchematicSelector selector, SWInventory inventory) {
|
||||
}
|
||||
|
||||
default void onFilterApply(SchematicSelector selector) {}
|
||||
default void onFilterApply(SchematicSelector selector) {
|
||||
}
|
||||
|
||||
default boolean onFolderCreate(SchematicSelector selector, String name) {return true;}
|
||||
default boolean onFolderCreate(SchematicSelector selector, String name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void onNodeFilter(SchematicSelector selector, SchematicNode node) {}
|
||||
default void onNodeFilter(SchematicSelector selector, SchematicNode node) {
|
||||
}
|
||||
|
||||
default void onSelectorOpen(SchematicSelector selector, OpenFrom from) {}
|
||||
default void onSelectorOpen(SchematicSelector selector, OpenFrom from) {
|
||||
}
|
||||
|
||||
default AnvilInvCloseAction onAnvilInvCloseAction(SchematicSelector selector) {return AnvilInvCloseAction.CLOSE;}
|
||||
default AnvilInvCloseAction onAnvilInvCloseAction(SchematicSelector selector) {
|
||||
return AnvilInvCloseAction.CLOSE;
|
||||
}
|
||||
|
||||
enum OpenFrom {
|
||||
FRESH,
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
package de.steamwar.inventory;
|
||||
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
import de.steamwar.inventory.SWListInv;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -39,11 +37,10 @@ public class UtilGui {
|
||||
|
||||
public static void openMaterialSelector(Player player, String title, Consumer<Material> callback) {
|
||||
List<SWListInv.SWListEntry<Material>> materials = new LinkedList<>();
|
||||
for(Material material : Material.values()){
|
||||
if(material.name().startsWith(Material.LEGACY_PREFIX) || !material.isItem())
|
||||
continue;
|
||||
for (Material material : Material.values()) {
|
||||
if (material.name().startsWith(Material.LEGACY_PREFIX) || !material.isItem()) continue;
|
||||
SWItem item = new SWItem(material, "§7" + material.name());
|
||||
if(item.getItemMeta() != null && material.isItem()) {
|
||||
if (item.getItemMeta() != null && material.isItem()) {
|
||||
materials.add(new SWListInv.SWListEntry<>(item, material));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package de.steamwar.linkage;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.message.Message;
|
||||
import de.steamwar.network.packets.PacketHandler;
|
||||
import lombok.NonNull;
|
||||
@@ -38,17 +37,6 @@ public class SpigotLinker extends AbstractLinker<JavaPlugin> {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean versionCheck(@NonNull Class<?> clazz, MinVersion minVersion, MaxVersion maxVersion) {
|
||||
if (minVersion != null && Core.getVersion() < minVersion.value()) {
|
||||
return false;
|
||||
}
|
||||
if (maxVersion != null && Core.getVersion() > maxVersion.value()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean pluginCheck(@NonNull Class<?> clazz, PluginCheck pluginCheck) {
|
||||
if (pluginCheck.has() == PluginCheck.Has.THIS && Bukkit.getPluginManager().getPlugin(pluginCheck.value()) != null) {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package de.steamwar.message;
|
||||
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
@@ -30,7 +29,6 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
@@ -39,36 +37,36 @@ public class Message {
|
||||
private final String resourceBundleName;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public Message(String resourceBundleName, ClassLoader classLoader){
|
||||
public Message(String resourceBundleName, ClassLoader classLoader) {
|
||||
this.resourceBundleName = resourceBundleName;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
/* Parsing input to a message */
|
||||
|
||||
public TextComponent parseToComponent(String message, boolean prefixed, CommandSender sender, Object... params){
|
||||
public TextComponent parseToComponent(String message, boolean prefixed, CommandSender sender, Object... params) {
|
||||
return new TextComponent(TextComponent.fromLegacyText(parse(message, prefixed, sender, params)));
|
||||
}
|
||||
|
||||
public String parsePrefixed(String message, CommandSender sender, Object... params){
|
||||
public String parsePrefixed(String message, CommandSender sender, Object... params) {
|
||||
return parse(message, true, sender, params);
|
||||
}
|
||||
|
||||
public String parse(String message, CommandSender sender, Object... params){
|
||||
public String parse(String message, CommandSender sender, Object... params) {
|
||||
return parse(message, false, sender, params);
|
||||
}
|
||||
|
||||
private String parse(String message, boolean prefixed, CommandSender sender, Object... params){
|
||||
private String parse(String message, boolean prefixed, CommandSender sender, Object... params) {
|
||||
Locale locale;
|
||||
if(sender instanceof Player)
|
||||
if (sender instanceof Player) {
|
||||
locale = getLocale((Player) sender);
|
||||
else
|
||||
} else {
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
|
||||
ResourceBundle resourceBundle = ResourceBundle.getBundle(resourceBundleName, locale, classLoader);
|
||||
String pattern = "";
|
||||
if(prefixed)
|
||||
pattern = fromRB(resourceBundle, "PREFIX") + " ";
|
||||
if (prefixed) pattern = fromRB(resourceBundle, "PREFIX") + " ";
|
||||
pattern += fromRB(resourceBundle, message);
|
||||
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
@@ -82,84 +80,90 @@ public class Message {
|
||||
}
|
||||
|
||||
private String fromRB(ResourceBundle bundle, String key) {
|
||||
String result = bundle.getString(key);
|
||||
if(Core.getVersion() < 12)
|
||||
result = new String(result.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
|
||||
return result;
|
||||
return bundle.getString(key);
|
||||
}
|
||||
|
||||
private Locale getLocale(Player player){
|
||||
private Locale getLocale(Player player) {
|
||||
return SteamwarUser.get(player.getUniqueId()).getLocale();
|
||||
}
|
||||
|
||||
/* Send a message to one player */
|
||||
|
||||
public void send(String message, CommandSender sender, Object... params){
|
||||
public void send(String message, CommandSender sender, Object... params) {
|
||||
send(message, true, sender, ChatMessageType.SYSTEM, null, null, params);
|
||||
}
|
||||
|
||||
public void sendPrefixless(String message, CommandSender sender, Object... params){
|
||||
public void sendPrefixless(String message, CommandSender sender, Object... params) {
|
||||
send(message, false, sender, ChatMessageType.SYSTEM, null, null, params);
|
||||
}
|
||||
|
||||
public void send(String message, CommandSender sender, ChatMessageType type, Object... params){
|
||||
public void send(String message, CommandSender sender, ChatMessageType type, Object... params) {
|
||||
send(message, true, sender, type, null, null, params);
|
||||
}
|
||||
|
||||
public void sendPrefixless(String message, CommandSender sender, ChatMessageType type, Object... params){
|
||||
public void sendPrefixless(String message, CommandSender sender, ChatMessageType type, Object... params) {
|
||||
send(message, false, sender, type, null, null, params);
|
||||
}
|
||||
|
||||
public void send(String message, CommandSender sender, String onHover, ClickEvent onClick, Object... params){
|
||||
public void send(String message, CommandSender sender, String onHover, ClickEvent onClick, Object... params) {
|
||||
send(message, true, sender, ChatMessageType.SYSTEM, onHover, onClick, params);
|
||||
}
|
||||
|
||||
public void sendPrefixless(String message, CommandSender sender, String onHover, ClickEvent onClick, Object... params){
|
||||
public void sendPrefixless(String message, CommandSender sender, String onHover, ClickEvent onClick, Object... params) {
|
||||
send(message, false, sender, ChatMessageType.SYSTEM, onHover, onClick, params);
|
||||
}
|
||||
|
||||
public void send(String message, boolean prefixed, CommandSender sender, ChatMessageType type, String onHover, ClickEvent onClick, Object... params){
|
||||
public void send(String message, boolean prefixed, CommandSender sender, ChatMessageType type, String onHover, ClickEvent onClick, Object... params) {
|
||||
TextComponent msg = parseToComponent(message, prefixed, sender, params);
|
||||
if(onHover != null)
|
||||
if (onHover != null) {
|
||||
msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(onHover)));
|
||||
if(onClick != null)
|
||||
}
|
||||
if (onClick != null) {
|
||||
msg.setClickEvent(onClick);
|
||||
}
|
||||
|
||||
if(sender instanceof Player)
|
||||
BountifulWrapper.impl.sendMessage((Player)sender, type, msg);
|
||||
else
|
||||
if (sender instanceof Player) {
|
||||
BountifulWrapper.impl.sendMessage((Player) sender, type, msg);
|
||||
} else {
|
||||
sender.sendMessage(msg.toPlainText());
|
||||
}
|
||||
}
|
||||
|
||||
/* Send message to all players */
|
||||
|
||||
public void broadcastPrefixless(String message, String onHover, ClickEvent onClick, Object... params){
|
||||
for(Player player : Bukkit.getOnlinePlayers())
|
||||
public void broadcastPrefixless(String message, String onHover, ClickEvent onClick, Object... params) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
sendPrefixless(message, player, parse(onHover, false, player), onClick, params);
|
||||
}
|
||||
}
|
||||
|
||||
public void broadcastPrefixless(String message, Object... params){
|
||||
for(Player player : Bukkit.getOnlinePlayers())
|
||||
public void broadcastPrefixless(String message, Object... params) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
sendPrefixless(message, player, ChatMessageType.SYSTEM, params);
|
||||
}
|
||||
}
|
||||
|
||||
public void broadcastActionbar(String message, Object... params){
|
||||
for(Player player : Bukkit.getOnlinePlayers())
|
||||
public void broadcastActionbar(String message, Object... params) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
send(message, player, ChatMessageType.ACTION_BAR, params);
|
||||
}
|
||||
}
|
||||
|
||||
public void broadcast(String message, String onHover, ClickEvent onClick, Object... params){
|
||||
for(Player player : Bukkit.getOnlinePlayers())
|
||||
public void broadcast(String message, String onHover, ClickEvent onClick, Object... params) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
send(message, player, parse(onHover, false, player), onClick, params);
|
||||
}
|
||||
}
|
||||
|
||||
public void broadcast(String message, Object... params){
|
||||
for(Player player : Bukkit.getOnlinePlayers())
|
||||
public void broadcast(String message, Object... params) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
send(message, player, ChatMessageType.SYSTEM, params);
|
||||
}
|
||||
}
|
||||
|
||||
public void chat(String message, Object... params){
|
||||
for(Player player : Bukkit.getOnlinePlayers())
|
||||
public void chat(String message, Object... params) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
sendPrefixless(message, player, ChatMessageType.CHAT, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class CoreNetworkHandler extends PacketHandler {
|
||||
@Handler
|
||||
public void handlePingPacket(PingPacket packet) {
|
||||
UUID uuid = SteamwarUser.byId(packet.getId()).getUUID();
|
||||
if(Bukkit.getPlayer(uuid) != null) {
|
||||
if (Bukkit.getPlayer(uuid) != null) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
BountifulWrapper.impl.playPling(player);
|
||||
}
|
||||
|
||||
@@ -51,8 +51,9 @@ public class InventoryHandler extends PacketHandler {
|
||||
|
||||
SWInventory inventory = new SWInventory(player, packet.getSize(), packet.getTitle(), items);
|
||||
inventory.addCloseCallback(click -> {
|
||||
if(player.getOpenInventory().getType() != InventoryType.CHEST)
|
||||
if (player.getOpenInventory().getType() != InventoryType.CHEST) {
|
||||
NetworkSender.send(InventoryCallbackPacket.builder().owner(packet.getPlayer()).type(InventoryCallbackPacket.CallbackType.CLOSE).build(), player);
|
||||
}
|
||||
});
|
||||
inventory.open();
|
||||
}
|
||||
|
||||
@@ -19,17 +19,16 @@
|
||||
|
||||
package de.steamwar.network.handlers;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import de.steamwar.linkage.MinVersion;
|
||||
import net.minecraft.network.protocol.game.ClientboundServerDataPacket;
|
||||
import net.minecraft.network.protocol.game.ServerboundChatSessionUpdatePacket;
|
||||
|
||||
@Linked
|
||||
@MinVersion(19)
|
||||
public class ServerDataHandler {
|
||||
|
||||
public ServerDataHandler() {
|
||||
TinyProtocol.instance.addFilter(Reflection.getClass("net.minecraft.network.protocol.game.ClientboundServerDataPacket"), (p, o) -> null);
|
||||
TinyProtocol.instance.addFilter(Reflection.getClass("net.minecraft.network.protocol.game.ServerboundChatSessionUpdatePacket"), (player, packet) -> null);
|
||||
TinyProtocol.instance.addFilter(ClientboundServerDataPacket.class, (p, o) -> null);
|
||||
TinyProtocol.instance.addFilter(ServerboundChatSessionUpdatePacket.class, (player, packet) -> null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ public class BauServerInfo {
|
||||
static {
|
||||
try {
|
||||
bauOwner = Integer.parseInt(Bukkit.getWorlds().get(0).getName());
|
||||
} catch (NumberFormatException ignored) {}
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static Integer getOwnerId() {
|
||||
|
||||
@@ -20,12 +20,54 @@
|
||||
package de.steamwar.scoreboard;
|
||||
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.VersionDependent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scoreboard.DisplaySlot;
|
||||
import org.bukkit.scoreboard.Objective;
|
||||
import org.bukkit.scoreboard.Scoreboard;
|
||||
|
||||
public interface SWScoreboard {
|
||||
public static final SWScoreboard impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
boolean createScoreboard(Player player, ScoreboardCallback callback);
|
||||
void removeScoreboard(Player player);
|
||||
public class SWScoreboard {
|
||||
public static final SWScoreboard impl = new SWScoreboard();
|
||||
|
||||
private static final HashMap<Player, ScoreboardCallback> playerBoards = new HashMap<>();
|
||||
private static final String SIDEBAR = "sw-sidebar";
|
||||
|
||||
static {
|
||||
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
|
||||
for (Map.Entry<Player, ScoreboardCallback> scoreboard : playerBoards.entrySet()) {
|
||||
render(scoreboard.getKey(), scoreboard.getValue());
|
||||
}
|
||||
}, 10, 5);
|
||||
}
|
||||
|
||||
private static void render(Player player, ScoreboardCallback callback) {
|
||||
if (player.getScoreboard().getObjective(SIDEBAR) != null) {
|
||||
player.getScoreboard().getObjective(SIDEBAR).unregister();
|
||||
}
|
||||
|
||||
Objective objective = player.getScoreboard().registerNewObjective(SIDEBAR, "dummy", Component.text(callback.getTitle()));
|
||||
objective.setAutoUpdateDisplay(true);
|
||||
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||
|
||||
callback.getData().forEach((text, score) -> objective.getScore(text).setScore(score));
|
||||
}
|
||||
|
||||
public boolean createScoreboard(Player player, ScoreboardCallback callback) {
|
||||
Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
|
||||
player.setScoreboard(scoreboard);
|
||||
|
||||
render(player, callback);
|
||||
|
||||
playerBoards.put(player, callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void removeScoreboard(Player player) {
|
||||
player.getScoreboard().getObjective(SIDEBAR).unregister();
|
||||
playerBoards.remove(player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,12 +48,12 @@ public class PersonalKit {
|
||||
return kit.getRawArmor();
|
||||
}
|
||||
|
||||
public ItemStack[] getInventory(){
|
||||
public ItemStack[] getInventory() {
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(new StringReader(getRawInventory()));
|
||||
return Objects.requireNonNull(config.getList("Inventory")).toArray(new ItemStack[0]);
|
||||
}
|
||||
|
||||
public ItemStack[] getArmor(){
|
||||
public ItemStack[] getArmor() {
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(new StringReader(getRawArmor()));
|
||||
return Objects.requireNonNull(config.getList("Armor")).toArray(new ItemStack[4]);
|
||||
}
|
||||
@@ -79,26 +79,24 @@ public class PersonalKit {
|
||||
kit.delete();
|
||||
}
|
||||
|
||||
public static List<PersonalKit> get(int userID, String gamemode){
|
||||
public static List<PersonalKit> get(int userID, String gamemode) {
|
||||
return InternalKit.get(userID, gamemode).stream().map(PersonalKit::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static PersonalKit get(int userID, String gamemode, String name) {
|
||||
InternalKit kit = InternalKit.get(userID, gamemode, name);
|
||||
if(kit == null)
|
||||
return null;
|
||||
if (kit == null) return null;
|
||||
return new PersonalKit(kit);
|
||||
}
|
||||
|
||||
public static PersonalKit create(int userID, String gamemode, String name, ItemStack[] inventory, ItemStack[] armor){
|
||||
public static PersonalKit create(int userID, String gamemode, String name, ItemStack[] inventory, ItemStack[] armor) {
|
||||
InternalKit kit = InternalKit.create(userID, gamemode, name, saveInvConfig("Inventory", inventory), saveInvConfig("Armor", armor));
|
||||
return new PersonalKit(kit);
|
||||
}
|
||||
|
||||
public static PersonalKit getKitInUse(int userID, String gamemode) {
|
||||
InternalKit kit = InternalKit.getKitInUse(userID, gamemode);
|
||||
if(kit == null)
|
||||
return null;
|
||||
if (kit == null) return null;
|
||||
return new PersonalKit(kit);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -46,9 +45,6 @@ public class SQLWrapperImpl implements SQLWrapper<Material> {
|
||||
|
||||
@Override
|
||||
public List<Material> getMaterialWithGreaterBlastResistance(double maxBlastResistance) {
|
||||
if (Core.getVersion() <= 12) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Arrays.stream(Material.values())
|
||||
.filter(material -> !material.isLegacy())
|
||||
.filter(Material::isBlock)
|
||||
@@ -61,11 +57,13 @@ public class SQLWrapperImpl implements SQLWrapper<Material> {
|
||||
@Override
|
||||
public void additionalExceptionMetadata(StringBuilder builder) {
|
||||
builder.append("\nPlayers: ");
|
||||
for (Player player : Bukkit.getOnlinePlayers())
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
builder.append(player.getName()).append(" ");
|
||||
}
|
||||
builder.append("\nWorlds: ");
|
||||
for (World world : Bukkit.getWorlds())
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
builder.append(world.getName()).append(" ");
|
||||
}
|
||||
builder.append("\nServer: ").append(SERVER_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class SchematicData {
|
||||
|
||||
@@ -33,13 +32,11 @@ public class SchematicData {
|
||||
|
||||
public SchematicData(SchematicNode node) {
|
||||
this.data = NodeData.getLatest(node);
|
||||
if(node.isDir())
|
||||
throw new SecurityException("Node is Directory");
|
||||
if (node.isDir()) throw new SecurityException("Node is Directory");
|
||||
}
|
||||
|
||||
public SchematicData(SchematicNode node, int revision) {
|
||||
if(node.isDir())
|
||||
throw new SecurityException("Node is Directory");
|
||||
if (node.isDir()) throw new SecurityException("Node is Directory");
|
||||
|
||||
if (revision < 1) {
|
||||
this.data = NodeData.getLatest(node);
|
||||
|
||||
@@ -20,18 +20,49 @@
|
||||
package de.steamwar.techhider;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.VersionDependent;
|
||||
import net.minecraft.core.IdMapper;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public interface BlockIds {
|
||||
BlockIds impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
public class BlockIds {
|
||||
public static final BlockIds impl = new BlockIds();
|
||||
|
||||
Reflection.Method getCombinedId = Reflection.getTypedMethod(TechHider.block, null, int.class, TechHider.iBlockData);
|
||||
public int materialToId(Material material) {
|
||||
return getCombinedId(getBlock(material).defaultBlockState());
|
||||
}
|
||||
|
||||
int getCombinedId(Object iBlockData);
|
||||
int materialToId(Material material);
|
||||
Set<Integer> materialToAllIds(Material material);
|
||||
private static final FluidState water = Fluids.WATER.getSource(false);
|
||||
private static final Iterable<BlockState> registryBlockId = (Iterable<BlockState>) Reflection.getField(TechHider.block, IdMapper.class, 0).get(null);
|
||||
|
||||
public Set<Integer> materialToAllIds(Material material) {
|
||||
Set<Integer> ids = new HashSet<>();
|
||||
for (BlockState data : getBlock(material).getStateDefinition().getPossibleStates()) {
|
||||
ids.add(getCombinedId(data));
|
||||
}
|
||||
|
||||
if (material == Material.WATER) {
|
||||
for (BlockState data : registryBlockId) {
|
||||
if (data.getFluidState() == water) {
|
||||
ids.add(getCombinedId(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
private Block getBlock(Material material) {
|
||||
return CraftMagicNumbers.getBlock(material);
|
||||
}
|
||||
|
||||
public int getCombinedId(BlockState blockData) {
|
||||
return Block.getId(blockData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,50 +19,64 @@
|
||||
|
||||
package de.steamwar.techhider;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.bukkit.Material;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.SimpleBitStorage;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import de.steamwar.Reflection;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
|
||||
import net.minecraft.util.SimpleBitStorage;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ChunkHider {
|
||||
public static final ChunkHider impl = new ChunkHider();
|
||||
|
||||
public Class<?> mapChunkPacket() {
|
||||
return ClientboundLevelChunkWithLightPacket.class;
|
||||
}
|
||||
|
||||
private static final UnaryOperator<Object> chunkPacketCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkWithLightPacket.class);
|
||||
private static final UnaryOperator<Object> chunkDataCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkPacketData.class);
|
||||
|
||||
private static final Reflection.Field<Integer> chunkXField = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 0);
|
||||
private static final Reflection.Field<Integer> chunkZField = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 1);
|
||||
private static final Reflection.Field<ClientboundLevelChunkPacketData> chunkData = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class, 0);
|
||||
|
||||
private static final Reflection.Field<byte[]> dataField = Reflection.getField(ClientboundLevelChunkPacketData.class, byte[].class, 0);
|
||||
private static final Reflection.Field<List> tileEntities = Reflection.getField(ClientboundLevelChunkPacketData.class, List.class, 0);
|
||||
|
||||
public ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(Player recivingPlayer, Set<String> hiddenBlockEntities , QuadFunction<Player, Integer, Integer, Integer, Boolean> isPlayerPrivilegedToAccessBlockPos, BlockState blockToObfuscateTo, Set<Integer> blockIdsToObfuscate, ClientboundLevelChunkWithLightPacket packet) {
|
||||
int chunkX = packet.getX();
|
||||
int chunkZ = packet.getZ();
|
||||
public BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider techHider) {
|
||||
return (p, packet) -> {
|
||||
int chunkX = chunkXField.get(packet);
|
||||
int chunkZ = chunkZField.get(packet);
|
||||
if (techHider.getLocationEvaluator().skipChunk(p, chunkX, chunkZ)) {
|
||||
return packet;
|
||||
}
|
||||
|
||||
Object clonedPacket = chunkPacketCloner.apply(packet);
|
||||
Object dataWrapper = chunkDataCloner.apply(chunkData.get(clonedPacket));
|
||||
packet = chunkPacketCloner.apply(packet);
|
||||
Object dataWrapper = chunkDataCloner.apply(chunkData.get(packet));
|
||||
|
||||
tileEntities.set(dataWrapper, ((List<?>)tileEntities.get(dataWrapper)).stream().filter(te -> tileEntityVisible(hiddenBlockEntities, te)).collect(Collectors.toList()));
|
||||
Set<String> hiddenBlockEntities = techHider.getHiddenBlockEntities();
|
||||
tileEntities.set(dataWrapper, ((List<?>) tileEntities.get(dataWrapper)).stream().filter(te -> tileEntityVisible(hiddenBlockEntities, te)).collect(Collectors.toList()));
|
||||
|
||||
ByteBuf in = Unpooled.wrappedBuffer(dataField.get(dataWrapper));
|
||||
ByteBuf out = Unpooled.buffer(in.readableBytes() + 64);
|
||||
for(int yOffset = recivingPlayer.getWorld().getMinHeight(); yOffset < recivingPlayer.getWorld().getMaxHeight(); yOffset += 16) {
|
||||
SectionHider section = new SectionHider(recivingPlayer, blockToObfuscateTo, blockIdsToObfuscate, in, out, chunkX, yOffset/16, chunkZ);
|
||||
for (int yOffset = p.getWorld().getMinHeight(); yOffset < p.getWorld().getMaxHeight(); yOffset += 16) {
|
||||
SectionHider section = new SectionHider(p, techHider, in, out, chunkX, yOffset / 16, chunkZ);
|
||||
section.copyBlockCount();
|
||||
|
||||
blocks(section, isPlayerPrivilegedToAccessBlockPos);
|
||||
blocks(section);
|
||||
biomes(section);
|
||||
}
|
||||
|
||||
@@ -76,43 +90,60 @@ public class ChunkHider {
|
||||
|
||||
chunkData.set(packet, dataWrapper);
|
||||
return packet;
|
||||
};
|
||||
}
|
||||
|
||||
private static final Registry<BlockEntityType<?>> registry = Reflection.getField(BuiltInRegistries.class, "BLOCK_ENTITY_TYPE", Registry.class).get(null);
|
||||
private static final Reflection.Method getKey = Reflection.getTypedMethod(Reflection.getClass("net.minecraft.core.Registry"), "getKey", ResourceLocation.class, Object.class);
|
||||
public static final Class<?> tileEntity = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo");
|
||||
protected static final Reflection.Field<BlockEntityType> entityType = Reflection.getField(tileEntity, BlockEntityType.class, 0);
|
||||
private static final Class<?> builtInRegestries = Reflection.getClass("net.minecraft.core.registries.BuiltInRegistries");
|
||||
private static final Class<?> registry = Reflection.getClass("net.minecraft.core.Registry");
|
||||
private static final Reflection.Field<?> nameField = Reflection.getField(builtInRegestries, "BLOCK_ENTITY_TYPE", registry);
|
||||
private static final Class<?> resourceLocation = Reflection.getClass("net.minecraft.resources.ResourceLocation");
|
||||
private static final Reflection.Method getKey = Reflection.getTypedMethod(registry, "getKey", resourceLocation, Object.class);
|
||||
private static final Reflection.Method getName = Reflection.getTypedMethod(resourceLocation, "getPath", String.class);
|
||||
|
||||
protected boolean tileEntityVisible(Set<String> hiddenBlockEntities, Object tile) {
|
||||
return !hiddenBlockEntities.contains(getName.invoke(getKey.invoke(nameField.get(null), entityType.get(tile))));
|
||||
BlockEntityType type = entityType.get(tile);
|
||||
String path = ((ResourceLocation) getKey.invoke(registry, type)).getPath();
|
||||
return !hiddenBlockEntities.contains(path);
|
||||
}
|
||||
|
||||
private void blocks(SectionHider section, QuadFunction<Player, Integer, Integer, Integer, Boolean> isPlayerPrivilegedToAccessBlockPos) {
|
||||
private void blocks(SectionHider section) {
|
||||
section.copyBitsPerBlock();
|
||||
|
||||
boolean singleValued = section.getBitsPerBlock() == 0;
|
||||
if (singleValued) {
|
||||
int value = ProtocolUtils.readVarInt(section.getIn());
|
||||
ProtocolUtils.writeVarInt(section.getOut(), section.getBlockIdsToObfuscate().contains(value) ? section.getTarget() : value);
|
||||
ProtocolUtils.writeVarInt(section.getOut(), !section.isSkipSection() && section.getObfuscate().contains(value) ? section.getTarget() : value);
|
||||
return;
|
||||
} else if (section.getBitsPerBlock() < 9) {
|
||||
// Indirect (paletted) storage – only present when bitsPerBlock < 9 in 1.21+
|
||||
section.processPalette();
|
||||
}
|
||||
|
||||
if (section.isSkipSection() || (!section.blockPrecise() && section.isPaletted())) {
|
||||
section.skipNewDataArray(4096);
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleBitStorage values = new SimpleBitStorage(section.getBitsPerBlock(), 4096, section.readNewDataArray(4096));
|
||||
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int pos = (((y * 16) + z) * 16) + x;
|
||||
int blockId = values.get(pos);
|
||||
|
||||
if(!isPlayerPrivilegedToAccessBlockPos.apply(section.player, section.getOffsetX() * x, section.getOffsetY() * y, section.getOffsetZ() * z) && !section.getBlockIdsToObfuscate().contains(blockId)) {
|
||||
values.set(pos, section.getTarget());
|
||||
TechHider.State test = section.test(x, y, z);
|
||||
|
||||
switch (test) {
|
||||
case SKIP:
|
||||
break;
|
||||
case CHECK:
|
||||
if (!section.getObfuscate().contains(values.get(pos))) {
|
||||
break;
|
||||
}
|
||||
case HIDE:
|
||||
values.set(pos, section.getTarget());
|
||||
break;
|
||||
case HIDE_AIR:
|
||||
default:
|
||||
values.set(pos, section.getAir());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,9 +154,9 @@ public class ChunkHider {
|
||||
|
||||
private void biomes(SectionHider section) {
|
||||
section.copyBitsPerBlock();
|
||||
if(section.getBitsPerBlock() == 0) {
|
||||
if (section.getBitsPerBlock() == 0) {
|
||||
section.copyVarInt();
|
||||
} else if(section.getBitsPerBlock() < 6) {
|
||||
} else if (section.getBitsPerBlock() < 6) {
|
||||
section.skipPalette();
|
||||
section.skipNewDataArray(64);
|
||||
} else {
|
||||
@@ -163,16 +194,24 @@ public class ChunkHider {
|
||||
this.chunkX = chunkX;
|
||||
this.chunkY = chunkY;
|
||||
this.chunkZ = chunkZ;
|
||||
this.offsetX = 16*chunkX;
|
||||
this.offsetY = 16*chunkY;
|
||||
this.offsetZ = 16*chunkZ;
|
||||
|
||||
this.blockIdsToObfuscate = blockIdsToObfuscate;
|
||||
this.blockIdToObfuscateTo = BlockIds.impl.getCombinedId(blockToObfuscateTo);
|
||||
|
||||
this.offsetX = 16 * chunkX;
|
||||
this.offsetY = 16 * chunkY;
|
||||
this.offsetZ = 16 * chunkZ;
|
||||
this.skipSection = techHider.getLocationEvaluator().skipChunkSection(player, chunkX, chunkY, chunkZ);
|
||||
|
||||
this.paletted = false;
|
||||
this.bitsPerBlock = 0;
|
||||
this.air = TechHider.AIR_ID;
|
||||
this.target = techHider.getObfuscationTargetId();
|
||||
this.obfuscate = techHider.getObfuscateIds();
|
||||
}
|
||||
|
||||
public boolean blockPrecise() {
|
||||
return techHider.getLocationEvaluator().blockPrecise(player, chunkX, chunkY, chunkZ);
|
||||
}
|
||||
|
||||
public TechHider.State test(int x, int y, int z) {
|
||||
return techHider.getLocationEvaluator().check(player, offsetX + x, offsetY + y, offsetZ + z);
|
||||
}
|
||||
|
||||
public void copyBlockCount() {
|
||||
@@ -193,28 +232,35 @@ public class ChunkHider {
|
||||
|
||||
public void skipPalette() {
|
||||
int paletteLength = copyVarInt();
|
||||
for(int i = 0; i < paletteLength; i++)
|
||||
for (int i = 0; i < paletteLength; i++) {
|
||||
copyVarInt();
|
||||
}
|
||||
}
|
||||
|
||||
public void processPalette() {
|
||||
int paletteLength = copyVarInt();
|
||||
if(paletteLength == 0)
|
||||
if (skipSection) {
|
||||
skipPalette();
|
||||
return;
|
||||
}
|
||||
|
||||
int paletteLength = copyVarInt();
|
||||
if (paletteLength == 0) return;
|
||||
|
||||
paletted = true;
|
||||
air = 0;
|
||||
target = 0;
|
||||
|
||||
for(int i = 0; i < paletteLength; i++) {
|
||||
for (int i = 0; i < paletteLength; i++) {
|
||||
int entry = ProtocolUtils.readVarInt(in);
|
||||
if(blockIdsToObfuscate.contains(entry))
|
||||
entry = blockIdToObfuscateTo;
|
||||
if (obfuscate.contains(entry)) {
|
||||
entry = techHider.getObfuscationTargetId();
|
||||
}
|
||||
|
||||
if(entry == BlockIds.impl.materialToId(Material.AIR))
|
||||
if (entry == TechHider.AIR_ID) {
|
||||
air = i;
|
||||
else if(entry == blockIdToObfuscateTo)
|
||||
} else if (entry == techHider.getObfuscationTargetId()) {
|
||||
target = i;
|
||||
}
|
||||
|
||||
ProtocolUtils.writeVarInt(out, entry);
|
||||
}
|
||||
@@ -223,7 +269,7 @@ public class ChunkHider {
|
||||
|
||||
public void skipDataArray() {
|
||||
int dataArrayLength = copyVarInt();
|
||||
out.writeBytes(in, dataArrayLength*8);
|
||||
out.writeBytes(in, dataArrayLength * 8);
|
||||
}
|
||||
|
||||
public void skipNewDataArray(int entries) {
|
||||
@@ -231,15 +277,16 @@ public class ChunkHider {
|
||||
return;
|
||||
}
|
||||
|
||||
char valuesPerLong = (char)(64 / bitsPerBlock);
|
||||
char valuesPerLong = (char) (64 / bitsPerBlock);
|
||||
int i1 = (entries + valuesPerLong - 1) / valuesPerLong;
|
||||
out.writeBytes(in, i1 * Long.BYTES);
|
||||
}
|
||||
|
||||
public long[] readDataArray() {
|
||||
long[] array = new long[copyVarInt()];
|
||||
for(int i = 0; i < array.length; i++)
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = in.readLong();
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
@@ -252,15 +299,17 @@ public class ChunkHider {
|
||||
char valuesPerLong = (char) (64 / bitsPerBlock);
|
||||
int i1 = (entries + valuesPerLong - 1) / valuesPerLong;
|
||||
long[] array = new long[i1];
|
||||
for(int i = 0; i < i1; i++)
|
||||
for (int i = 0; i < i1; i++) {
|
||||
array[i] = in.readLong();
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public void writeDataArray(long[] array) {
|
||||
for(long l : array)
|
||||
for (long l : array) {
|
||||
out.writeLong(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
package de.steamwar.techhider;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import com.google.common.primitives.Bytes;
|
||||
import de.steamwar.Reflection;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
@@ -33,7 +33,8 @@ import java.util.function.BiFunction;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class ProtocolUtils {
|
||||
private ProtocolUtils() {}
|
||||
private ProtocolUtils() {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static BiFunction<Object, UnaryOperator<Object>, Object> arrayCloneGenerator(Class<?> elementClass) {
|
||||
@@ -41,8 +42,9 @@ public class ProtocolUtils {
|
||||
int length = Array.getLength(array);
|
||||
Object result = Array.newInstance(elementClass, length);
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
for (int i = 0; i < length; i++) {
|
||||
Array.set(result, i, worker.apply(Array.get(array, i)));
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
@@ -69,16 +71,17 @@ public class ProtocolUtils {
|
||||
}
|
||||
|
||||
private static BiConsumer<Object, Object> shallowFill(Class<?> clazz) {
|
||||
if(clazz == null)
|
||||
return (source, clone) -> {};
|
||||
if (clazz == null) {
|
||||
return (source, clone) -> {
|
||||
};
|
||||
}
|
||||
|
||||
BiConsumer<Object, Object> superFiller = shallowFill(clazz.getSuperclass());
|
||||
|
||||
Field[] fds = clazz.getDeclaredFields();
|
||||
List<Field> fields = new ArrayList<>();
|
||||
for(Field field : fds) {
|
||||
if (Modifier.isStatic(field.getModifiers()))
|
||||
continue;
|
||||
for (Field field : fds) {
|
||||
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||
|
||||
field.setAccessible(true);
|
||||
fields.add(field);
|
||||
@@ -87,7 +90,7 @@ public class ProtocolUtils {
|
||||
return (source, clone) -> {
|
||||
superFiller.accept(source, clone);
|
||||
try {
|
||||
for(Field field : fields) {
|
||||
for (Field field : fields) {
|
||||
field.set(clone, field.get(source));
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
@@ -97,10 +100,9 @@ public class ProtocolUtils {
|
||||
};
|
||||
}
|
||||
|
||||
public static int posToChunk(int c){
|
||||
public static int posToChunk(int c) {
|
||||
int chunk = c / 16;
|
||||
if(c < 0)
|
||||
chunk--;
|
||||
if (c < 0) chunk--;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@@ -132,8 +134,7 @@ public class ProtocolUtils {
|
||||
int value = (read & 0b01111111);
|
||||
result |= (value << (7 * numRead));
|
||||
|
||||
if (++numRead > 5)
|
||||
throw new SecurityException("VarInt too long");
|
||||
if (++numRead > 5) throw new SecurityException("VarInt too long");
|
||||
} while ((read & 0b10000000) != 0);
|
||||
|
||||
return result;
|
||||
@@ -170,7 +171,7 @@ public class ProtocolUtils {
|
||||
public static byte[] writeVarInt(int value) {
|
||||
List<Byte> buffer = new ArrayList<>(5);
|
||||
do {
|
||||
byte temp = (byte)(value & 0b01111111);
|
||||
byte temp = (byte) (value & 0b01111111);
|
||||
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
|
||||
value >>>= 7;
|
||||
if (value != 0) {
|
||||
@@ -182,20 +183,20 @@ public class ProtocolUtils {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static class ChunkPos{
|
||||
public static class ChunkPos {
|
||||
final int x;
|
||||
final int z;
|
||||
|
||||
public ChunkPos(int x, int z){
|
||||
public ChunkPos(int x, int z) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public final int x(){
|
||||
public final int x() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public final int z(){
|
||||
public final int z() {
|
||||
return z;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,19 +19,77 @@
|
||||
|
||||
package de.steamwar.techhider;
|
||||
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.core.VersionDependent;
|
||||
import de.steamwar.Reflection;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.entity.SignBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public interface ProtocolWrapper {
|
||||
ProtocolWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||
public class ProtocolWrapper {
|
||||
public static final ProtocolWrapper impl = new ProtocolWrapper();
|
||||
|
||||
private static final Reflection.Field<SectionPos> multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, SectionPos.class, 0);
|
||||
private static final Reflection.Field<short[]> multiBlockChangePos = Reflection.getField(TechHider.multiBlockChangePacket, short[].class, 0);
|
||||
private static final Reflection.Field<BlockState[]> multiBlockChangeBlocks = Reflection.getField(TechHider.multiBlockChangePacket, BlockState[].class, 0);
|
||||
|
||||
boolean unfilteredTileEntityDataAction(Object packet);
|
||||
public BiFunction<Player, Object, Object> multiBlockChangeGenerator(TechHider techHider) {
|
||||
return (p, packet) -> {
|
||||
TechHider.LocationEvaluator locationEvaluator = techHider.getLocationEvaluator();
|
||||
Object chunkCoords = multiBlockChangeChunk.get(packet);
|
||||
int chunkX = TechHider.blockPositionX.get(chunkCoords);
|
||||
int chunkY = TechHider.blockPositionY.get(chunkCoords);
|
||||
int chunkZ = TechHider.blockPositionZ.get(chunkCoords);
|
||||
if (locationEvaluator.skipChunkSection(p, chunkX, chunkY, chunkZ)) {
|
||||
return packet;
|
||||
}
|
||||
|
||||
BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider);
|
||||
packet = TechHider.multiBlockChangeCloner.apply(packet);
|
||||
final short[] oldPos = multiBlockChangePos.get(packet);
|
||||
final BlockState[] oldBlocks = multiBlockChangeBlocks.get(packet);
|
||||
ArrayList<Short> poss = new ArrayList<>(oldPos.length);
|
||||
ArrayList<BlockState> blocks = new ArrayList<>(oldPos.length);
|
||||
for (int i = 0; i < oldPos.length; i++) {
|
||||
short pos = oldPos[i];
|
||||
BlockState block = oldBlocks[i];
|
||||
switch (locationEvaluator.check(p, 16 * chunkX + (pos >> 8 & 0xF), 16 * chunkY + (pos & 0xF), 16 * chunkZ + (pos >> 4 & 0xF))) {
|
||||
case SKIP:
|
||||
poss.add(pos);
|
||||
blocks.add(block);
|
||||
break;
|
||||
case CHECK:
|
||||
poss.add(pos);
|
||||
blocks.add(techHider.iBlockDataHidden(block) ? (BlockState) techHider.getObfuscationTarget() : block);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BiFunction<Player, Object, Object> multiBlockChangeGenerator(TechHider techHider);
|
||||
if (blocks.isEmpty()) return null;
|
||||
|
||||
short[] newPos = new short[poss.size()];
|
||||
for (int i = 0; i < newPos.length; i++) {
|
||||
newPos[i] = poss.get(i);
|
||||
}
|
||||
|
||||
multiBlockChangePos.set(packet, newPos);
|
||||
multiBlockChangeBlocks.set(packet, blocks.toArray(new BlockState[0]));
|
||||
return packet;
|
||||
};
|
||||
}
|
||||
|
||||
private static final Reflection.Field<BlockEntityType> tileEntityType = Reflection.getField(TechHider.tileEntityDataPacket, BlockEntityType.class, 0);
|
||||
private static final BlockEntityType<?> signType = Reflection.getField(BlockEntityType.class, BlockEntityType.class, 0, SignBlockEntity.class).get(null);
|
||||
|
||||
public boolean unfilteredTileEntityDataAction(Object packet) {
|
||||
return tileEntityType.get(packet) != signType;
|
||||
}
|
||||
|
||||
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user