forked from SteamWar/SteamWar
Compare commits
264
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12e085600e | ||
|
|
f8cda32119 | ||
|
|
867ca6f5dc | ||
|
|
badff1c70f | ||
|
|
1d2ac4f705 | ||
|
|
b48c75ef74 | ||
|
|
8b6ea12a08 | ||
|
|
801678ddd3 | ||
|
|
e5cc874834 | ||
|
|
95119fc93f | ||
|
|
d84ca3547a | ||
|
|
25ab79abc0 | ||
|
|
582d6a62e3 | ||
|
|
5eec792aff
|
||
|
|
e0f26c3e8d
|
||
|
|
a59e9b4343 | ||
|
|
a8c68864d8 | ||
|
|
c0668723d7 | ||
|
|
5bc2daf37a | ||
|
|
e6d39da36b | ||
|
|
390d388692 | ||
|
|
9a60ac228c | ||
|
|
dab443b989 | ||
|
|
bf3c65c630 | ||
|
|
b488c4ed7c | ||
|
|
2e795aaf8e | ||
|
|
7a601235f5 | ||
|
|
62e855ec1b
|
||
|
|
9e7311934f | ||
|
|
6fd3e6f690
|
||
|
|
7acd51fd61
|
||
|
|
b278ca15f3
|
||
|
|
029249c2b0
|
||
|
|
1ceb10439b
|
||
|
|
a5dfe6ab7e
|
||
|
|
c8a5f567eb | ||
|
|
47fb4da85b
|
||
|
|
0eef22aab0 | ||
|
|
013d18614f | ||
|
|
c7c1ab64e0 | ||
|
|
b68a27fbb6 | ||
|
|
7038dc2aa5
|
||
|
|
7af586ec16
|
||
|
|
b04e99ce54 | ||
|
|
524702fbb9 | ||
|
|
e07298e748 | ||
|
|
e1df793e9f | ||
|
|
806a1affea | ||
|
|
c538cdbbd2 | ||
|
|
d7ba19049a | ||
|
|
47909b6f07 | ||
|
|
48846a698f | ||
|
|
b771c95b99 | ||
|
|
d0aada2b00 | ||
|
|
6522fc77f2 | ||
|
|
27e01a56ae | ||
|
|
ed89770c0f | ||
|
|
3ec3c90f04 | ||
|
|
73d4ed26c8 | ||
|
|
256bcfb1bf | ||
|
|
28ce288815 | ||
|
|
6599dd026a | ||
|
|
03052b677f | ||
|
|
f76a6fa79d | ||
|
|
7fb7f46ca7 | ||
|
|
1269b7f00a | ||
|
|
91a0685724 | ||
|
|
72dd2ef59a | ||
|
|
54a1549973 | ||
|
|
fd5f5b92b4 | ||
|
|
60dc5e4442 | ||
|
|
4cdaf759af | ||
|
|
6e919d9148 | ||
|
|
a20ec8c93d | ||
|
|
18b65a2984 | ||
|
|
669235709e | ||
|
|
796e154c1c | ||
|
|
9efe35fe0d | ||
|
|
e0aaacd66a | ||
|
|
7adb1e8b4a | ||
|
|
b88e592e79 | ||
|
|
914134600e | ||
|
|
27877938bc
|
||
|
|
701964c2f2 | ||
|
|
70c8678c60
|
||
|
|
6cbfc94e6d | ||
|
|
c0ff123279 | ||
|
|
5511a1f08e | ||
|
|
8c8da355bb | ||
|
|
7326ed4aa0 | ||
|
|
2d59eb81c7 | ||
|
|
711920464a | ||
|
|
117dbd08ae | ||
|
|
b36464e69e | ||
|
|
f5ac006c0c | ||
|
|
414bfbfe3c | ||
|
|
c362a3e1f0 | ||
|
|
2b43af8851 | ||
|
|
1590f8f0ee | ||
|
|
932732737d | ||
|
|
2bc164c1b0 | ||
|
|
aa66b3dc83 | ||
|
|
f5d9c6e175 | ||
|
|
36b31fac77 | ||
|
|
641cefad01 | ||
|
|
eb866125ea | ||
|
|
961331f029 | ||
|
|
786257ad0e | ||
|
|
997292d58e | ||
|
|
8050f51424
|
||
|
|
e176b3bca8 | ||
|
|
a6681ffaf6
|
||
|
|
a23530074c
|
||
|
|
e88a4c624b
|
||
|
|
105beaf7a6 | ||
|
|
5f7ab3cd7b
|
||
|
|
f81f05c3d0 | ||
|
|
0afb6ce06a | ||
|
|
5ce69e6b7a
|
||
|
|
a938abde3f | ||
|
|
ec9b0387c5 | ||
|
|
03c3d49659 | ||
|
|
8d9a77ab67 | ||
|
|
fc2997e011 | ||
|
|
8eb5f5ddf2 | ||
|
|
aa807060f4 | ||
|
|
9bbbab9d4b | ||
|
|
7cca4ada10 | ||
|
|
725e6df047 | ||
|
|
f3ce124a23 | ||
|
|
e83f72a53e | ||
|
|
def0c19e43 | ||
|
|
3810ccd63d | ||
|
|
9e43d5cd1b | ||
|
|
2ad9ae3c7f | ||
|
|
847eb3fe5d | ||
|
|
8fa9f7b0d3 | ||
|
|
559cae2b6d | ||
|
|
5dbf3638d0 | ||
|
|
a018af1c8a | ||
|
|
fd8f942014 | ||
|
|
eab8826583 | ||
|
|
bc0177df43 | ||
|
|
1dc78b8eb8 | ||
|
|
a9fb982143 | ||
|
|
5b8d881e01 | ||
|
|
eb55f4b395 | ||
|
|
273db91d06 | ||
|
|
983ad544c1 | ||
|
|
a6a34b2221 | ||
|
|
6c6bd19038 | ||
|
|
89e05cd109 | ||
|
|
ea9d7ac584 | ||
|
|
17e1cf53b0 | ||
|
|
f64f337f17 | ||
|
|
c5f5be7d58 | ||
|
|
9f18644763 | ||
|
|
1de17d27f4 | ||
|
|
3cd0db9bdf | ||
|
|
9711b48f2f | ||
|
|
9934b8bbb2
|
||
|
|
6447265b90 | ||
|
|
71258318db | ||
|
|
52e95e2649 | ||
|
|
de6ac2cf20 | ||
|
|
628001e693 | ||
|
|
47c148d64a | ||
|
|
78617d5a98 | ||
|
|
69b924ded6 | ||
|
|
002f7e5542 | ||
|
|
5d70f75ac9 | ||
|
|
7f21a31ec9 | ||
|
|
23b5ab3e82 | ||
|
|
4f9fe07951 | ||
|
|
3bcff4c5ce | ||
|
|
1810cb7546 | ||
|
|
e55ca911c4 | ||
|
|
793f2de6c3 | ||
|
|
54fa47bd99 | ||
|
|
14a770b207 | ||
|
|
7b3a04f4eb | ||
|
|
f2a06057a8 | ||
|
|
e11f3f7cbc | ||
|
|
ebc10c1ce4 | ||
|
|
d682e35159 | ||
|
|
7d74eb0c09 | ||
|
|
7e18207b87 | ||
|
|
72b23ad116 | ||
|
|
c508627d92 | ||
|
|
93ff982649 | ||
|
|
21f6394359 | ||
|
|
29d0c8978c | ||
|
|
7366f83b15 | ||
|
|
9240bcfd5f | ||
|
|
bede8caa82 | ||
|
|
108aa2af9a | ||
|
|
d07a86c13f | ||
|
|
29106d5bb5 | ||
|
|
32fd4b4630 | ||
|
|
c241aef932 | ||
|
|
2db24ef2eb | ||
|
|
a2caa79f99 | ||
|
|
e49cfa9495 | ||
|
|
1f44b3169e | ||
|
|
49fafa5955 | ||
|
|
c81e6b15e5 | ||
|
|
dc0365834a | ||
|
|
13334e03a4 | ||
|
|
b35b2c0138 | ||
|
|
6ef311ce68 | ||
|
|
68d9c55525 | ||
|
|
dcd70c5ced | ||
|
|
a1d22b7d77 | ||
|
|
3b6fdbeec3 | ||
|
|
714f86a55b | ||
|
|
a177cc4faf | ||
|
|
09aa2ee22c | ||
|
|
b8499a7a8a | ||
|
|
e50bff3d38 | ||
|
|
8424f842c3 | ||
|
|
8f23f57415 | ||
|
|
3b65b93e73 | ||
|
|
4a458f0e92 | ||
|
|
5f5a98bcd6 | ||
|
|
72df919312 | ||
|
|
7ed36fe56e | ||
|
|
a7a8c4d051 | ||
|
|
5da3767378 | ||
|
|
53f98d4cd7 | ||
|
|
48fb6b5ed7 | ||
|
|
24d8ec7301 | ||
|
|
ba29e5cf23 | ||
|
|
a5992a9e4e | ||
|
|
e94eac9b9d
|
||
|
|
a000beee20 | ||
|
|
2fd6c40b15 | ||
|
|
32a2cbb4dd | ||
|
|
cf7a1ee086 | ||
|
|
8da7956523 | ||
|
|
9b821ff08f | ||
|
|
ae6f279dcf | ||
|
|
aead25650e | ||
|
|
53ada2de83 | ||
|
|
496cc3121c | ||
|
|
270d82eb71 | ||
|
|
9f319128cc | ||
|
|
3bd1cf7167 | ||
|
|
723a7dc0ca | ||
|
|
88de28ed68 | ||
|
|
6f1a3fe70c | ||
|
|
4a43e09a8b | ||
|
|
0452a9faa5 | ||
|
|
9a75f38226 | ||
|
|
42808f40c0 | ||
|
|
57c21122e6 | ||
|
|
42faba70d9 | ||
|
|
99e1f01869 | ||
|
|
13bddbe359 | ||
|
|
51ff0e1a9f | ||
|
|
6766862a00 | ||
|
|
c30aad179b | ||
|
|
d3aad6a198 | ||
|
|
744dc67ca9 | ||
|
|
164a7f5826 |
@@ -51,6 +51,7 @@ jobs:
|
||||
rm -rf deploy
|
||||
mkdir -p deploy
|
||||
|
||||
cp "AccessWidener/build/libs/AccessWidener-all.jar" "deploy/AccessWidener.jar"
|
||||
cp "BauSystem/build/libs/BauSystem-all.jar" "deploy/BauSystem.jar"
|
||||
cp "FightSystem/build/libs/FightSystem-all.jar" "deploy/FightSystem.jar"
|
||||
cp "KotlinCore/build/libs/KotlinCore-all.jar" "deploy/KotlinCore.jar"
|
||||
|
||||
@@ -15,6 +15,11 @@ bin/
|
||||
.vscode
|
||||
.settings
|
||||
|
||||
# Language Server
|
||||
**/.project
|
||||
**/.factorypath
|
||||
**/.classpath
|
||||
|
||||
# Other
|
||||
lib
|
||||
/WebsiteBackend/data
|
||||
|
||||
Generated
+151
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="LanguageInjectionConfiguration">
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>AsyncQueryRunner (org.apache.commons.dbutils)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("batch").withParameterCount(2).definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("insertBatch").withParameterCount(3).definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "insert").withParameters("java.lang.String", "org.apache.commons.dbutils.ResultSetHandler").definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "insert").withParameters("java.lang.String", "org.apache.commons.dbutils.ResultSetHandler", "java.lang.Object...").definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("update").withParameters("java.lang.String").definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("update").withParameters("java.lang.String", "java.lang.Object").definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("update").withParameters("java.lang.String", "java.lang.Object...").definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("batch").withParameterCount(3).definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("insertBatch").withParameterCount(4).definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("query", "insert").withParameters("java.sql.Connection", "java.lang.String", "org.apache.commons.dbutils.ResultSetHandler").definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("query", "insert").withParameters("java.sql.Connection", "java.lang.String", "org.apache.commons.dbutils.ResultSetHandler", "java.lang.Object...").definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("update").withParameters("java.sql.Connection", "java.lang.String").definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("update").withParameters("java.sql.Connection", "java.lang.String", "java.lang.Object").definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("update").withParameters("java.sql.Connection", "java.lang.String", "java.lang.Object...").definedInClass("org.apache.commons.dbutils.AsyncQueryRunner"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>Jodd (jodd.db)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query").withParameterCount(1).definedInClass("jodd.db.DbQuery"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("DbQuery").withParameterCount(2).definedInClass("jodd.db.DbQuery"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("query").withParameterCount(2).definedInClass("jodd.db.DbQuery"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(2, psiMethod().withName("DbQuery").withParameterCount(3).definedInClass("jodd.db.DbQuery"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>MyBatis @Select/@Delete/@Insert/@Update</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiMethod().withName("value").withParameters().definedInClass("org.apache.ibatis.annotations.Delete")]]></place>
|
||||
<place><![CDATA[psiMethod().withName("value").withParameters().definedInClass("org.apache.ibatis.annotations.Insert")]]></place>
|
||||
<place><![CDATA[psiMethod().withName("value").withParameters().definedInClass("org.apache.ibatis.annotations.Select")]]></place>
|
||||
<place><![CDATA[psiMethod().withName("value").withParameters().definedInClass("org.apache.ibatis.annotations.Update")]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>QueryRunner (org.apache.commons.dbutils)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("batch").withParameterCount(2).definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("insertBatch").withParameterCount(3).definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "insert").withParameters("java.lang.String", "org.apache.commons.dbutils.ResultSetHandler").definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "insert", "execute").withParameters("java.lang.String", "org.apache.commons.dbutils.ResultSetHandler", "java.lang.Object...").definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("update").withParameters("java.lang.String").definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("update").withParameters("java.lang.String", "java.lang.Object").definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("update", "execute").withParameters("java.lang.String", "java.lang.Object...").definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("batch").withParameterCount(3).definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("insertBatch").withParameterCount(4).definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("query", "insert").withParameters("java.sql.Connection", "java.lang.String", "org.apache.commons.dbutils.ResultSetHandler", "java.lang.Object...").definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("query", "insert", "execute").withParameters("java.sql.Connection", "java.lang.String", "org.apache.commons.dbutils.ResultSetHandler").definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("update").withParameters("java.sql.Connection", "java.lang.String").definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("update").withParameters("java.sql.Connection", "java.lang.String", "java.lang.Object").definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("update", "execute").withParameters("java.sql.Connection", "java.lang.String", "java.lang.Object...").definedInClass("org.apache.commons.dbutils.QueryRunner"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>R2DBC (io.r2dbc)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("add").definedInClass("io.r2dbc.spi.Batch"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("createStatement").definedInClass("io.r2dbc.spi.Connection"))]]></place>
|
||||
</injection>
|
||||
<injection language="PostgreSQL" injector-id="java">
|
||||
<display-name>Reactiverse Postgres Client (io.reactiverse)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch").definedInClass("io.reactiverse.pgclient.PgConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch").definedInClass("io.reactiverse.pgclient.PgTransaction"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPrepare", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.reactiverse.reactivex.pgclient.PgClient"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPrepare", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.reactiverse.reactivex.pgclient.PgConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPrepare", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.reactiverse.reactivex.pgclient.PgPool"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPrepare", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.reactiverse.reactivex.pgclient.PgTransaction"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "preparedQuery", "preparedBatch").definedInClass("io.reactiverse.axle.pgclient.PgClient"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "preparedQuery", "preparedBatch").definedInClass("io.reactiverse.pgclient.PgClient"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "preparedQuery", "preparedBatch").definedInClass("io.reactiverse.pgclient.PgPool"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>SmallRye Axle SqlClient (io.vertx.axle.sqlclient)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "preparedQuery", "preparedBatch").definedInClass("io.vertx.axle.sqlclient.Pool"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "preparedQuery", "preparedBatch").definedInClass("io.vertx.axle.sqlclient.SqlClient"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>SmallRye Mutiny SqlClient (io.vertx.mutiny.sqlclient)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "preparedQuery", "preparedBatch").definedInClass("io.vertx.mutiny.sqlclient.Pool"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "preparedQuery", "preparedBatch").definedInClass("io.vertx.mutiny.sqlclient.SqlClient"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>SmallRye Mutiny SqlConnection (io.vertx.mutiny.sqlclient)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("prepare", "prepareAndAwait").definedInClass("io.vertx.mutiny.db2client.DB2Connection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("prepare", "prepareAndAwait").definedInClass("io.vertx.mutiny.mssqlclient.MSSQLConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("prepare", "prepareAndAwait").definedInClass("io.vertx.mutiny.mysqlclient.MySQLConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("prepare", "prepareAndAwait").definedInClass("io.vertx.mutiny.pgclient.PgConnection"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>Vert.x SQL Extensions (io.vertx.ext.sql)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "queryWithParams", "queryStream", "queryStreamWithParams", "querySingle", "querySingleWithParams", "update", "updateWithParams", "call", "callWithParams").definedInClass("io.vertx.ext.sql.SQLClient"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "queryWithParams", "queryStream", "queryStreamWithParams", "querySingle", "querySingleWithParams", "update", "updateWithParams", "call", "callWithParams").definedInClass("io.vertx.ext.sql.SQLOperations"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "queryWithParams", "queryStream", "queryStreamWithParams", "querySingle", "querySingleWithParams", "update", "updateWithParams", "call", "callWithParams", "execute", "batchWithParams", "batchCallableWithParams").definedInClass("io.vertx.ext.sql.SQLConnection"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>Vert.x SQL Reactive Extensions (io.vertx.reactivex.ext.sql)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "queryWithParams", "queryStream", "queryStreamWithParams", "querySingle", "querySingleWithParams", "update", "updateWithParams", "call", "callWithParams").definedInClass("io.vertx.reactivex.ext.sql.SQLOperations"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "queryWithParams", "queryStream", "queryStreamWithParams", "querySingle", "querySingleWithParams", "update", "updateWithParams", "call", "callWithParams", "execute", "batchWithParams", "batchCallableWithParams", "rxQuerySingle", "rxQuerySingleWithParams", "rxQuery", "rxQueryWithParams", "rxQueryStream", "rxQueryStreamWithParams", "rxUpdate", "rxUpdateWithParams", "rxCall", "rxCallWithParams", "rxExecute", "rxBatchWithParams", "rxBatchCallableWithParams").definedInClass("io.vertx.reactivex.ext.sql.SQLClient"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "queryWithParams", "queryStream", "queryStreamWithParams", "querySingle", "querySingleWithParams", "update", "updateWithParams", "call", "callWithParams", "execute", "batchWithParams", "batchCallableWithParams", "rxQuerySingle", "rxQuerySingleWithParams", "rxQuery", "rxQueryWithParams", "rxQueryStream", "rxQueryStreamWithParams", "rxUpdate", "rxUpdateWithParams", "rxCall", "rxCallWithParams", "rxExecute", "rxBatchWithParams", "rxBatchCallableWithParams").definedInClass("io.vertx.reactivex.ext.sql.SQLConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("querySingle", "rxQuerySingle", "querySingleWithParams", "rxQuerySingleWithParams").definedInClass("io.vertx.reactivex.ext.asyncsql.AsyncSQLClient"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("querySingle", "rxQuerySingle", "querySingleWithParams", "rxQuerySingleWithParams").definedInClass("io.vertx.reactivex.ext.asyncsql.MySQLClient"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("querySingle", "rxQuerySingle", "querySingleWithParams", "rxQuerySingleWithParams").definedInClass("io.vertx.reactivex.ext.asyncsql.PostgreSQLClient"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>Vert.x SqlClient (io.vertx.sqlclient)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch").definedInClass("io.vertx.mssqlclient.MSSQLConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch").definedInClass("io.vertx.mysqlclient.MySQLConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch").definedInClass("io.vertx.pgclient.PgConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch").definedInClass("io.vertx.sqlclient.Pool"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch").definedInClass("io.vertx.sqlclient.SqlClient"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch").definedInClass("io.vertx.sqlclient.SqlConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch").definedInClass("io.vertx.sqlclient.Transaction"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>Vert.x SqlClient RxJava2 (io.vertx.reactivex.sqlclient)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPrepare", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.vertx.reactivex.mysqlclient.MySQLConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPrepare", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.vertx.reactivex.pgclient.PgConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPrepare", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.vertx.reactivex.sqlclient.SqlConnection"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPrepare", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.vertx.reactivex.sqlclient.Transaction"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.vertx.reactivex.mysqlclient.MySQLPool"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.vertx.reactivex.pgclient.PgPool"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.vertx.reactivex.sqlclient.Pool"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "prepare", "preparedQuery", "preparedBatch", "rxQuery", "rxPreparedQuery", "rxPreparedBatch").definedInClass("io.vertx.reactivex.sqlclient.SqlClient"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>jOOQ (org.jooq.DSLContext)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("batch").withParameters("java.lang.String", "java.lang.Object[]...").definedInClass("org.jooq.DSLContext"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "fetch", "fetchLazy", "fetchAsync", "fetchStream", "fetchMany", "fetchOne", "fetchSingle", "fetchOptional", "fetchValue", "fetchOptionalValue", "fetchValues", "execute", "resultQuery").withParameters("java.lang.String", "java.lang.Object...").definedInClass("org.jooq.DSLContext"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("query", "fetch", "fetchLazy", "fetchAsync", "fetchStream", "fetchMany", "fetchOne", "fetchSingle", "fetchOptional", "fetchValue", "fetchOptionalValue", "fetchValues", "execute", "resultQuery", "batch").withParameters("java.lang.String").definedInClass("org.jooq.DSLContext"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(psiMethod().withName("batch").withParameters("java.lang.String...").definedInClass("org.jooq.DSLContext"))]]></place>
|
||||
</injection>
|
||||
<injection language="SQL" injector-id="java">
|
||||
<display-name>rxjava2-jdbc (org.davidmoten.rx.jdbc)</display-name>
|
||||
<single-file value="true" />
|
||||
<place><![CDATA[psiMethod().withName("value").definedInClass("org.davidmoten.rx.jdbc.annotations.Query")]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("call", "select", "update").definedInClass("org.davidmoten.rx.jdbc.Database"))]]></place>
|
||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("call", "select", "update").definedInClass("org.davidmoten.rx.jdbc.TransactedBuilder"))]]></place>
|
||||
</injection>
|
||||
</component>
|
||||
</project>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Remote JVM Debugger" type="Remote">
|
||||
<option name="USE_SOCKET_TRANSPORT" value="true" />
|
||||
<option name="SERVER_MODE" value="false" />
|
||||
<option name="SHMEM_ADDRESS" />
|
||||
<option name="HOST" value="localhost" />
|
||||
<option name="PORT" value="5005" />
|
||||
<option name="AUTO_RESTART" value="false" />
|
||||
<RunnerSettings RunnerId="Debug">
|
||||
<option name="DEBUG_PORT" value="5005" />
|
||||
<option name="LOCAL" value="false" />
|
||||
</RunnerSettings>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
alias(libs.plugins.shadow)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.ow2.asm:asm:9.7")
|
||||
implementation("org.ow2.asm:asm-commons:9.7")
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
manifest {
|
||||
attributes(
|
||||
"Manifest-Version" to "1.0",
|
||||
"Build-Jdk-Spec" to "21",
|
||||
"Main-Class" to "de.steamwar.Main",
|
||||
"Premain-Class" to "de.steamwar.Agent",
|
||||
"Can-Retransform-Classes" to "true",
|
||||
"Can-Redefine-Classes" to "true",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.shadowJar)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A single parsed line from a .accesswidener file.
|
||||
* <p>
|
||||
* Examples:
|
||||
* accessible class net/minecraft/server/level/ServerPlayer
|
||||
* accessible method net/minecraft/server/level/ServerPlayer getStats ()V
|
||||
* mutable field net/minecraft/world/entity/Entity id I
|
||||
* extendable class net/minecraft/world/level/chunk/LevelChunk
|
||||
*/
|
||||
public record AccessWidenerEntry(
|
||||
/** accessible | mutable | extendable (may have "transitive-" prefix) */
|
||||
String directive,
|
||||
/** class | method | field */
|
||||
String memberType,
|
||||
/** Internal class name, e.g. net/minecraft/server/level/ServerPlayer */
|
||||
String target,
|
||||
/** Method/field name, null for class entries */
|
||||
String name,
|
||||
/** Descriptor, null for class entries */
|
||||
String descriptor) {
|
||||
/**
|
||||
* Returns true if this entry targets the class with the given internal name.
|
||||
*/
|
||||
public boolean targets(String internalName) {
|
||||
return target.equals(internalName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Parses Fabric-compatible .accesswidener files.
|
||||
* <p>
|
||||
* Supported format:
|
||||
* <pre>
|
||||
* accessWidener v2 named
|
||||
*
|
||||
* # comments are supported
|
||||
* accessible class net/minecraft/Foo
|
||||
* accessible method net/minecraft/Foo someMethod ()V
|
||||
* accessible field net/minecraft/Foo someField I
|
||||
* mutable field net/minecraft/Foo someField I
|
||||
* extendable class net/minecraft/Foo
|
||||
* extendable method net/minecraft/Foo someMethod ()V
|
||||
*
|
||||
* # transitive variants (expose widening to dependents)
|
||||
* transitive-accessible class net/minecraft/Foo
|
||||
* </pre>
|
||||
*/
|
||||
public final class AccessWidenerParser {
|
||||
|
||||
private AccessWidenerParser() {
|
||||
}
|
||||
|
||||
public static List<AccessWidenerEntry> parse(InputStream in) throws IOException {
|
||||
List<AccessWidenerEntry> entries = new ArrayList<>();
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
|
||||
|
||||
String line;
|
||||
boolean headerSeen = false;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
// Strip inline comments
|
||||
int commentIdx = line.indexOf('#');
|
||||
if (commentIdx >= 0) line = line.substring(0, commentIdx);
|
||||
line = line.strip();
|
||||
|
||||
if (line.isEmpty()) continue;
|
||||
|
||||
if (!headerSeen) {
|
||||
// First non-blank, non-comment line must be the header
|
||||
if (!line.startsWith("accessWidener")) {
|
||||
throw new IOException("Missing accessWidener header, got: " + line);
|
||||
}
|
||||
headerSeen = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
AccessWidenerEntry entry = parseLine(line);
|
||||
if (entry != null) entries.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static AccessWidenerEntry parseLine(String line) {
|
||||
String[] parts = line.split("\\s+");
|
||||
if (parts.length < 3) return null;
|
||||
|
||||
String directive = parts[0]; // accessible / mutable / extendable / transitive-*
|
||||
String memberType = parts[1]; // class / method / field
|
||||
String target = parts[2]; // internal class name
|
||||
|
||||
return switch (memberType) {
|
||||
case "class" -> new AccessWidenerEntry(directive, "class", target, null, null);
|
||||
case "method", "field" -> {
|
||||
if (parts.length < 5) yield null;
|
||||
yield new AccessWidenerEntry(directive, memberType, target, parts[3], parts[4]);
|
||||
}
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Java agent entry point.
|
||||
* <p>
|
||||
* At JVM startup: java -javaagent:paper-access-widener-agent.jar -jar server.jar
|
||||
* <p>
|
||||
* On attach the agent:
|
||||
* <ol>
|
||||
* <li>Find all .jar files inside the plugins folder</li>
|
||||
* <li>Scan all found jars for *.accesswidener resources</li>
|
||||
* <li>Transform any class during loading</li>
|
||||
* </ol>
|
||||
*/
|
||||
public class Agent {
|
||||
private Agent() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
private static final Logger LOG = Logger.getLogger("AccessWidenerAgent");
|
||||
|
||||
// -javaagent: startup
|
||||
public static void premain(String args, Instrumentation inst) {
|
||||
init(inst);
|
||||
}
|
||||
|
||||
private static void init(Instrumentation inst) {
|
||||
LOG.info("[AccessWidener] Agent initialising.");
|
||||
|
||||
List<AccessWidenerEntry> entries = new ArrayList<>();
|
||||
File file = new File(new File(".").getAbsoluteFile(), "plugins/");
|
||||
File[] files = file.listFiles();
|
||||
if (files == null) files = new File[0];
|
||||
for (File jarFile : files) {
|
||||
if (!jarFile.isFile()) continue;
|
||||
if (!jarFile.getName().endsWith(".jar")) continue;
|
||||
try {
|
||||
entries.addAll(Utils.findAndParseAccessWideners(jarFile.toPath()));
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to parse access wideners from " + jarFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
LOG.info("[AccessWidener] Loaded " + entries.size() + " access wideners.");
|
||||
|
||||
inst.addTransformer(new WideningTransformer(entries), false);
|
||||
LOG.info("[AccessWidener] Agent ready.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Uses ASM to patch class bytecode according to a list of access widener entries.
|
||||
*
|
||||
* Returns {@code null} if the class is not targeted by any entry (no-op signal
|
||||
* to the caller so it can skip the write).
|
||||
*/
|
||||
public class ClassPatcher {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger("ClassPatcher");
|
||||
|
||||
private final List<AccessWidenerEntry> entries;
|
||||
|
||||
/** Pre-computed set of targeted internal names for fast filtering. */
|
||||
private final Set<String> targets;
|
||||
|
||||
private final Set<String> targetsPublicConstructor;
|
||||
|
||||
public ClassPatcher(List<AccessWidenerEntry> entries) {
|
||||
this.entries = entries;
|
||||
this.targets = entries.stream()
|
||||
.map(AccessWidenerEntry::target)
|
||||
.flatMap(s -> {
|
||||
if (!s.contains("$")) return Stream.of(s);
|
||||
int index = s.lastIndexOf('$');
|
||||
return Stream.of(s, s.substring(0, index));
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
this.targetsPublicConstructor = entries.stream()
|
||||
.filter(entry -> entry.directive().equals("transitive-extendable"))
|
||||
.map(AccessWidenerEntry::target)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches {@code classBytes} if {@code className} is targeted.
|
||||
*
|
||||
* @return patched bytes, or {@code null} if no changes were needed
|
||||
*/
|
||||
public byte[] patch(String className, byte[] classBytes) {
|
||||
if (!targets.contains(className)) return null;
|
||||
|
||||
try {
|
||||
ClassReader cr = new ClassReader(classBytes);
|
||||
ClassWriter cw = new ClassWriter(cr, 0);
|
||||
cr.accept(new ClassTransformer(cw, className, entries, targetsPublicConstructor.contains(className)), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
return cw.toByteArray();
|
||||
} catch (Exception e) {
|
||||
LOG.warning("[AccessWidener] Failed to transform " + className + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ClassTransformer extends ClassVisitor {
|
||||
|
||||
private final String internalName;
|
||||
private final List<AccessWidenerEntry> entries;
|
||||
private final boolean appendPublicConstructor;
|
||||
|
||||
public ClassTransformer(ClassVisitor cv, String internalName, List<AccessWidenerEntry> entries, boolean appendPublicConstructor) {
|
||||
super(Opcodes.ASM9, cv);
|
||||
this.internalName = internalName;
|
||||
this.entries = entries;
|
||||
this.appendPublicConstructor = appendPublicConstructor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
int newAccess = access;
|
||||
for (AccessWidenerEntry e : entries) {
|
||||
if (!e.targets(internalName) || !"class".equals(e.memberType())) continue;
|
||||
newAccess = applyDirective(e.directive(), newAccess, false);
|
||||
}
|
||||
if (appendPublicConstructor) {
|
||||
MethodVisitor methodVisitor = visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(
|
||||
Opcodes.INVOKESPECIAL,
|
||||
"java/lang/Object",
|
||||
"<init>",
|
||||
"()V",
|
||||
false
|
||||
);
|
||||
methodVisitor.visitInsn(Opcodes.RETURN);
|
||||
methodVisitor.visitMaxs(1, 1);
|
||||
methodVisitor.visitEnd();
|
||||
}
|
||||
super.visit(version, newAccess, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||
int newAccess = access;
|
||||
for (AccessWidenerEntry e : entries) {
|
||||
if (!e.target().equals(name) || !"class".equals(e.memberType())) continue;
|
||||
newAccess = applyDirective(e.directive(), newAccess, false);
|
||||
}
|
||||
super.visitInnerClass(name, outerName, innerName, newAccess);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||
int newAccess = access;
|
||||
for (AccessWidenerEntry e : entries) {
|
||||
if (!e.targets(internalName) || !"method".equals(e.memberType())) continue;
|
||||
if (!name.equals(e.name()) || !descriptor.equals(e.descriptor())) continue;
|
||||
newAccess = applyDirective(e.directive(), newAccess, false);
|
||||
}
|
||||
return super.visitMethod(newAccess, name, descriptor, signature, exceptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
||||
int newAccess = access;
|
||||
for (AccessWidenerEntry e : entries) {
|
||||
if (!e.targets(internalName) || !"field".equals(e.memberType())) continue;
|
||||
if (!name.equals(e.name())) continue;
|
||||
newAccess = applyDirective(e.directive(), newAccess, true);
|
||||
}
|
||||
return super.visitField(newAccess, name, descriptor, signature, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a directive to an access bitmask.
|
||||
*
|
||||
* @param directive accessible / mutable / extendable (with optional "transitive-" prefix)
|
||||
* @param access current access flags
|
||||
* @param isField true when processing a field (mutable removes final)
|
||||
*/
|
||||
private static int applyDirective(String directive, int access, boolean isField) {
|
||||
// Strip transitive- prefix — the widening itself is the same
|
||||
String effective = directive.startsWith("transitive-") ? directive.substring("transitive-".length()) : directive;
|
||||
|
||||
return switch (effective) {
|
||||
case "accessible" -> makePublic(access);
|
||||
case "extendable" -> makePublic(removeFinal(access));
|
||||
case "mutable" -> isField ? removeFinal(access) : access;
|
||||
default -> access;
|
||||
};
|
||||
}
|
||||
|
||||
private static int makePublic(int access) {
|
||||
return (access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) | Opcodes.ACC_PUBLIC;
|
||||
}
|
||||
|
||||
private static int removeFinal(int access) {
|
||||
return access & ~Opcodes.ACC_FINAL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Command-line tool that produces a widened copy of a JAR for use as a
|
||||
* compile-time stub in IntelliJ / Gradle.
|
||||
*
|
||||
* Usage:
|
||||
* java -jar jar-widener.jar <input.jar> <output.jar> [file.accesswidener ...]
|
||||
*
|
||||
* The output JAR is identical to the input JAR except that every class
|
||||
* targeted by the access widener entries has its access flags patched:
|
||||
* accessible → public
|
||||
* extendable → public + non-final
|
||||
* mutable → non-final field
|
||||
*
|
||||
* Intended for use as a Gradle task so IntelliJ sees the already-widened
|
||||
* class when you Ctrl+click NMS code, and javac compiles without complaints.
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length < 2) {
|
||||
System.err.println("Usage: jar-widener <input.jar> <output.jar> [*.accesswidener ...]");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
Path inputJar = Path.of(args[0]);
|
||||
Path outputJar = Path.of(args[1]);
|
||||
|
||||
if (!Files.exists(inputJar)) {
|
||||
System.err.println("Input JAR not found: " + inputJar);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// --- Collect all access widener entries ---
|
||||
List<AccessWidenerEntry> entries = new ArrayList<>();
|
||||
|
||||
if (args.length > 2) {
|
||||
for (int i = 2; i < args.length; i++) {
|
||||
Path awFile = Path.of(args[i]);
|
||||
if (!Files.exists(awFile)) {
|
||||
System.err.println("Warning: access widener file not found, skipping: " + awFile);
|
||||
continue;
|
||||
}
|
||||
try (InputStream in = Files.newInputStream(awFile)) {
|
||||
List<AccessWidenerEntry> parsed = AccessWidenerParser.parse(in);
|
||||
System.out.println("Loaded " + parsed.size() + " entries from " + awFile.getFileName());
|
||||
entries.addAll(parsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entries.isEmpty()) {
|
||||
System.out.println("No access widener entries found — copying JAR unchanged.");
|
||||
Files.createDirectories(outputJar.getParent());
|
||||
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Widening " + inputJar.getFileName()
|
||||
+ " with " + entries.size() + " total entr"
|
||||
+ (entries.size() == 1 ? "y" : "ies") + "...");
|
||||
|
||||
// --- Copy input → output, transforming .class files in place ---
|
||||
Files.createDirectories(outputJar.getParent());
|
||||
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
ClassPatcher patcher = new ClassPatcher(entries);
|
||||
|
||||
try (FileSystem fs = FileSystems.newFileSystem(outputJar)) {
|
||||
// Walk every .class entry in the JAR
|
||||
try (var stream = Files.walk(fs.getPath("/"))) {
|
||||
stream.filter(p -> p.toString().endsWith(".class"))
|
||||
.forEach(classPath -> patchClass(fs, classPath, patcher));
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Done. Widened JAR written to " + outputJar);
|
||||
}
|
||||
|
||||
private static void patchClass(FileSystem fs, Path classPath, ClassPatcher patcher) {
|
||||
// Derive internal class name from path e.g. /net/minecraft/Foo.class → net/minecraft/Foo
|
||||
String internalName = classPath.toString()
|
||||
.replaceFirst("^/", "")
|
||||
.replace(".class", "");
|
||||
|
||||
try {
|
||||
byte[] original = Files.readAllBytes(classPath);
|
||||
byte[] patched = patcher.patch(internalName, original);
|
||||
|
||||
if (patched != null) {
|
||||
Files.write(classPath, patched);
|
||||
System.out.println(" Widened: " + internalName);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println(" Warning: failed to patch " + internalName + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class Utils {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger("AccessWidenerAgent");
|
||||
|
||||
private Utils() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static List<AccessWidenerEntry> findAndParseAccessWideners(Path jarPath) throws IOException {
|
||||
List<AccessWidenerEntry> results = new ArrayList<>();
|
||||
|
||||
try (ZipFile zip = new ZipFile(jarPath.toFile())) {
|
||||
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = entries.nextElement();
|
||||
if (entry.isDirectory() || !entry.getName().endsWith(".accesswidener")) continue;
|
||||
|
||||
try (InputStream in = zip.getInputStream(entry)) {
|
||||
results.addAll(AccessWidenerParser.parse(in));
|
||||
} catch (IOException e) {
|
||||
LOG.warning("[AccessWidener] Failed to parse " + entry.getName()
|
||||
+ " in " + jarPath.getFileName() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Transforms class bytecode to apply access widening rules.
|
||||
* <p>
|
||||
* Also monitors for new plugin ClassLoaders appearing (when plugins load after
|
||||
* the agent attaches) and automatically picks up their .accesswidener files.
|
||||
*/
|
||||
public class WideningTransformer implements ClassFileTransformer {
|
||||
|
||||
private final ClassPatcher patcher;
|
||||
|
||||
public WideningTransformer(List<AccessWidenerEntry> entries) {
|
||||
patcher = new ClassPatcher(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
|
||||
return patcher.patch(className, classfileBuffer);
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
plugins {
|
||||
steamwar.java
|
||||
widener
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
@@ -34,6 +35,7 @@ dependencies {
|
||||
compileOnly(libs.classindex)
|
||||
annotationProcessor(libs.classindex)
|
||||
compileOnly(project(":SpigotCore", "default"))
|
||||
compileOnly(project(":KotlinCore", "default"))
|
||||
|
||||
compileOnly(libs.axiom)
|
||||
compileOnly(libs.authlib)
|
||||
@@ -47,3 +49,7 @@ dependencies {
|
||||
implementation(libs.luaj)
|
||||
implementation(files("$projectDir/../libs/YAPION-SNAPSHOT.jar"))
|
||||
}
|
||||
|
||||
widener {
|
||||
fromCatalog(libs.nms)
|
||||
}
|
||||
|
||||
@@ -834,6 +834,10 @@ SKIN_NO_REGION = §7You are not in a region with a changealbe skin
|
||||
SKIN_ALREADY_EXISTS = §cThis skin already exists like this
|
||||
SKIN_MESSAGE = §7Skin created
|
||||
SKIN_MESSAGE_HOVER = §eClick to copy for YoyoNow and send
|
||||
# Blast Resistance
|
||||
BLASTRESISTANCE_HELP = §8/§eblastresistance §8-§7 Calculate min/max and average blast resistance of current clipboard
|
||||
BLASTRESISTANCE_NO_CLIPBOARD = §cYou currently do not have a clipboard to be used.
|
||||
BLASTRESISTANCE_RESULT = §7BlastResistance §8>>§7 Min§8: §e{0}§7 Max§8: §e{1}§7 Avg§8: §e{2}
|
||||
# Panzern
|
||||
PANZERN_HELP = §8/§epanzern §8[§7Block§8] §8[§7Slab§8] §8- §7Armor your WorldEdit selection
|
||||
PANZERN_PREPARE1 = §71. Check, if barrels reach until border of armor.
|
||||
|
||||
@@ -772,6 +772,10 @@ SKIN_NO_REGION = §7Du steht in keiner Region, welche mit einem Skin versehen we
|
||||
SKIN_ALREADY_EXISTS = §cDieser Skin existiert in der Form bereits
|
||||
SKIN_MESSAGE = §7Skin erstellt
|
||||
SKIN_MESSAGE_HOVER = §eKlicken zum kopieren für YoyoNow und an diesen senden
|
||||
# Blast Resistance
|
||||
BLASTRESISTANCE_HELP = §8/§eblastresistance §8-§7 Minimal-, Maximal- und durchschnittliche Sprengfestigkeit des aktuellen Inhalts der Zwischenablage berechnen
|
||||
BLASTRESISTANCE_NO_CLIPBOARD = §cDerzeit steht Ihnen keine Zwischenablage zur Verfügung.
|
||||
BLASTRESISTANCE_RESULT = §7BlastResistance §8>>§7 Min§8: §e{0}§7 Max§8: §e{1}§7 Avg§8: §e{2}
|
||||
# Panzern
|
||||
PANZERN_HELP = §8/§epanzern §8[§7Block§8] §8[§7Slab§8] §8- §7Panzer deine WorldEdit Auswahl
|
||||
PANZERN_PREPARE1 = §71. Gucke nochmal nach, ob Läufe auch bis zur Panzergrenze führen.
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
accessWidener v2 named
|
||||
|
||||
# For NoClipCommand
|
||||
accessible field net/minecraft/server/level/ServerPlayerGameMode gameModeForPlayer Lnet/minecraft/world/level/GameType;
|
||||
|
||||
# For PlaceItemUtils
|
||||
accessible field org/bukkit/craftbukkit/block/CraftBlockState position Lnet/minecraft/core/BlockPos;
|
||||
mutable field org/bukkit/craftbukkit/block/CraftBlockState position Lnet/minecraft/core/BlockPos;
|
||||
accessible field org/bukkit/craftbukkit/block/CraftBlockState world Lorg/bukkit/craftbukkit/CraftWorld;
|
||||
mutable field org/bukkit/craftbukkit/block/CraftBlockState world Lorg/bukkit/craftbukkit/CraftWorld;
|
||||
|
||||
# For TickManager
|
||||
accessible field net/minecraft/server/ServerTickRateManager remainingSprintTicks J
|
||||
+15
-14
@@ -21,9 +21,7 @@ package de.steamwar.bausystem.features.design.endstone;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.entity.REntity;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RFallingBlockEntity;
|
||||
import de.steamwar.entity.*;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@@ -59,15 +57,15 @@ public class DesignEndStone {
|
||||
.filter(material -> material.getBlastResistance() > region.getGameModeConfig().Schematic.MaxDesignBlastResistance)
|
||||
.collect(Collectors.toSet());
|
||||
calculateFromBottom = region.getGameModeConfig().Arena.NoFloor;
|
||||
}
|
||||
|
||||
entityServer.setCallback((player, rEntity, entityAction) -> {
|
||||
if (entityAction != REntityServer.EntityAction.ATTACK) return;
|
||||
Location location = new Location(WORLD, rEntity.getX(), rEntity.getY(), rEntity.getZ());
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
location.getBlock().breakNaturally();
|
||||
calc();
|
||||
}, 1);
|
||||
});
|
||||
private void interact(Player player, RInteraction entity, REntityAction action) {
|
||||
if (action != REntityAction.ATTACK) return;
|
||||
Location location = new Location(WORLD, entity.getX(), entity.getY(), entity.getZ());
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
location.getBlock().breakNaturally();
|
||||
calc();
|
||||
}, 1);
|
||||
}
|
||||
|
||||
public void calc() {
|
||||
@@ -110,12 +108,15 @@ public class DesignEndStone {
|
||||
Material material = WORLD.getBlockAt(cx, cy, cz).getType();
|
||||
|
||||
if (material != Material.WATER && material != Material.LAVA && limited.contains(material)) {
|
||||
Location location = new Location(WORLD, cx + 0.5, cy, cz + 0.5);
|
||||
Location location = new Location(WORLD, cx, cy, cz);
|
||||
if (!locations.add(location)) break;
|
||||
RFallingBlockEntity entity = new RFallingBlockEntity(entityServer, location, Material.RED_STAINED_GLASS);
|
||||
entity.setNoGravity(true);
|
||||
RBlockDisplay entity = new RBlockDisplay(entityServer, location);
|
||||
entity.setBlock(Material.RED_STAINED_GLASS.createBlockData());
|
||||
entity.setGlowing(true);
|
||||
entities.add(entity);
|
||||
RInteraction interaction = new RInteraction(entityServer, location);
|
||||
interaction.setCallback(this::interact);
|
||||
entities.add(interaction);
|
||||
break;
|
||||
} else if (!material.isAir() && material != Material.WATER && material != Material.LAVA) {
|
||||
break;
|
||||
|
||||
+10
-9
@@ -26,8 +26,9 @@ import de.steamwar.bausystem.features.autostart.AutostartListener;
|
||||
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
|
||||
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
|
||||
import de.steamwar.core.SWPlayer;
|
||||
import de.steamwar.entity.RBlockDisplay;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RFallingBlockEntity;
|
||||
import de.steamwar.entity.RInteraction;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.UtilityClass;
|
||||
@@ -58,10 +59,6 @@ public class Detonator {
|
||||
@Override
|
||||
public void onMount(SWPlayer player) {
|
||||
entities.addPlayer(player.getPlayer());
|
||||
entities.setCallback((player1, entity, action) -> {
|
||||
Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
|
||||
DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player1);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,8 +67,6 @@ public class Detonator {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Vector HALF = new Vector(0.5, 0, 0.5);
|
||||
|
||||
public static boolean isDetonator(ItemStack itemStack) {
|
||||
return ItemStorage.isDetonator(itemStack);
|
||||
}
|
||||
@@ -79,8 +74,14 @@ public class Detonator {
|
||||
public static void showDetonator(Player p, List<Location> locs) {
|
||||
DetonatorComponent detonatorComponent = SWPlayer.of(p).getComponentOrDefault(DetonatorComponent.class, DetonatorComponent::new);
|
||||
locs.forEach(location -> {
|
||||
RFallingBlockEntity entity = new RFallingBlockEntity(detonatorComponent.entities, location.clone().add(HALF), Material.RED_STAINED_GLASS);
|
||||
entity.setNoGravity(true);
|
||||
RBlockDisplay blockDisplay = new RBlockDisplay(detonatorComponent.entities, location);
|
||||
blockDisplay.setBlock(Material.RED_STAINED_GLASS.createBlockData());
|
||||
|
||||
RInteraction interaction = new RInteraction(detonatorComponent.entities, location);
|
||||
interaction.setCallback((player, entity, action) -> {
|
||||
Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
|
||||
DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+8
-13
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
* 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
|
||||
@@ -17,20 +17,15 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
package de.steamwar.bausystem.features.experimental;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.linkage.Linked;
|
||||
|
||||
public class TickEndEvent extends Event {
|
||||
@Linked
|
||||
public class ExperimentalCommand extends SWCommand {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
public ExperimentalCommand() {
|
||||
super("experimental", "experiment");
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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.bausystem.features.experimental.redstone_engine;
|
||||
|
||||
import de.steamwar.bausystem.features.experimental.ExperimentalCommand;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.bausystem.utils.ScoreboardElement;
|
||||
import de.steamwar.command.AbstractSWCommand;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import io.papermc.paper.configuration.WorldConfiguration;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.title.TitlePart;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@AbstractSWCommand.PartOf(ExperimentalCommand.class)
|
||||
@Linked
|
||||
public class RedstoneEngine extends SWCommand implements Listener, ScoreboardElement {
|
||||
|
||||
public RedstoneEngine() {
|
||||
super("");
|
||||
}
|
||||
|
||||
private WorldConfiguration.Misc getConfig() {
|
||||
return ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle().paperConfig().misc;
|
||||
}
|
||||
|
||||
@Register("redstone")
|
||||
@Register("redstoneengine")
|
||||
public void setRedstoneEngine(Player player, @StaticValue("alternate_current") String __, WorldConfiguration.Misc.AlternateCurrentUpdateOrder updateOrder) {
|
||||
WorldConfiguration.Misc misc = getConfig();
|
||||
misc.redstoneImplementation = WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT;
|
||||
misc.alternateCurrentUpdateOrder = updateOrder;
|
||||
broadcastTitle(Bukkit.getOnlinePlayers());
|
||||
}
|
||||
|
||||
@Register("redstone")
|
||||
@Register("redstoneengine")
|
||||
public void setRedstoneEngine(Player player, WorldConfiguration.Misc.RedstoneImplementation implementation) {
|
||||
getConfig().redstoneImplementation = implementation;
|
||||
broadcastTitle(Bukkit.getOnlinePlayers());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
WorldConfiguration.Misc misc = getConfig();
|
||||
if (misc.redstoneImplementation != WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) {
|
||||
broadcastTitle(List.of(event.getPlayer()));
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcastTitle(Collection<? extends Player> players) {
|
||||
WorldConfiguration.Misc misc = getConfig();
|
||||
Component title = switch (misc.redstoneImplementation) {
|
||||
case VANILLA -> Component.text("⚠").color(NamedTextColor.RED).append(Component.text(" Redstone: Vanilla ").color(NamedTextColor.WHITE)).append(Component.text("⚠").color(NamedTextColor.RED));
|
||||
case EIGENCRAFT -> Component.text("Redstone: Eigencraft");
|
||||
case ALTERNATE_CURRENT -> Component.text("⚠").color(NamedTextColor.RED).append(Component.text(" Redstone: AC ").color(NamedTextColor.WHITE)).append(Component.text("⚠").color(NamedTextColor.RED));
|
||||
};
|
||||
Component subtitle;
|
||||
if (misc.redstoneImplementation != WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
||||
subtitle = Component.text().build();
|
||||
} else {
|
||||
subtitle = switch (misc.alternateCurrentUpdateOrder) {
|
||||
case VERTICAL_FIRST_INWARD -> Component.text("Y first inwards"); // Y before XZ
|
||||
case VERTICAL_FIRST_OUTWARD -> Component.text("Y first outwards"); // XZ before Y
|
||||
case HORIZONTAL_FIRST_INWARD -> Component.text("XZ first inwards"); // Y before XZ
|
||||
case HORIZONTAL_FIRST_OUTWARD -> Component.text("XZ first outwards"); // XZ before Y
|
||||
};
|
||||
}
|
||||
players.forEach(player -> {
|
||||
player.sendTitlePart(TitlePart.TITLE, title);
|
||||
player.sendTitlePart(TitlePart.SUBTITLE, subtitle);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoreboardGroup getGroup() {
|
||||
return ScoreboardGroup.FOOTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int order() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(Region region, Player p) {
|
||||
WorldConfiguration.Misc misc = getConfig();
|
||||
switch (misc.redstoneImplementation) {
|
||||
case ALTERNATE_CURRENT:
|
||||
switch (misc.alternateCurrentUpdateOrder) {
|
||||
case VERTICAL_FIRST_INWARD:
|
||||
return "§eRedstone§8: §cAC §8(§7Y in§8)";
|
||||
case VERTICAL_FIRST_OUTWARD:
|
||||
return "§eRedstone§8: §cAC §8(§7Y out§8)";
|
||||
case HORIZONTAL_FIRST_INWARD:
|
||||
return "§eRedstone§8: §cAC §8(§7XZ in§8)";
|
||||
case HORIZONTAL_FIRST_OUTWARD:
|
||||
return "§eRedstone§8: §cAC §8(§7XZ out§8)";
|
||||
}
|
||||
return "§eRedstone§8: §cAC";
|
||||
case EIGENCRAFT:
|
||||
return null;
|
||||
case VANILLA:
|
||||
default:
|
||||
return "§eRedstone§8: §cVanilla";
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -24,9 +24,9 @@ import de.steamwar.bausystem.region.Point;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
|
||||
import de.steamwar.bausystem.utils.bossbar.BossBarService;
|
||||
import de.steamwar.entity.RBlockDisplay;
|
||||
import de.steamwar.entity.REntity;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RFallingBlockEntity;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
@@ -290,8 +290,8 @@ public class KillcheckerVisualizer {
|
||||
}
|
||||
rEntities.get(point).die();
|
||||
}
|
||||
RFallingBlockEntity entity = new RFallingBlockEntity(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0.5, 0, 0.5), MATERIALS[Math.min(count - 1, MATERIALS.length) - 1]);
|
||||
entity.setNoGravity(true);
|
||||
RBlockDisplay entity = new RBlockDisplay(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0.5, 0, 0.5));
|
||||
entity.setBlock(MATERIALS[Math.min(count - 1, MATERIALS.length) - 1].createBlockData());
|
||||
rEntities.put(point, entity);
|
||||
if (outlinePoints.contains(point)) outlinePointsCache.add(point);
|
||||
killCount.put(point, count);
|
||||
|
||||
+4
-5
@@ -185,17 +185,16 @@ public class TestblockCommand extends SWCommand {
|
||||
return new TypeMapper<SchematicNode>() {
|
||||
@Override
|
||||
public List<String> tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
|
||||
List<String> stringList = new ArrayList<>(SchematicNode.getNodeTabcomplete(SteamwarUser.get(((Player) commandSender).getUniqueId()), s));
|
||||
List<String> stringList = new ArrayList<>();
|
||||
stringList.addAll(SchematicNode.getNodeTabcomplete(SteamwarUser.byId(0), s));
|
||||
stringList.addAll(SchematicNode.getNodeTabcomplete(SteamwarUser.get(((Player) commandSender).getUniqueId()), s));
|
||||
return stringList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchematicNode map(CommandSender commandSender, PreviousArguments previousArguments, String s) {
|
||||
SchematicNode node = SchematicNode.getNodeFromPath(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
|
||||
if (node == null) {
|
||||
node = SchematicNode.getNodeFromPath(SteamwarUser.byId(0), s);
|
||||
}
|
||||
SchematicNode node = SchematicNode.getNodeFromPath(SteamwarUser.byId(0), s);
|
||||
if (node == null) node = SchematicNode.getNodeFromPath(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
+133
-237
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.bausystem.features.simulator;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import com.destroystokyo.paper.event.server.ServerTickEndEvent;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.Permission;
|
||||
import de.steamwar.bausystem.SWUtils;
|
||||
@@ -38,77 +38,88 @@ import de.steamwar.bausystem.features.simulator.gui.SimulatorGui;
|
||||
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
|
||||
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
|
||||
import de.steamwar.bausystem.utils.ItemUtils;
|
||||
import de.steamwar.bausystem.utils.RayTraceUtils;
|
||||
import de.steamwar.core.SWPlayer;
|
||||
import de.steamwar.cursor.Cursor;
|
||||
import de.steamwar.entity.REntity;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RFallingBlockEntity;
|
||||
import de.steamwar.inventory.SWAnvilInv;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.player.*;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Linked
|
||||
public class SimulatorCursor implements Listener {
|
||||
|
||||
private static final World WORLD = Bukkit.getWorlds().get(0);
|
||||
|
||||
private static Map<Player, CursorType> cursorType = Collections.synchronizedMap(new HashMap<>());
|
||||
private static Map<Player, REntityServer> cursors = Collections.synchronizedMap(new HashMap<>());
|
||||
private static final Set<Player> calculating = new HashSet<>();
|
||||
private static final Map<Player, CursorType> cursorType = Collections.synchronizedMap(new HashMap<>());
|
||||
private static final Map<Player, REntityServer> emptyTargetServers = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
public static boolean isSimulatorItem(ItemStack itemStack) {
|
||||
return ItemUtils.isItem(itemStack, "simulator");
|
||||
}
|
||||
|
||||
public SimulatorCursor() {
|
||||
BiFunction<Player, Object, Object> function = (player, object) -> {
|
||||
calcCursor(player);
|
||||
return object;
|
||||
};
|
||||
TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Pos.class, function);
|
||||
TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Rot.class, function);
|
||||
TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.PosRot.class, function);
|
||||
private static boolean hasSimulatorItem(Player player) {
|
||||
return isSimulatorItem(player.getInventory().getItemInMainHand()) || isSimulatorItem(player.getInventory().getItemInOffHand());
|
||||
}
|
||||
|
||||
private static Set<Player> scheduledUpdates = new HashSet<>();
|
||||
|
||||
private static void scheduleCursorUpdate(Player player) {
|
||||
scheduledUpdates.add(player);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerTickEnd(ServerTickEndEvent event) {
|
||||
scheduledUpdates.forEach(SimulatorCursor::calcCursor);
|
||||
scheduledUpdates.clear();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
calcCursor(event.getPlayer());
|
||||
}, 0);
|
||||
scheduleCursorUpdate(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerDropItem(PlayerDropItemEvent event) {
|
||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||
calcCursor(event.getPlayer());
|
||||
scheduleCursorUpdate(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerItemHeld(PlayerItemHeldEvent event) {
|
||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||
calcCursor(event.getPlayer());
|
||||
}, 1);
|
||||
scheduleCursorUpdate(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (!(event.getWhoClicked() instanceof Player player)) return;
|
||||
if (!Permission.BUILD.hasPermission(player)) return;
|
||||
scheduleCursorUpdate(player);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryDrag(InventoryDragEvent event) {
|
||||
if (!(event.getWhoClicked() instanceof Player player)) return;
|
||||
if (!Permission.BUILD.hasPermission(player)) return;
|
||||
scheduleCursorUpdate(player);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -119,10 +130,8 @@ public class SimulatorCursor implements Listener {
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
cursorType.remove(event.getPlayer());
|
||||
cursors.remove(event.getPlayer());
|
||||
synchronized (calculating) {
|
||||
calculating.remove(event.getPlayer());
|
||||
}
|
||||
removeCursor(event.getPlayer());
|
||||
scheduledUpdates.remove(event.getPlayer());
|
||||
}
|
||||
|
||||
private static final Map<Player, Long> LAST_SNEAKS = new HashMap<>();
|
||||
@@ -138,7 +147,7 @@ public class SimulatorCursor implements Listener {
|
||||
public void onPlayerToggleSneak(PlayerToggleSneakEvent event) {
|
||||
if (!event.isSneaking()) return;
|
||||
Player player = event.getPlayer();
|
||||
if (!isSimulatorItem(player.getInventory().getItemInMainHand()) && !isSimulatorItem(player.getInventory().getItemInOffHand())) {
|
||||
if (!hasSimulatorItem(player)) {
|
||||
return;
|
||||
}
|
||||
if (LAST_SNEAKS.containsKey(player)) {
|
||||
@@ -164,17 +173,10 @@ public class SimulatorCursor implements Listener {
|
||||
}
|
||||
|
||||
public static void calcCursor(Player player) {
|
||||
synchronized (calculating) {
|
||||
if (calculating.contains(player)) return;
|
||||
calculating.add(player);
|
||||
}
|
||||
if (!Permission.BUILD.hasPermission(player) || (!isSimulatorItem(player.getInventory().getItemInMainHand()) && !isSimulatorItem(player.getInventory().getItemInOffHand()))) {
|
||||
if (removeCursor(player) || SimulatorWatcher.show(null, player)) {
|
||||
if (!Permission.BUILD.hasPermission(player) || !hasSimulatorItem(player)) {
|
||||
if (removeCursor(player) | SimulatorWatcher.show(null, player)) {
|
||||
SWUtils.sendToActionbar(player, "");
|
||||
}
|
||||
synchronized (calculating) {
|
||||
calculating.remove(player);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,203 +185,98 @@ public class SimulatorCursor implements Listener {
|
||||
removeCursor(player);
|
||||
SimulatorWatcher.show(null, player);
|
||||
SWUtils.sendToActionbar(player, "§cGenerating Stab");
|
||||
synchronized (calculating) {
|
||||
calculating.remove(player);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SimulatorWatcher.show(simulator, player);
|
||||
List<REntity> entities = SimulatorWatcher.getEntitiesOfSimulator(simulator);
|
||||
RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), entities);
|
||||
if (rayTraceResult == null) {
|
||||
removeCursor(player);
|
||||
if (simulator == null) {
|
||||
SWUtils.sendToActionbar(player, "§eSelect Simulator");
|
||||
} else {
|
||||
SWUtils.sendToActionbar(player, "§eOpen Simulator");
|
||||
}
|
||||
synchronized (calculating) {
|
||||
calculating.remove(player);
|
||||
}
|
||||
return;
|
||||
Cursor cursor = getOrCreateCursor(player, simulator, cursorType.getOrDefault(player, CursorType.TNT));
|
||||
cursor.renderDeduplicated();
|
||||
}
|
||||
|
||||
private static Cursor getOrCreateCursor(Player player, Simulator simulator, CursorType type) {
|
||||
REntityServer targetServer = simulator == null ? emptyTargetServers.computeIfAbsent(player, __ -> new REntityServer()) : SimulatorWatcher.getEntityServerOfSimulator(simulator);
|
||||
SWPlayer swPlayer = SWPlayer.of(player);
|
||||
Optional<Cursor> activeCursor = swPlayer.getComponent(Cursor.class);
|
||||
|
||||
Cursor cursor = activeCursor.orElse(null);
|
||||
if (cursor == null || cursor.getTargetServer() != targetServer) {
|
||||
swPlayer.removeComponent(Cursor.class);
|
||||
cursor = new Cursor(
|
||||
targetServer,
|
||||
player,
|
||||
Material.GLASS,
|
||||
type.material,
|
||||
type.cursorModes,
|
||||
(location, hitEntity, action) -> handlePlayerClick(player, location, hitEntity, action),
|
||||
(location, hitEntity) -> sendCursorActionbar(player, SimulatorStorage.getSimulator(player), location != null, hitEntity.isPresent())
|
||||
);
|
||||
} else {
|
||||
cursor.setCursorMaterial(type.material);
|
||||
cursor.setAllowedCursorModes(type.cursorModes);
|
||||
}
|
||||
|
||||
showCursor(player, rayTraceResult, simulator != null);
|
||||
synchronized (calculating) {
|
||||
calculating.remove(player);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
private static synchronized boolean removeCursor(Player player) {
|
||||
REntityServer entityServer = cursors.get(player);
|
||||
boolean hadCursor = entityServer != null && !entityServer.getEntities().isEmpty();
|
||||
if (entityServer != null) {
|
||||
entityServer.getEntities().forEach(REntity::die);
|
||||
Optional<Cursor> cursor = SWPlayer.of(player).getComponent(Cursor.class);
|
||||
cursor.ifPresent(__ -> SWPlayer.of(player).removeComponent(Cursor.class));
|
||||
REntityServer emptyTargetServer = emptyTargetServers.remove(player);
|
||||
if (emptyTargetServer != null) {
|
||||
emptyTargetServer.close();
|
||||
}
|
||||
return hadCursor;
|
||||
return cursor.isPresent();
|
||||
}
|
||||
|
||||
private static synchronized void showCursor(Player player, RayTraceUtils.RRayTraceResult rayTraceResult, boolean hasSimulatorSelected) {
|
||||
REntityServer entityServer = cursors.computeIfAbsent(player, __ -> {
|
||||
REntityServer rEntityServer = new REntityServer();
|
||||
rEntityServer.addPlayer(player);
|
||||
return rEntityServer;
|
||||
});
|
||||
|
||||
CursorType type = cursorType.getOrDefault(player, CursorType.TNT);
|
||||
REntity hitEntity = rayTraceResult.getHitEntity();
|
||||
Location location = hitEntity != null ? new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ()).toLocation(WORLD) :
|
||||
type.position.apply(player, rayTraceResult).toLocation(WORLD);
|
||||
|
||||
Material material = hitEntity != null ? Material.GLASS : type.getMaterial();
|
||||
List<RFallingBlockEntity> entities = entityServer.getEntitiesByType(RFallingBlockEntity.class);
|
||||
entities.removeIf(rFallingBlockEntity -> {
|
||||
if (rFallingBlockEntity.getMaterial() != material) {
|
||||
rFallingBlockEntity.die();
|
||||
return true;
|
||||
}
|
||||
rFallingBlockEntity.move(location);
|
||||
return false;
|
||||
});
|
||||
if (entities.isEmpty()) {
|
||||
RFallingBlockEntity rFallingBlockEntity = new RFallingBlockEntity(entityServer, location, material);
|
||||
rFallingBlockEntity.setNoGravity(true);
|
||||
if (material == Material.GLASS) {
|
||||
rFallingBlockEntity.setGlowing(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSimulatorSelected) {
|
||||
if (hitEntity != null) {
|
||||
SWUtils.sendToActionbar(player, "§eEdit Position");
|
||||
} else {
|
||||
SWUtils.sendToActionbar(player, "§eAdd new " + type.name);
|
||||
}
|
||||
} else {
|
||||
private static void sendCursorActionbar(Player player, Simulator simulator, boolean hasCursorLocation, boolean hasHitEntity) {
|
||||
if (!hasCursorLocation) {
|
||||
SWUtils.sendToActionbar(player, simulator == null ? "§eSelect Simulator" : "§eOpen Simulator");
|
||||
} else if (simulator == null) {
|
||||
SWUtils.sendToActionbar(player, "§eCreate new Simulator");
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector getPosFree(Player player, RayTraceUtils.RRayTraceResult result) {
|
||||
Vector pos = result.getHitPosition();
|
||||
|
||||
BlockFace face = result.getHitBlockFace();
|
||||
if (face != null) {
|
||||
switch (face) {
|
||||
case DOWN:
|
||||
pos.setY(pos.getY() - 0.98);
|
||||
break;
|
||||
case EAST:
|
||||
pos.setX(pos.getX() + 0.49);
|
||||
break;
|
||||
case WEST:
|
||||
pos.setX(pos.getX() - 0.49);
|
||||
break;
|
||||
case NORTH:
|
||||
pos.setZ(pos.getZ() - 0.49);
|
||||
break;
|
||||
case SOUTH:
|
||||
pos.setZ(pos.getZ() + 0.49);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (face.getModY() == 0 && player.isSneaking()) {
|
||||
pos.setY(pos.getY() - 0.49);
|
||||
}
|
||||
}
|
||||
|
||||
if (!player.isSneaking()) {
|
||||
pos.setX(pos.getBlockX() + 0.5);
|
||||
if (face == null || face.getModY() == 0) {
|
||||
pos.setY(pos.getBlockY() + 0.0);
|
||||
}
|
||||
pos.setZ(pos.getBlockZ() + 0.5);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
private static Vector getPosBlockAligned(Player player, RayTraceUtils.RRayTraceResult result) {
|
||||
Vector pos = result.getHitPosition();
|
||||
|
||||
BlockFace face = result.getHitBlockFace();
|
||||
if (face != null) {
|
||||
switch (face) {
|
||||
case DOWN:
|
||||
pos.setY(pos.getY() - 0.98);
|
||||
break;
|
||||
case EAST:
|
||||
pos.setX(pos.getX() + 0.49);
|
||||
break;
|
||||
case WEST:
|
||||
pos.setX(pos.getX() - 0.49);
|
||||
break;
|
||||
case NORTH:
|
||||
pos.setZ(pos.getZ() - 0.49);
|
||||
break;
|
||||
case SOUTH:
|
||||
pos.setZ(pos.getZ() + 0.49);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pos.setX(pos.getBlockX() + 0.5);
|
||||
if (pos.getY() - pos.getBlockY() != 0 && face == BlockFace.UP) {
|
||||
pos.setY(pos.getBlockY() + 1.0);
|
||||
} else if (hasHitEntity) {
|
||||
SWUtils.sendToActionbar(player, "§eEdit Position");
|
||||
} else {
|
||||
pos.setY(pos.getBlockY());
|
||||
SWUtils.sendToActionbar(player, "§eAdd new " + cursorType.getOrDefault(player, CursorType.TNT).name);
|
||||
}
|
||||
pos.setZ(pos.getBlockZ() + 0.5);
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum CursorType {
|
||||
TNT(Material.TNT, Material.GUNPOWDER, SimulatorCursor::getPosFree, "TNT", vector -> new TNTElement(vector).add(new TNTPhase())),
|
||||
REDSTONE_BLOCK(Material.REDSTONE_BLOCK, Material.REDSTONE, SimulatorCursor::getPosBlockAligned, "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())),
|
||||
OBSERVER(Material.OBSERVER, Material.QUARTZ, SimulatorCursor::getPosBlockAligned, "Observer", vector -> new ObserverElement(vector).add(new ObserverPhase())),
|
||||
TNT(Material.TNT, Material.GUNPOWDER, List.of(Cursor.CursorMode.FREE, Cursor.CursorMode.SURFACE_ALIGNED), "TNT", vector -> new TNTElement(vector).add(new TNTPhase())),
|
||||
REDSTONE_BLOCK(Material.REDSTONE_BLOCK, Material.REDSTONE, List.of(Cursor.CursorMode.BLOCK_ALIGNED), "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())),
|
||||
OBSERVER(Material.OBSERVER, Material.QUARTZ, List.of(Cursor.CursorMode.BLOCK_ALIGNED), "Observer", vector -> new ObserverElement(vector).add(new ObserverPhase())),
|
||||
;
|
||||
|
||||
public final Material material;
|
||||
public final Material nonSelectedMaterial;
|
||||
public final BiFunction<Player, RayTraceUtils.RRayTraceResult, Vector> position;
|
||||
public final List<Cursor.CursorMode> cursorModes;
|
||||
public final String name;
|
||||
public final Function<Vector, SimulatorElement<?>> elementFunction;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||
if (!ItemUtils.isItem(event.getItem(), "simulator")) {
|
||||
private static void handlePlayerClick(Player player, Location cursorLocation, Optional<REntity> hitEntity, Action action) {
|
||||
if (!Permission.BUILD.hasPermission(player)) return;
|
||||
if (!hasSimulatorItem(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
Player player = event.getPlayer();
|
||||
Simulator simulator = SimulatorStorage.getSimulator(player);
|
||||
|
||||
if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_AIR) {
|
||||
if (action == Action.LEFT_CLICK_BLOCK || action == Action.LEFT_CLICK_AIR) {
|
||||
if (simulator == null) {
|
||||
return;
|
||||
}
|
||||
SimulatorExecutor.run(event.getPlayer(), simulator, null);
|
||||
SimulatorExecutor.run(player, simulator, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.RIGHT_CLICK_AIR) {
|
||||
if (action != Action.RIGHT_CLICK_BLOCK && action != Action.RIGHT_CLICK_AIR) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), SimulatorWatcher.getEntitiesOfSimulator(simulator));
|
||||
if (simulator == null) {
|
||||
if (rayTraceResult == null) {
|
||||
if (cursorLocation == null) {
|
||||
SimulatorStorage.openSimulatorSelector(player);
|
||||
} else {
|
||||
SWAnvilInv anvilInv = new SWAnvilInv(player, "Name");
|
||||
@@ -395,7 +292,7 @@ public class SimulatorCursor implements Listener {
|
||||
}
|
||||
sim = new Simulator(s);
|
||||
SimulatorStorage.addSimulator(s, sim);
|
||||
createElement(player, rayTraceResult, sim);
|
||||
createElement(player, cursorLocation, sim);
|
||||
SimulatorStorage.setSimulator(player, sim);
|
||||
});
|
||||
anvilInv.open();
|
||||
@@ -403,57 +300,56 @@ public class SimulatorCursor implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rayTraceResult == null) {
|
||||
if (cursorLocation == null) {
|
||||
new SimulatorGui(player, simulator).open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (rayTraceResult.getHitEntity() != null) {
|
||||
REntity hitEntity = rayTraceResult.getHitEntity();
|
||||
Vector vector = new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ());
|
||||
List<SimulatorElement<?>> elements = simulator.getGroups().stream().map(SimulatorGroup::getElements).flatMap(List::stream).filter(element -> {
|
||||
return element.getWorldPos().distanceSquared(vector) < (1 / 16.0) * (1 / 16.0);
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
switch (elements.size()) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
// Open single element present in Simulator
|
||||
SimulatorElement<?> element = elements.get(0);
|
||||
SimulatorGroup group1 = element.getGroup(simulator);
|
||||
SimulatorBaseGui back = new SimulatorGui(player, simulator);
|
||||
if (group1.getElements().size() > 1) {
|
||||
back = new SimulatorGroupGui(player, simulator, group1, back);
|
||||
}
|
||||
element.open(player, simulator, group1, back);
|
||||
break;
|
||||
default:
|
||||
List<SimulatorGroup> parents = elements.stream().map(e -> e.getGroup(simulator)).distinct().collect(Collectors.toList());
|
||||
if (parents.size() == 1) {
|
||||
// Open multi element present in Simulator in existing group
|
||||
SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
|
||||
new SimulatorGroupGui(player, simulator, parents.get(0), simulatorGui).open();
|
||||
} else {
|
||||
// Open multi element present in Simulator in implicit group
|
||||
SimulatorGroup group2 = new SimulatorGroup();
|
||||
group2.setMaterial(null);
|
||||
group2.getElements().addAll(elements);
|
||||
SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
|
||||
new SimulatorGroupGui(player, simulator, group2, simulatorGui).open();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (hitEntity.isPresent()) {
|
||||
openElement(player, simulator, hitEntity.get());
|
||||
return;
|
||||
}
|
||||
|
||||
// Add new Element to current simulator
|
||||
createElement(player, rayTraceResult, simulator);
|
||||
createElement(player, cursorLocation, simulator);
|
||||
}
|
||||
|
||||
private void createElement(Player player, RayTraceUtils.RRayTraceResult rayTraceResult, Simulator simulator) {
|
||||
private static void openElement(Player player, Simulator simulator, REntity hitEntity) {
|
||||
Vector vector = new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ());
|
||||
List<SimulatorElement<?>> elements = simulator.getGroups().stream().map(SimulatorGroup::getElements).flatMap(List::stream).filter(element -> {
|
||||
return element.getWorldPos().distanceSquared(vector) < (1 / 16.0) * (1 / 16.0);
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
switch (elements.size()) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
SimulatorElement<?> element = elements.get(0);
|
||||
SimulatorGroup group1 = element.getGroup(simulator);
|
||||
SimulatorBaseGui back = new SimulatorGui(player, simulator);
|
||||
if (group1.getElements().size() > 1) {
|
||||
back = new SimulatorGroupGui(player, simulator, group1, back);
|
||||
}
|
||||
element.open(player, simulator, group1, back);
|
||||
break;
|
||||
default:
|
||||
List<SimulatorGroup> parents = elements.stream().map(e -> e.getGroup(simulator)).distinct().collect(Collectors.toList());
|
||||
if (parents.size() == 1) {
|
||||
SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
|
||||
new SimulatorGroupGui(player, simulator, parents.get(0), simulatorGui).open();
|
||||
} else {
|
||||
SimulatorGroup group2 = new SimulatorGroup();
|
||||
group2.setMaterial(null);
|
||||
group2.getElements().addAll(elements);
|
||||
SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
|
||||
new SimulatorGroupGui(player, simulator, group2, simulatorGui).open();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void createElement(Player player, Location cursorLocation, Simulator simulator) {
|
||||
CursorType type = cursorType.getOrDefault(player, CursorType.TNT);
|
||||
Vector vector = type.position.apply(player, rayTraceResult);
|
||||
Vector vector = cursorLocation.toVector();
|
||||
if (type == CursorType.REDSTONE_BLOCK) {
|
||||
vector.subtract(new Vector(0.5, 0, 0.5));
|
||||
}
|
||||
|
||||
+7
@@ -124,4 +124,11 @@ public class SimulatorWatcher {
|
||||
}
|
||||
return entityServer.getEntities();
|
||||
}
|
||||
|
||||
synchronized REntityServer getEntityServerOfSimulator(Simulator simulator) {
|
||||
if (simulator == null) {
|
||||
return null;
|
||||
}
|
||||
return entityServers.computeIfAbsent(simulator, __ -> createSim(new REntityServer(), simulator));
|
||||
}
|
||||
}
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.bausystem.features.slaves.blastresistance;
|
||||
|
||||
import com.google.common.util.concurrent.AtomicDouble;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Linked
|
||||
public class BlastResistanceCommand extends SWCommand {
|
||||
|
||||
public BlastResistanceCommand() {
|
||||
super("blastresistance");
|
||||
}
|
||||
|
||||
@Register(description = "BLASTRESISTANCE_HELP")
|
||||
public void command(@Validator Player player) {
|
||||
LocalSession localSession = WorldEdit.getInstance().getSessionManager().get(BukkitAdapter.adapt(player));
|
||||
Clipboard clipboard;
|
||||
try {
|
||||
clipboard = localSession.getClipboard().getClipboards().getFirst();
|
||||
} catch (WorldEditException e) {
|
||||
BauSystem.MESSAGE.send("BLASTRESISTANCE_NO_CLIPBOARD", player);
|
||||
return;
|
||||
}
|
||||
|
||||
AtomicDouble min = new AtomicDouble(0);
|
||||
AtomicDouble max = new AtomicDouble(0);
|
||||
AtomicDouble sum = new AtomicDouble(0);
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
clipboard.forEach(blockVector3 -> {
|
||||
BlockState blockState = clipboard.getBlock(blockVector3);
|
||||
Material material = BukkitAdapter.adapt(blockState).getMaterial();
|
||||
if (material == Material.WATER || material == Material.LAVA) return;
|
||||
double blastResistance = BukkitAdapter.adapt(blockState).getMaterial().getBlastResistance();
|
||||
min.set(Math.min(min.get(), blastResistance));
|
||||
max.set(Math.max(max.get(), blastResistance));
|
||||
sum.addAndGet(blastResistance);
|
||||
count.getAndIncrement();
|
||||
});
|
||||
|
||||
BauSystem.MESSAGE.send("BLASTRESISTANCE_RESULT", player, min.get(), max.get(), sum.get() / count.get());
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -21,7 +21,6 @@ package de.steamwar.bausystem.features.slaves.laufbau;
|
||||
|
||||
import com.sk89q.worldedit.blocks.SkullBlock;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import de.steamwar.bausystem.utils.NMSWrapper;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
@@ -99,7 +98,7 @@ public class BlockBoundingBox {
|
||||
// addPixel(Material.COBWEB.createBlockData(), 0, 0, 0, 0, 0, 0, createItem("LAUFBAU_BLOCK_COBWEB", Material.COBWEB));
|
||||
addPixel(Material.END_STONE.createBlockData(), 0, 0, 0, 16, 16, 16, null);
|
||||
|
||||
addPixel(NMSWrapper.impl.pathMaterial().createBlockData(), 0, 0, 0, 16, 15, 16, createItem("LAUFBAU_BLOCK_GRASS_PATH", NMSWrapper.impl.pathMaterial()));
|
||||
addPixel(Material.DIRT_PATH.createBlockData(), 0, 0, 0, 16, 15, 16, createItem("LAUFBAU_BLOCK_GRASS_PATH", Material.DIRT_PATH));
|
||||
addPixel(Material.MUD.createBlockData(), 0, 0, 0, 16, 14, 16, createItem("LAUFBAU_BLOCK_SOUL_SAND", Material.SOUL_SAND));
|
||||
|
||||
Cocoa cocoaNorth = (Cocoa) Material.COCOA.createBlockData();
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.core.CraftbukkitWrapper;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import de.steamwar.linkage.LinkedInstance;
|
||||
import de.steamwar.techhider.TechHider;
|
||||
import de.steamwar.techhider.legacy.TechHider;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
|
||||
package de.steamwar.bausystem.features.tpslimit;
|
||||
|
||||
import com.destroystokyo.paper.event.server.ServerTickEndEvent;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.Permission;
|
||||
import de.steamwar.bausystem.SWUtils;
|
||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.bausystem.utils.ScoreboardElement;
|
||||
import de.steamwar.bausystem.utils.TickEndEvent;
|
||||
import de.steamwar.bausystem.utils.TickManager;
|
||||
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
|
||||
import de.steamwar.bausystem.utils.bossbar.BossBarService;
|
||||
@@ -72,7 +72,7 @@ public class TPSSystem implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onTickEnd(TickEndEvent event) {
|
||||
public void onTickEnd(ServerTickEndEvent event) {
|
||||
bossbar();
|
||||
}
|
||||
|
||||
|
||||
@@ -143,14 +143,6 @@ public class Trace {
|
||||
} else {
|
||||
entityServer = new REntityServer();
|
||||
entityServer.addPlayer(player);
|
||||
entityServer.setCallback((p, rEntity, entityAction) -> {
|
||||
if (entityAction != REntityServer.EntityAction.INTERACT) {
|
||||
return;
|
||||
}
|
||||
if (rEntity instanceof TraceEntity) {
|
||||
((TraceEntity) rEntity).printIntoChat(p);
|
||||
}
|
||||
});
|
||||
entityServerMap.put(player, entityServer);
|
||||
}
|
||||
render(getRecords(), entityServer, playerTraceShowData);
|
||||
@@ -167,14 +159,6 @@ public class Trace {
|
||||
REntityServer entityServer = entityServerMap.computeIfAbsent(player, k -> {
|
||||
REntityServer newEntityServer = new REntityServer();
|
||||
newEntityServer.addPlayer(k);
|
||||
newEntityServer.setCallback((p, rEntity, entityAction) -> {
|
||||
if (entityAction != REntityServer.EntityAction.INTERACT) {
|
||||
return;
|
||||
}
|
||||
if (rEntity instanceof TraceEntity) {
|
||||
((TraceEntity) rEntity).printIntoChat(p);
|
||||
}
|
||||
});
|
||||
return newEntityServer;
|
||||
});
|
||||
|
||||
|
||||
+5
-1
@@ -153,7 +153,11 @@ public class TraceCommand extends SWCommand {
|
||||
|
||||
@Register(value = "isolate", description = "TRACE_COMMAND_HELP_ISOLATE")
|
||||
public void isolate(@Validator Player player, Trace trace, @ErrorMessage("TRACE_RECORD_ID_INVALID") TNTPoint... records) {
|
||||
TraceManager.instance.isolate(player, records);
|
||||
if (records.length == 0) {
|
||||
TraceManager.instance.isolate(player, trace, trace.getRecords().toArray(TNTPoint[]::new));
|
||||
} else {
|
||||
TraceManager.instance.isolate(player, trace, records);
|
||||
}
|
||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_ISOLATE", player);
|
||||
}
|
||||
|
||||
|
||||
+15
-6
@@ -347,9 +347,10 @@ public class TraceManager implements Listener {
|
||||
* Toggles the isolated render for the given records and player
|
||||
*
|
||||
* @param player the player the trace is shown to
|
||||
* @param records the record for which isolation is toggled
|
||||
* @param ptrace the trace for whitch isolation is toggled
|
||||
* @param records the records of the trace for which isolation is toggled
|
||||
*/
|
||||
public void isolate(Player player, TNTPoint... records) {
|
||||
public void isolate(Player player, Trace ptrace, TNTPoint... records) {
|
||||
unfollow(player);
|
||||
|
||||
Region region = Region.getRegion(player.getLocation());
|
||||
@@ -374,12 +375,20 @@ public class TraceManager implements Listener {
|
||||
isolateFlag.toggleId(record.getTntId());
|
||||
}
|
||||
|
||||
if (isolateFlag.isEmpty() && playerTraceShowData.hasViewFlagOnly(IsolateFlag.class) && records.length != 0) {
|
||||
playerTraceShowData.removeViewFlag(IsolateFlag.class);
|
||||
}
|
||||
|
||||
PlayerTraceShowData finalPlayerTraceShowData = playerTraceShowData;
|
||||
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
|
||||
trace.render(player, finalPlayerTraceShowData);
|
||||
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
|
||||
trace.render(follower, finalPlayerTraceShowData);
|
||||
});
|
||||
if (trace.getUuid() == ptrace.getUuid() || finalPlayerTraceShowData.hasNoViewFlags()) {
|
||||
trace.render(player, finalPlayerTraceShowData);
|
||||
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
|
||||
trace.render(follower, finalPlayerTraceShowData);
|
||||
});
|
||||
} else {
|
||||
trace.hide(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -135,6 +135,13 @@ public class TraceRecorder implements Listener {
|
||||
Iterator<TNTPrimed> iter = trackedTNT.getOrDefault(region, Collections.emptyList()).iterator();
|
||||
while (iter.hasNext()) {
|
||||
TNTPrimed tnt = iter.next();
|
||||
if (tnt.isDead()) {
|
||||
iter.remove();
|
||||
tntSpawnRegion.remove(tnt);
|
||||
historyMap.remove(tnt);
|
||||
tntSpawnRegion.remove(tnt);
|
||||
continue;
|
||||
}
|
||||
if (tnt.getFuseTicks() == 80) continue;
|
||||
TNTPoint record = record(tnt, wrappedTrace, Collections.emptyList());
|
||||
if (record == null) {
|
||||
|
||||
+4
@@ -95,4 +95,8 @@ public class PlayerTraceShowData {
|
||||
public void addViewFlag(ViewFlag viewFlag) {
|
||||
viewFlags.put(viewFlag.getClass(), viewFlag);
|
||||
}
|
||||
|
||||
public <T extends ViewFlag> void removeViewFlag(Class<T> clazz) {
|
||||
viewFlags.remove(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
+36
-4
@@ -24,13 +24,18 @@ import de.steamwar.bausystem.configplayer.Config;
|
||||
import de.steamwar.bausystem.features.tracer.TNTPoint;
|
||||
import de.steamwar.bausystem.features.tracer.Trace;
|
||||
import de.steamwar.bausystem.features.tracer.TraceManager;
|
||||
import de.steamwar.entity.RBlockDisplay;
|
||||
import de.steamwar.entity.REntityAction;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RFallingBlockEntity;
|
||||
import de.steamwar.entity.RInteraction;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Transformation;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
import yapion.hierarchy.types.YAPIONValue;
|
||||
|
||||
import java.util.List;
|
||||
@@ -41,7 +46,16 @@ import static de.steamwar.bausystem.features.util.TNTClickListener.TNT_CLICK_DET
|
||||
/**
|
||||
* Wrapper for the rendering of a record bundle
|
||||
*/
|
||||
public class TraceEntity extends RFallingBlockEntity {
|
||||
public class TraceEntity extends RBlockDisplay {
|
||||
|
||||
public static final float TNT_VISUAL_SCALE = 0.98F;
|
||||
public static final float TNT_VISUAL_OFFSET = -TNT_VISUAL_SCALE / 2.0F;
|
||||
public static final Transformation TNT_VISUAL_TRANSFORM = new Transformation(
|
||||
new Vector3f(TNT_VISUAL_OFFSET, 0.0F, TNT_VISUAL_OFFSET),
|
||||
new Quaternionf(0, 0, 0, 1),
|
||||
new Vector3f(TNT_VISUAL_SCALE, TNT_VISUAL_SCALE, TNT_VISUAL_SCALE),
|
||||
new Quaternionf(0, 0, 0, 1)
|
||||
);
|
||||
|
||||
/**
|
||||
* The records represented by this REntity
|
||||
@@ -55,13 +69,31 @@ public class TraceEntity extends RFallingBlockEntity {
|
||||
private final String uniqueTntIdsString;
|
||||
|
||||
private final Trace trace;
|
||||
private final RInteraction hitbox;
|
||||
|
||||
public TraceEntity(REntityServer server, Location location, boolean isExplosion, List<TNTPoint> records, Trace trace) {
|
||||
super(server, location, isExplosion ? Material.RED_STAINED_GLASS : Material.TNT);
|
||||
super(server, location);
|
||||
Material material = isExplosion ? Material.RED_STAINED_GLASS : Material.TNT;
|
||||
this.records = records;
|
||||
this.trace = trace;
|
||||
uniqueTntIdsString = records.stream().map(TNTPoint::getTntId).distinct().map(Object::toString).collect(Collectors.joining(" "));
|
||||
setNoGravity(true);
|
||||
hitbox = new RInteraction(server, location);
|
||||
hitbox.setInteractionHeight(TNT_VISUAL_SCALE);
|
||||
hitbox.setInteractionWidth(TNT_VISUAL_SCALE);
|
||||
hitbox.setCallback((player, action) -> {
|
||||
if (action == REntityAction.INTERACT) {
|
||||
printIntoChat(player);
|
||||
}
|
||||
});
|
||||
setTransform(TNT_VISUAL_TRANSFORM);
|
||||
setBlock(material.createBlockData());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
hitbox.die();
|
||||
super.die();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
-5
@@ -20,8 +20,8 @@
|
||||
package de.steamwar.bausystem.features.tracer.rendering;
|
||||
|
||||
import de.steamwar.bausystem.features.tracer.TNTPoint;
|
||||
import de.steamwar.entity.RBlockDisplay;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RFallingBlockEntity;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.util.Vector;
|
||||
@@ -129,8 +129,9 @@ public abstract class ViewFlag {
|
||||
|
||||
Location yLocation = previous.getLocation().clone().add(0, delta.getY(), 0);
|
||||
if (yLocation.distanceSquared(representative.getLocation()) >= 1.0 / 256.0 && yLocation.distanceSquared(previous.getLocation()) >= 1.0 / 256.0) {
|
||||
RFallingBlockEntity y = new RFallingBlockEntity(server, yLocation, Material.WHITE_STAINED_GLASS);
|
||||
y.setNoGravity(true);
|
||||
RBlockDisplay y = new RBlockDisplay(server, yLocation);
|
||||
y.setBlock(Material.WHITE_STAINED_GLASS.createBlockData());
|
||||
y.setTransform(TraceEntity.TNT_VISUAL_TRANSFORM);
|
||||
}
|
||||
|
||||
Location secoundLocation;
|
||||
@@ -141,8 +142,9 @@ public abstract class ViewFlag {
|
||||
}
|
||||
|
||||
if (secoundLocation.distanceSquared(representative.getLocation()) >= 1.0 / 256.0 && secoundLocation.distanceSquared(previous.getLocation()) >= 1.0 / 256.0) {
|
||||
RFallingBlockEntity second = new RFallingBlockEntity(server, secoundLocation, Material.WHITE_STAINED_GLASS);
|
||||
second.setNoGravity(true);
|
||||
RBlockDisplay second = new RBlockDisplay(server, secoundLocation);
|
||||
second.setBlock(Material.WHITE_STAINED_GLASS.createBlockData());
|
||||
second.setTransform(TraceEntity.TNT_VISUAL_TRANSFORM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -51,6 +51,10 @@ public class IsolateFlag extends ViewFlag {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return tntToIsolate.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
|
||||
if (tntToIsolate.isEmpty()) return records;
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.command.CommandMap;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
@@ -47,7 +48,6 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -73,19 +73,7 @@ public class BindCommand extends SWCommand implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private static final CommandMap commandMap;
|
||||
|
||||
static {
|
||||
Field knownCommandsField;
|
||||
try {
|
||||
knownCommandsField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
|
||||
knownCommandsField.setAccessible(true);
|
||||
commandMap = (CommandMap) knownCommandsField.get(Bukkit.getServer());
|
||||
} catch (IllegalAccessException | NoSuchFieldException var2) {
|
||||
Bukkit.shutdown();
|
||||
throw new SecurityException("Oh shit. Commands cannot be registered.", var2);
|
||||
}
|
||||
}
|
||||
private static final CommandMap commandMap = ((CraftServer) Bukkit.getServer()).getCommandMap();
|
||||
|
||||
private static final NamespacedKey KEY = SWUtils.getNamespaceKey("command");
|
||||
|
||||
|
||||
+27
-7
@@ -24,14 +24,17 @@ import com.mojang.authlib.GameProfile;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
||||
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
|
||||
import de.steamwar.bausystem.utils.NMSWrapper;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.core.ProtocolWrapper;
|
||||
import de.steamwar.core.SWPlayer;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import net.minecraft.network.protocol.game.*;
|
||||
import net.minecraft.world.entity.player.Abilities;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
@@ -57,11 +60,11 @@ public class NoClipCommand extends SWCommand implements Listener {
|
||||
public NoClipCommand() {
|
||||
super("noclip", "nc");
|
||||
|
||||
BiFunction<Player, Object, Object> first = (player, o) -> {
|
||||
BiFunction<Player, ServerboundMovePlayerPacket, Object> first = (player, o) -> {
|
||||
NoClipData noClipData = SWPlayer.of(player).getComponent(NoClipData.class).orElse(null);
|
||||
if (noClipData == null) return o;
|
||||
if (noClipData.lastTick == TPSUtils.currentTick.get()) return o;
|
||||
NMSWrapper.impl.setInternalGameMode(player, GameMode.SPECTATOR);
|
||||
setInternalGameMode(player, GameMode.SPECTATOR);
|
||||
noClipData.lastTick = TPSUtils.currentTick.get();
|
||||
return o;
|
||||
};
|
||||
@@ -71,7 +74,7 @@ public class NoClipCommand extends SWCommand implements Listener {
|
||||
BiFunction<Player, Object, Object> second = (player, o) -> {
|
||||
NoClipData noClipData = SWPlayer.of(player).getComponent(NoClipData.class).orElse(null);
|
||||
if (noClipData == null) return o;
|
||||
NMSWrapper.impl.setInternalGameMode(player, GameMode.CREATIVE);
|
||||
setInternalGameMode(player, GameMode.CREATIVE);
|
||||
noClipData.lastTick = TPSUtils.currentTick.get();
|
||||
return o;
|
||||
};
|
||||
@@ -79,15 +82,29 @@ public class NoClipCommand extends SWCommand implements Listener {
|
||||
TinyProtocol.instance.addFilter(ServerboundPlayerActionPacket.class, second);
|
||||
TinyProtocol.instance.addFilter(ServerboundContainerClickPacket.class, second);
|
||||
|
||||
BiFunction<Player, Object, Object> third = (player, o) -> {
|
||||
BiFunction<Player, ServerboundSetCreativeModeSlotPacket, Object> third = (player, o) -> {
|
||||
if (SWPlayer.of(player).hasComponent(NoClipData.class)) {
|
||||
NMSWrapper.impl.setSlotToItemStack(player, o);
|
||||
int index = o.slotNum();
|
||||
if (index >= 36 && index <= 44) {
|
||||
index -= 36;
|
||||
} else if (index > 44) {
|
||||
index -= 5;
|
||||
} else if (index <= 8) {
|
||||
index = index - 8 + 36;
|
||||
}
|
||||
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(o.itemStack()));
|
||||
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
||||
player.updateInventory();
|
||||
}
|
||||
return o;
|
||||
};
|
||||
TinyProtocol.instance.addFilter(ServerboundSetCreativeModeSlotPacket.class, third);
|
||||
}
|
||||
|
||||
private void setInternalGameMode(Player player, GameMode gameMode) {
|
||||
((CraftPlayer) player).getHandle().gameMode.gameModeForPlayer = GameType.byId(gameMode.getValue());
|
||||
}
|
||||
|
||||
@Register(help = true)
|
||||
public void genericCommand(@Validator Player player) {
|
||||
SWPlayer swPlayer = SWPlayer.of(player);
|
||||
@@ -95,7 +112,9 @@ public class NoClipCommand extends SWCommand implements Listener {
|
||||
swPlayer.removeComponent(NoClipData.class);
|
||||
} else {
|
||||
player.setGameMode(GameMode.SPECTATOR);
|
||||
NMSWrapper.impl.setPlayerBuildAbilities(player);
|
||||
Abilities abilities = (((CraftPlayer) player).getHandle()).getAbilities();
|
||||
abilities.mayBuild = true;
|
||||
abilities.mayfly = true;
|
||||
|
||||
swPlayer.setComponent(new NoClipData());
|
||||
BauSystem.MESSAGE.send("OTHER_NOCLIP_SLOT_INFO", player);
|
||||
@@ -120,6 +139,7 @@ public class NoClipCommand extends SWCommand implements Listener {
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onBlock(BlockCanBuildEvent event) {
|
||||
if (event.getPlayer() == null) return;
|
||||
if (SWPlayer.of(event.getPlayer()).hasComponent(NoClipData.class)) {
|
||||
event.setBuildable(true);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import de.steamwar.bausystem.utils.bossbar.BossBarService;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import de.steamwar.network.packets.PacketHandler;
|
||||
import de.steamwar.network.packets.server.BaumemberUpdatePacket;
|
||||
import io.papermc.paper.event.player.PlayerPickBlockEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
@@ -127,4 +128,11 @@ public class BauMemberUpdate extends PacketHandler implements Listener {
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerClick(PlayerPickBlockEvent event) {
|
||||
if(SPECTATORS.contains(event.getPlayer())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+40
-4
@@ -19,8 +19,9 @@
|
||||
|
||||
package de.steamwar.bausystem.features.world;
|
||||
|
||||
import de.steamwar.bausystem.utils.NMSWrapper;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.item.ItemContainerContents;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -32,6 +33,8 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Linked
|
||||
public class InventoryListener implements Listener {
|
||||
|
||||
@@ -57,7 +60,7 @@ public class InventoryListener implements Listener {
|
||||
}
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
if (NMSWrapper.impl.checkItemStack(stack)) {
|
||||
if (checkItemStack(stack)) {
|
||||
e.setCurrentItem(null);
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
@@ -73,7 +76,7 @@ public class InventoryListener implements Listener {
|
||||
for (int i = 0; i < content.length; i++) {
|
||||
if (content[i] == null) continue;
|
||||
int finalI = i;
|
||||
if (NMSWrapper.impl.checkItemStack(content[finalI])) {
|
||||
if (checkItemStack(content[finalI])) {
|
||||
p.getInventory().setItem(i, null);
|
||||
}
|
||||
}
|
||||
@@ -82,11 +85,44 @@ public class InventoryListener implements Listener {
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
Player p = event.getPlayer();
|
||||
if (NMSWrapper.impl.checkItemStack(event.getItemInHand())) {
|
||||
if (checkItemStack(event.getItemInHand())) {
|
||||
event.setCancelled(true);
|
||||
event.setBuild(false);
|
||||
p.getInventory().setItemInMainHand(null);
|
||||
p.getInventory().setItemInOffHand(null);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int threshold = 2048;
|
||||
|
||||
private boolean checkItemStack(ItemStack item) {
|
||||
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
|
||||
if (data == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return drillDown(data.contents(), 0, 0) > threshold;
|
||||
}
|
||||
|
||||
private int drillDown(List<ItemStack> items, int layer, int start) {
|
||||
if (layer > 2) return start + threshold;
|
||||
int invalid = start;
|
||||
for (int i = start; i < items.size(); i++) {
|
||||
ItemStack item = items.get(i);
|
||||
if (item.isEmpty()) continue;
|
||||
|
||||
invalid += item.getAmount();
|
||||
|
||||
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
|
||||
if (data == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<ItemStack> subItems = data.contents();
|
||||
if (subItems.size() > 1) {
|
||||
invalid = drillDown(subItems, layer + 1, invalid);
|
||||
}
|
||||
}
|
||||
return invalid;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-2
@@ -20,18 +20,24 @@
|
||||
package de.steamwar.bausystem.features.world;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.bausystem.utils.NMSWrapper;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import net.minecraft.network.protocol.game.ClientboundExplodePacket;
|
||||
import org.bukkit.GameMode;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Linked
|
||||
public class NoCreativeKnockback {
|
||||
|
||||
public NoCreativeKnockback() {
|
||||
TinyProtocol.instance.addFilter(ClientboundExplodePacket.class, (player, o) -> {
|
||||
if (player.getGameMode() != GameMode.CREATIVE) return o;
|
||||
return NMSWrapper.impl.resetExplosionKnockback(o);
|
||||
return new ClientboundExplodePacket(
|
||||
o.center(),
|
||||
Optional.empty(),
|
||||
o.explosionParticle(),
|
||||
o.explosionSound()
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ public class SignEdit implements Listener {
|
||||
}
|
||||
|
||||
{
|
||||
TinyProtocol.instance.addTypedFilter(ServerboundSignUpdatePacket.class, (player, o) -> {
|
||||
TinyProtocol.instance.addFilter(ServerboundSignUpdatePacket.class, (player, o) -> {
|
||||
Bukkit.getScheduler().runTask(BauSystem.getInstance(), () -> {
|
||||
ServerLevel serverLevel = ((CraftWorld) player.getWorld()).getHandle();
|
||||
Block signLoc = CraftBlock.at(serverLevel, o.getPos());
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import de.steamwar.bausystem.config.BauServer;
|
||||
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import de.steamwar.sql.BauweltMember;
|
||||
import de.steamwar.techhider.TechHider;
|
||||
import de.steamwar.techhider.legacy.TechHider;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ public class WorldEditListener implements Listener {
|
||||
|
||||
private static final Set<String> commands = new HashSet<>();
|
||||
private static final Set<String> commandExclusions = new HashSet<>();
|
||||
private static final String[] shortcutCommands = {"//1", "//2", "//90", "//-90", "//180", "//p", "//c", "//flopy", "//floppy", "//flopyp", "//floppyp", "//u", "//r"};
|
||||
private static final String[] shortcutCommands = {"//1", "//2", "//90", "//-90", "//180", "//p", "//c", "//flopy", "//floppy", "//flopyp", "//floppyp", "//u", "//r", "//download", "/download"};
|
||||
|
||||
public static boolean isWorldEditCommand(String command) {
|
||||
for (String shortcut : shortcutCommands) {
|
||||
|
||||
@@ -28,7 +28,7 @@ import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.core.CraftbukkitWrapper;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import de.steamwar.linkage.LinkedInstance;
|
||||
import de.steamwar.techhider.TechHider;
|
||||
import de.steamwar.techhider.legacy.TechHider;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@@ -115,8 +115,8 @@ public class XrayCommand extends SWCommand implements Listener, ScoreboardElemen
|
||||
return packet;
|
||||
};
|
||||
|
||||
TinyProtocol.instance.addTypedFilter(ServerboundMovePlayerPacket.Pos.class, positionSetter);
|
||||
TinyProtocol.instance.addTypedFilter(ServerboundMovePlayerPacket.PosRot.class, positionSetter);
|
||||
TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Pos.class, positionSetter);
|
||||
TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.PosRot.class, positionSetter);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
||||
@@ -1,117 +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.bausystem.utils;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.item.ItemContainerContents;
|
||||
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundExplodePacket;
|
||||
import net.minecraft.server.level.ServerPlayerGameMode;
|
||||
import net.minecraft.world.entity.player.Abilities;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class NMSWrapper {
|
||||
public static final NMSWrapper impl = new NMSWrapper();
|
||||
|
||||
private static final Reflection.Field<GameType> playerGameMode = Reflection.getField(ServerPlayerGameMode.class, GameType.class, 0);
|
||||
|
||||
public void setInternalGameMode(Player player, GameMode gameMode) {
|
||||
playerGameMode.set(((CraftPlayer) player).getHandle().gameMode, GameType.byId(gameMode.getValue()));
|
||||
}
|
||||
|
||||
public void setSlotToItemStack(Player player, Object o) {
|
||||
ClientboundContainerSetSlotPacket packetPlayInSetCreativeSlot = (ClientboundContainerSetSlotPacket) o;
|
||||
int index = packetPlayInSetCreativeSlot.getSlot();
|
||||
if (index >= 36 && index <= 44) {
|
||||
index -= 36;
|
||||
} else if (index > 44) {
|
||||
index -= 5;
|
||||
} else if (index <= 8) {
|
||||
index = index - 8 + 36;
|
||||
}
|
||||
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.getItem()));
|
||||
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
||||
player.updateInventory();
|
||||
}
|
||||
|
||||
public void setPlayerBuildAbilities(Player player) {
|
||||
Abilities abilities = (((CraftPlayer) player).getHandle()).getAbilities();
|
||||
abilities.mayBuild = true;
|
||||
abilities.mayfly = true;
|
||||
}
|
||||
|
||||
public Material pathMaterial() {
|
||||
return Material.DIRT_PATH;
|
||||
}
|
||||
|
||||
private static final int threshold = 2048;
|
||||
|
||||
public boolean checkItemStack(ItemStack item) {
|
||||
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
|
||||
if (data == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return drillDown(data.contents(), 0, 0) > threshold;
|
||||
}
|
||||
|
||||
private int drillDown(List<ItemStack> items, int layer, int start) {
|
||||
if (layer > 2) return start + threshold;
|
||||
int invalid = start;
|
||||
for (int i = start; i < items.size(); i++) {
|
||||
ItemStack item = items.get(i);
|
||||
if (item.isEmpty()) continue;
|
||||
|
||||
invalid += item.getAmount();
|
||||
|
||||
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
|
||||
if (data == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<ItemStack> subItems = data.contents();
|
||||
if (subItems.size() > 1) {
|
||||
invalid = drillDown(subItems, layer + 1, invalid);
|
||||
}
|
||||
}
|
||||
return invalid;
|
||||
}
|
||||
|
||||
public Object resetExplosionKnockback(Object packet) {
|
||||
ClientboundExplodePacket explosion = (ClientboundExplodePacket) packet;
|
||||
|
||||
return new ClientboundExplodePacket(
|
||||
explosion.center(),
|
||||
Optional.empty(),
|
||||
explosion.explosionParticle(),
|
||||
explosion.explosionSound()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import de.steamwar.Reflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.UtilityClass;
|
||||
@@ -86,9 +85,6 @@ public class PlaceItemUtils {
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static final Reflection.Field<?> positionAccessor = Reflection.getField(CraftBlockState.class, BlockPos.class, 0);
|
||||
private static final Reflection.Field<?> worldAccessor = Reflection.getField(CraftBlockState.class, CraftWorld.class, 0);
|
||||
|
||||
/**
|
||||
* Attempt to place an {@link ItemStack} the {@link Player} is holding against a {@link Block} inside the World.
|
||||
* This can be easily used inside the {@link org.bukkit.event.player.PlayerInteractEvent} to mimik placing a
|
||||
@@ -288,8 +284,9 @@ public class PlaceItemUtils {
|
||||
} else {
|
||||
// If a BlockState is present set the Position and World to the Block you want to place
|
||||
Location blockLocation = block.getLocation();
|
||||
positionAccessor.set(blockState, new BlockPos(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ()));
|
||||
worldAccessor.set(blockState, blockLocation.getWorld());
|
||||
CraftBlockState craftBlockState = (CraftBlockState) blockState;
|
||||
craftBlockState.position = new BlockPos(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ());
|
||||
craftBlockState.world = (CraftWorld) blockLocation.getWorld();
|
||||
}
|
||||
|
||||
if (blockData.getMaterial().isSolid()) {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import net.minecraft.network.protocol.game.ClientboundTickingStatePacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
@@ -33,7 +32,6 @@ public class TickManager implements Listener {
|
||||
public static final TickManager impl = new TickManager();
|
||||
|
||||
private static final ServerTickRateManager manager = MinecraftServer.getServer().tickRateManager();
|
||||
private static final Reflection.Field<Long> remainingSprintTicks = Reflection.getField(ServerTickRateManager.class, long.class, 0);
|
||||
|
||||
private boolean blockTpsPacket = true;
|
||||
private int totalSteps;
|
||||
@@ -42,7 +40,7 @@ public class TickManager implements Listener {
|
||||
TinyProtocol.instance.addFilter(ClientboundTickingStatePacket.class, this::blockPacket);
|
||||
}
|
||||
|
||||
private Object blockPacket(Player player, Object packet) {
|
||||
private Object blockPacket(Player player, ClientboundTickingStatePacket packet) {
|
||||
if (blockTpsPacket) {
|
||||
return new ClientboundTickingStatePacket(20, manager.isFrozen());
|
||||
} else {
|
||||
@@ -121,7 +119,7 @@ public class TickManager implements Listener {
|
||||
|
||||
public long getRemainingTicks() {
|
||||
if (isSprinting()) {
|
||||
return remainingSprintTicks.get(manager);
|
||||
return manager.remainingSprintTicks;
|
||||
} else {
|
||||
return manager.frozenTicksToRun();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package de.steamwar.bausystem.utils;
|
||||
|
||||
import com.fastasyncworldedit.core.regions.selector.PolyhedralRegionSelector;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
@@ -32,16 +33,19 @@ import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.regions.RegionSelector;
|
||||
import com.sk89q.worldedit.regions.selector.*;
|
||||
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
|
||||
import de.steamwar.Reflection;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import de.steamwar.bausystem.shared.Pair;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@UtilityClass
|
||||
@@ -91,17 +95,36 @@ public class WorldEditUtils {
|
||||
.getRegionSelector(BukkitAdapter.adapt(player.getWorld()));
|
||||
return new Pair<>(regionSelector.getClass(), regionSelector.getVertices()
|
||||
.stream()
|
||||
.map(blockVector3 -> blockVector3 == null ? null : adapt(player.getWorld(), blockVector3))
|
||||
.map(blockVector3 -> {
|
||||
if (blockVector3 == null) {
|
||||
return null;
|
||||
} else {
|
||||
return BukkitAdapter.adapt(player.getWorld(), blockVector3);
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private static final Map<Class<? extends RegionSelector>, Function<World, RegionSelector>> constructors = new HashMap<>();
|
||||
static {
|
||||
constructors.put(CuboidRegionSelector.class, CuboidRegionSelector::new);
|
||||
constructors.put(ExtendingCuboidRegionSelector.class, ExtendingCuboidRegionSelector::new);
|
||||
constructors.put(Polygonal2DRegionSelector.class, Polygonal2DRegionSelector::new);
|
||||
constructors.put(EllipsoidRegionSelector.class, EllipsoidRegionSelector::new);
|
||||
constructors.put(SphereRegionSelector.class, SphereRegionSelector::new);
|
||||
constructors.put(CylinderRegionSelector.class, CylinderRegionSelector::new);
|
||||
constructors.put(ConvexPolyhedralRegionSelector.class, ConvexPolyhedralRegionSelector::new);
|
||||
constructors.put(PolyhedralRegionSelector.class, PolyhedralRegionSelector::new);
|
||||
}
|
||||
|
||||
public void setVertices(Player player, Class<? extends RegionSelector> clazz, List<Location> vertices) {
|
||||
LocalSession localSession = WorldEdit.getInstance()
|
||||
.getSessionManager()
|
||||
.get(BukkitAdapter.adapt(player));
|
||||
|
||||
Reflection.Constructor constructorInvoker = Reflection.getConstructor(clazz, com.sk89q.worldedit.world.World.class);
|
||||
RegionSelector regionSelector = (RegionSelector) constructorInvoker.invoke(BukkitAdapter.adapt(player.getWorld()));
|
||||
Function<World, RegionSelector> constructor = constructors.get(clazz);
|
||||
if (constructor == null) return;
|
||||
RegionSelector regionSelector = constructor.apply(BukkitAdapter.adapt(player.getWorld()));
|
||||
localSession.setRegionSelector(BukkitAdapter.adapt(player.getWorld()), regionSelector);
|
||||
|
||||
if (vertices.isEmpty()) return;
|
||||
@@ -127,13 +150,9 @@ public class WorldEditUtils {
|
||||
try {
|
||||
BlockVector3 min = regionSelector.getRegion().getMinimumPoint();
|
||||
BlockVector3 max = regionSelector.getRegion().getMaximumPoint();
|
||||
return new Pair<>(adapt(player.getWorld(), min), adapt(player.getWorld(), max));
|
||||
return new Pair<>(BukkitAdapter.adapt(player.getWorld(), min), BukkitAdapter.adapt(player.getWorld(), max));
|
||||
} catch (IncompleteRegionException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Location adapt(World world, BlockVector3 blockVector3) {
|
||||
return new Location(world, blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ version: "2.0"
|
||||
depend: [ WorldEdit, SpigotCore ]
|
||||
load: POSTWORLD
|
||||
main: de.steamwar.bausystem.BauSystem
|
||||
api-version: "1.13"
|
||||
api-version: "1.21"
|
||||
website: "https://steamwar.de"
|
||||
description: "So unseriös wie wir sind: BauSystem nur besser."
|
||||
|
||||
|
||||
@@ -31,20 +31,12 @@ dependencies {
|
||||
implementation(project(":BauSystem:BauSystem_Main"))
|
||||
}
|
||||
|
||||
tasks.register<DevServer>("DevBau20") {
|
||||
group = "run"
|
||||
description = "Run a 1.20 Dev Bau"
|
||||
dependsOn(":SpigotCore:shadowJar")
|
||||
dependsOn(":BauSystem:shadowJar")
|
||||
dependsOn(":SchematicSystem:shadowJar")
|
||||
template = "Bau20"
|
||||
}
|
||||
|
||||
tasks.register<DevServer>("DevBau21") {
|
||||
group = "run"
|
||||
description = "Run a 1.21 Dev Bau"
|
||||
dependsOn(":SpigotCore:shadowJar")
|
||||
dependsOn(":BauSystem:shadowJar")
|
||||
dependsOn(":SchematicSystem:shadowJar")
|
||||
dependsOn(":KotlinCore:shadowJar")
|
||||
template = "Bau21"
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ dependencies {
|
||||
implementation("com.github.ajalt.clikt:clikt:5.0.3")
|
||||
implementation("com.github.ajalt.mordant:mordant:3.0.2")
|
||||
implementation(libs.logback)
|
||||
implementation("org.yaml:snakeyaml:2.2")
|
||||
implementation("org.mariadb.jdbc:mariadb-java-client:3.3.1")
|
||||
|
||||
implementation(libs.exposedCore)
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.github.ajalt.mordant.rendering.TextColors
|
||||
import com.github.ajalt.mordant.rendering.TextStyles
|
||||
import de.steamwar.db.Database
|
||||
import de.steamwar.db.execute
|
||||
import de.steamwar.db.executeScript
|
||||
import de.steamwar.db.useDb
|
||||
import java.io.File
|
||||
|
||||
@@ -22,13 +23,25 @@ class ResetCommand : CliktCommand() {
|
||||
|
||||
val schema = schemaFile.readText()
|
||||
|
||||
val tables = execute("SHOW TABLES;") { it.getString(1) }
|
||||
for (table in tables) {
|
||||
execute("DROP TABLE IF EXISTS $table;") { }
|
||||
execute("SET FOREIGN_KEY_CHECKS=0;") { }
|
||||
|
||||
val databaseObjects = execute("SHOW FULL TABLES;") { it.getString(1) to it.getString(2) }
|
||||
for (view in databaseObjects.filter { it.second == "VIEW" }.map { it.first }) {
|
||||
execute("DROP VIEW IF EXISTS `${view.replace("`", "``")}`;") { }
|
||||
}
|
||||
for (table in databaseObjects.filter { it.second == "BASE TABLE" }.map { it.first }) {
|
||||
execute("DROP TABLE IF EXISTS `${table.replace("`", "``")}`;") { }
|
||||
}
|
||||
|
||||
execute(schema) { }
|
||||
executeScript(schema)
|
||||
|
||||
val seed = javaClass.getResource("/db/reset-seed.sql")
|
||||
?: throw CliktError("Reset seed file not found!")
|
||||
|
||||
executeScript(seed.readText())
|
||||
|
||||
execute("SET FOREIGN_KEY_CHECKS=1;") { }
|
||||
|
||||
echo(TextColors.brightGreen(TextStyles.bold("Database reset!")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,11 @@ import com.github.ajalt.clikt.parameters.types.file
|
||||
import com.github.ajalt.clikt.parameters.types.long
|
||||
import com.github.ajalt.clikt.parameters.types.path
|
||||
import com.sun.security.auth.module.UnixSystem
|
||||
import org.yaml.snakeyaml.Yaml
|
||||
import java.io.File
|
||||
import kotlin.io.path.absolute
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.random.Random
|
||||
|
||||
const val LOG4J_CONFIG = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN" packages="com.mojang.util">
|
||||
@@ -69,35 +71,47 @@ class DevCommand : CliktCommand("dev") {
|
||||
override fun run() {
|
||||
val args = mutableListOf<String>()
|
||||
|
||||
val serverDirectory = File(workingDir, server)
|
||||
val serverDir =
|
||||
if (serverDirectory.exists() && serverDirectory.isDirectory) serverDirectory else File(workingDir, server)
|
||||
var serverDir = resolveServerDirectory(server)
|
||||
|
||||
if (isVelocity(server)) {
|
||||
runServer(
|
||||
args, jvmArgs, listOf(
|
||||
jar?.absolutePath
|
||||
?: File("/jar/Velocity.jar").absolutePath
|
||||
?: File("/jars/Velocity.jar").absolutePath
|
||||
), serverDir
|
||||
)
|
||||
} else {
|
||||
setLogConfig(args)
|
||||
val version = findVersion(server)
|
||||
?: throw CliktError("Unknown Server Version")
|
||||
val gameModeTemplate = if (serverDir.isDirectory) null else loadGameModeTemplate(server)
|
||||
if (gameModeTemplate != null) {
|
||||
serverDir = gameModeTemplate.serverDir
|
||||
args += "-Dconfig=$server.yml"
|
||||
}
|
||||
val worldFile = world?.absolute()?.toFile()
|
||||
?: File(serverDir, "devtempworld")
|
||||
val jarFile = jar?.absolutePath
|
||||
?: File(workingDir, "devtempworld")
|
||||
var jarFile = jar?.absolutePath
|
||||
?: additionalVersions[server]?.let { supportedVersionJars[it] }
|
||||
?: supportedVersionJars[version]
|
||||
?: throw CliktError("Unknown Server Version")
|
||||
if (gameModeTemplate != null) {
|
||||
jarFile = if (gameModeTemplate.spigot) {
|
||||
jarFile.replace("paper", "spigot")
|
||||
} else {
|
||||
jarFile.replace("spigot", "paper")
|
||||
}
|
||||
}
|
||||
|
||||
if (!worldFile.exists()) {
|
||||
val templateFile = File(serverDir, "Bauwelt")
|
||||
val templateFile = gameModeTemplate?.worldTemplate ?: File(serverDir, "Bauwelt")
|
||||
if (!templateFile.exists()) {
|
||||
throw CliktError("World Template not found!")
|
||||
throw CliktError("Could not find world template: ${templateFile.absolutePath}")
|
||||
}
|
||||
worldFile.parentFile?.mkdirs()
|
||||
templateFile.copyRecursively(worldFile)
|
||||
}
|
||||
val worldDir = worldFile.parentFile ?: workingDir
|
||||
|
||||
val devFile = File("/configs/DevServer/${System.getProperty("user.name")}.$port.$version")
|
||||
if (System.getProperty("user.name") != "minecraft") {
|
||||
@@ -108,10 +122,11 @@ class DevCommand : CliktCommand("dev") {
|
||||
args, jvmArgs, listOf(
|
||||
jarFile,
|
||||
*(if (forceUpgrade) arrayOf("-forceUpgrade") else arrayOf()),
|
||||
"--log-strip-color",
|
||||
"--port", port.toString(),
|
||||
"--level-name", worldFile.name,
|
||||
"--world-dir", workingDir.absolutePath,
|
||||
"--nogui",
|
||||
"--world-dir", worldDir.absolutePath,
|
||||
"nogui",
|
||||
*(if (plugins != null) arrayOf("--plugins", plugins!!.absolutePathString()) else arrayOf())
|
||||
), serverDir
|
||||
)
|
||||
@@ -123,6 +138,12 @@ class DevCommand : CliktCommand("dev") {
|
||||
}
|
||||
}
|
||||
|
||||
data class GameModeTemplate(
|
||||
val serverDir: File,
|
||||
val worldTemplate: File,
|
||||
val spigot: Boolean
|
||||
)
|
||||
|
||||
val jvmDefaultParams = arrayOf(
|
||||
"-Xmx1G",
|
||||
"-Xgc:excessiveGCratio=80",
|
||||
@@ -138,6 +159,16 @@ class DevCommand : CliktCommand("dev") {
|
||||
|
||||
val jvmArgOverrides = arrayOf("--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED")
|
||||
|
||||
val jvmNonJava8Params = arrayOf(
|
||||
*jvmArgOverrides,
|
||||
"-XX:-CRIUSecProvider"
|
||||
)
|
||||
|
||||
val extendedStartupParams = arrayOf(
|
||||
"-Dpaper.disablePluginRemapping=true",
|
||||
"-javaagent:/jars/AccessWidener.jar=start"
|
||||
)
|
||||
|
||||
val supportedVersionJars = mapOf(
|
||||
8 to "/jars/paper-1.8.8.jar",
|
||||
9 to "/jars/spigot-1.9.4.jar",
|
||||
@@ -152,8 +183,7 @@ class DevCommand : CliktCommand("dev") {
|
||||
)
|
||||
|
||||
val additionalVersions = mapOf(
|
||||
"Tutorial" to 15,
|
||||
"Lobby" to 20
|
||||
"Lobby" to 21
|
||||
)
|
||||
|
||||
fun findVersion(server: String): Int? =
|
||||
@@ -166,6 +196,41 @@ class DevCommand : CliktCommand("dev") {
|
||||
fun isVelocity(server: String): Boolean =
|
||||
server.endsWith("Velocity")
|
||||
|
||||
fun resolveServerDirectory(server: String): File {
|
||||
val localServer = File(workingDir, server)
|
||||
if (localServer.isDirectory) {
|
||||
return localServer
|
||||
}
|
||||
return File("/servers", server)
|
||||
}
|
||||
|
||||
fun loadGameModeTemplate(server: String): GameModeTemplate? {
|
||||
val configFile = File("/configs/GameModes/$server.yml")
|
||||
if (!configFile.exists()) {
|
||||
throw CliktError("Server/GameMode not found")
|
||||
}
|
||||
|
||||
val document = configFile.reader().use { reader ->
|
||||
Yaml().load<Map<String, Any?>>(reader)
|
||||
} ?: throw CliktError("GameMode config is empty: ${configFile.absolutePath}")
|
||||
val serverConfig = document["Server"] as? Map<*, *>
|
||||
?: throw CliktError("GameMode config is missing Server section: ${configFile.absolutePath}")
|
||||
val folder = serverConfig["Folder"] as? String
|
||||
?: throw CliktError("GameMode config is missing Server.Folder: ${configFile.absolutePath}")
|
||||
val maps = (serverConfig["Maps"] as? List<*>)
|
||||
?.filterIsInstance<String>()
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?: throw CliktError("GameMode config is missing Server.Maps: ${configFile.absolutePath}")
|
||||
|
||||
val serverDir = File("/servers", folder)
|
||||
val worldTemplate = File(File(serverDir, "arenas"), maps[Random.nextInt(maps.size)])
|
||||
return GameModeTemplate(
|
||||
serverDir = serverDir,
|
||||
worldTemplate = worldTemplate,
|
||||
spigot = serverConfig["Spigot"] == true
|
||||
)
|
||||
}
|
||||
|
||||
fun setLogConfig(args: MutableList<String>) {
|
||||
args += "-DlogPath=${workingDir.absolutePath}/logs"
|
||||
args += "-Dlog4j.configurationFile=${log4jConfig.absolutePath}"
|
||||
@@ -176,13 +241,23 @@ class DevCommand : CliktCommand("dev") {
|
||||
}
|
||||
|
||||
fun runServer(args: List<String>, jvmArgs: List<String>, cmd: List<String>, serverDir: File) {
|
||||
val effectiveJvmArgs = mutableListOf<String>()
|
||||
effectiveJvmArgs += jvmArgs
|
||||
if (!isVelocity(server)) {
|
||||
extendedStartupParams.forEach { arg ->
|
||||
if (effectiveJvmArgs.none { it == arg }) {
|
||||
effectiveJvmArgs += arg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val process = ProcessBuilder(
|
||||
jvm?.absolutePath
|
||||
?: if (isJava8(server)) "/usr/lib/jvm/openj9-8/bin/java" else "java",
|
||||
*jvmArgs.toTypedArray(),
|
||||
?: if (isJava8(server)) "/usr/lib/jvm/openj9-8/bin/java" else "/usr/lib/jvm/openj9-21/bin/java",
|
||||
*effectiveJvmArgs.toTypedArray(),
|
||||
*args.toTypedArray(),
|
||||
*jvmDefaultParams,
|
||||
*(if (isJava8(server)) arrayOf() else jvmArgOverrides),
|
||||
*(if (isJava8(server)) arrayOf() else jvmNonJava8Params),
|
||||
*(if (profile) arrayOf("-javaagent:/jars/LixfelsProfiler.jar=start") else arrayOf()),
|
||||
"-Xshareclasses:nonfatal,name=$server",
|
||||
"-jar",
|
||||
@@ -191,4 +266,4 @@ class DevCommand : CliktCommand("dev") {
|
||||
Runtime.getRuntime().addShutdownHook(Thread { if (process.isAlive) process.destroyForcibly() })
|
||||
process.waitFor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+120
-9
@@ -16,15 +16,14 @@ import java.sql.ResultSet
|
||||
import java.util.*
|
||||
|
||||
object Database {
|
||||
lateinit var host: String
|
||||
lateinit var port: String
|
||||
lateinit var database: String
|
||||
val host: String
|
||||
val port: String
|
||||
val database: String
|
||||
val username: String
|
||||
val password: String
|
||||
lateinit var db: Database
|
||||
|
||||
fun ensureConnected() {
|
||||
if (::db.isInitialized) {
|
||||
return
|
||||
}
|
||||
init {
|
||||
val config = File(System.getProperty("user.home"), "mysql.properties")
|
||||
|
||||
if (!config.exists()) {
|
||||
@@ -38,9 +37,14 @@ object Database {
|
||||
host = props.getProperty("host")
|
||||
port = props.getProperty("port")
|
||||
database = props.getProperty("database")
|
||||
username = props.getProperty("user")
|
||||
password = props.getProperty("password")
|
||||
}
|
||||
|
||||
val username = props.getProperty("user")
|
||||
val password = props.getProperty("password")
|
||||
fun ensureConnected() {
|
||||
if (::db.isInitialized) {
|
||||
return
|
||||
}
|
||||
|
||||
val url = "jdbc:mariadb://$host:$port/$database"
|
||||
|
||||
@@ -79,6 +83,113 @@ fun <T> JdbcTransaction.executeSingle(sql: String, transform: (ResultSet) -> T):
|
||||
}.single()
|
||||
}
|
||||
|
||||
fun JdbcTransaction.executeScript(sql: String) {
|
||||
for (statement in splitSqlScript(sql)) {
|
||||
exec(statement) { }
|
||||
}
|
||||
}
|
||||
|
||||
private fun splitSqlScript(sql: String): List<String> {
|
||||
val statements = mutableListOf<String>()
|
||||
val current = StringBuilder()
|
||||
var quote: Char? = null
|
||||
var inLineComment = false
|
||||
var inBlockComment = false
|
||||
var index = 0
|
||||
|
||||
fun addStatement() {
|
||||
val statement = current.toString().trim()
|
||||
if (statement.isNotEmpty()) {
|
||||
statements += statement
|
||||
}
|
||||
current.clear()
|
||||
}
|
||||
|
||||
while (index < sql.length) {
|
||||
val char = sql[index]
|
||||
val next = sql.getOrNull(index + 1)
|
||||
|
||||
if (inLineComment) {
|
||||
current.append(char)
|
||||
if (char == '\n') {
|
||||
inLineComment = false
|
||||
}
|
||||
index++
|
||||
continue
|
||||
}
|
||||
|
||||
if (inBlockComment) {
|
||||
current.append(char)
|
||||
if (char == '*' && next == '/') {
|
||||
current.append(next)
|
||||
inBlockComment = false
|
||||
index += 2
|
||||
} else {
|
||||
index++
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (quote != null) {
|
||||
current.append(char)
|
||||
if (char == '\\' && quote != '`' && next != null) {
|
||||
current.append(next)
|
||||
index += 2
|
||||
continue
|
||||
}
|
||||
if (char == quote) {
|
||||
if (next == quote) {
|
||||
current.append(next)
|
||||
index += 2
|
||||
continue
|
||||
}
|
||||
quote = null
|
||||
}
|
||||
index++
|
||||
continue
|
||||
}
|
||||
|
||||
when {
|
||||
char == '-' && next == '-' -> {
|
||||
current.append(char).append(next)
|
||||
inLineComment = true
|
||||
index += 2
|
||||
}
|
||||
|
||||
char == '#' -> {
|
||||
current.append(char)
|
||||
inLineComment = true
|
||||
index++
|
||||
}
|
||||
|
||||
char == '/' && next == '*' -> {
|
||||
current.append(char).append(next)
|
||||
inBlockComment = true
|
||||
index += 2
|
||||
}
|
||||
|
||||
char == '\'' || char == '"' || char == '`' -> {
|
||||
current.append(char)
|
||||
quote = char
|
||||
index++
|
||||
}
|
||||
|
||||
char == ';' -> {
|
||||
addStatement()
|
||||
index++
|
||||
}
|
||||
|
||||
else -> {
|
||||
current.append(char)
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addStatement()
|
||||
return statements
|
||||
}
|
||||
|
||||
fun useDb(statement: JdbcTransaction.() -> Unit) {
|
||||
de.steamwar.db.Database.ensureConnected()
|
||||
transaction(de.steamwar.db.Database.db, statement = statement)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -86,6 +86,24 @@ class CheckedSchematic(id: EntityID<CompositeID>) : CompositeEntity(id) {
|
||||
useDb {
|
||||
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.seen eq false) }.orderBy(CheckedSchematicTable.endTime to SortOrder.DESC).toList()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun countAccepted(owner: SteamwarUser) =
|
||||
useDb {
|
||||
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.declineReason eq "freigegeben") }.count()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun countAccepted(owner: SteamwarUser, type: String) =
|
||||
useDb {
|
||||
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.declineReason eq "freigegeben") and (CheckedSchematicTable.nodeType like "$type%") }.count()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun countChecked(validator: SteamwarUser) =
|
||||
useDb {
|
||||
find { CheckedSchematicTable.validator eq validator.id }.count()
|
||||
}
|
||||
}
|
||||
|
||||
val node by CheckedSchematicTable.nodeId.transform({ it?.let { EntityID(it, SchematicNodeTable) } }, { it?.value })
|
||||
|
||||
@@ -130,6 +130,43 @@ class EventFight(id: EntityID<Int>) : IntEntity(id), Comparable<EventFight> {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun countEventFights(fighter: SteamwarUser) =
|
||||
useDb {
|
||||
exec(
|
||||
"SELECT COUNT(DISTINCT F.FightID) AS FightCount FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID INNER JOIN EventFight EF on F.FightID = EF.Fight WHERE UserID = ?",
|
||||
args = listOf(IntegerColumnType() to fighter.id.value)
|
||||
) {
|
||||
if (it.next()) {
|
||||
it.getLong("FightCount")
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
?: 0
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun countPlacement(fighter: SteamwarUser, placement: Int) =
|
||||
useDb {
|
||||
exec(
|
||||
"""
|
||||
SELECT COUNT(DISTINCT EventFight.EventID) AS PlacementCount FROM TeamTeilnahme
|
||||
INNER JOIN EventFight ON EventFight.EventID = TeamTeilnahme.EventID
|
||||
INNER JOIN FightPlayer ON FightPlayer.FightID = EventFight.Fight
|
||||
WHERE (IF(FightPlayer.Team = 1, EventFight.TeamBlue, EventFight.TeamRed)) = TeamTeilnahme.TeamID AND UserID = ? AND Placement = ?
|
||||
""".trimIndent(),
|
||||
args = listOf(IntegerColumnType() to fighter.id.value, IntegerColumnType() to placement)
|
||||
) {
|
||||
if (it.next()) {
|
||||
it.getInt("PlacementCount")
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
?: 0
|
||||
}
|
||||
}
|
||||
|
||||
val fightID by EventFightTable.id.transform({ EntityID(it, EventFightTable) }, { it.value })
|
||||
@@ -200,6 +237,7 @@ class EventFight(id: EntityID<Int>) : IntEntity(id), Comparable<EventFight> {
|
||||
|
||||
override fun delete() =
|
||||
useDb {
|
||||
EventRelation.deleteRelations(this@EventFight)
|
||||
super.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,10 +159,13 @@ class EventGroup(id: EntityID<Int>) : IntEntity(id) {
|
||||
}
|
||||
|
||||
override fun delete() =
|
||||
useDb { super.delete() }
|
||||
useDb {
|
||||
EventRelation.deleteRelations(this@EventGroup)
|
||||
super.delete()
|
||||
}
|
||||
|
||||
enum class EventGroupType {
|
||||
GROUP_STAGE,
|
||||
ELIMINATION_STAGE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ import org.jetbrains.exposed.v1.core.and
|
||||
import org.jetbrains.exposed.v1.core.dao.id.EntityID
|
||||
import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
|
||||
import org.jetbrains.exposed.v1.core.eq
|
||||
import org.jetbrains.exposed.v1.core.or
|
||||
import org.jetbrains.exposed.v1.dao.IntEntity
|
||||
import org.jetbrains.exposed.v1.dao.IntEntityClass
|
||||
import org.jetbrains.exposed.v1.jdbc.deleteWhere
|
||||
import org.jetbrains.exposed.v1.jdbc.select
|
||||
|
||||
object EventRelationTable : IntIdTable("EventRelation") {
|
||||
@@ -59,6 +61,23 @@ class EventRelation(id: EntityID<Int>) : IntEntity(id) {
|
||||
fun getGroupRelations(group: EventGroup) =
|
||||
useDb { find { (EventRelationTable.fromId eq group.id.value) and (EventRelationTable.fromType eq FromType.GROUP) }.toList() }
|
||||
|
||||
@JvmStatic
|
||||
fun deleteRelations(fight: EventFight) =
|
||||
useDb {
|
||||
EventRelationTable.deleteWhere {
|
||||
(EventRelationTable.fightId eq fight.id) or
|
||||
((EventRelationTable.fromId eq fight.id.value) and (EventRelationTable.fromType eq FromType.FIGHT))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun deleteRelations(group: EventGroup) =
|
||||
useDb {
|
||||
EventRelationTable.deleteWhere {
|
||||
(EventRelationTable.fromId eq group.id.value) and (EventRelationTable.fromType eq FromType.GROUP)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun create(fight: EventFight, fightTeam: FightTeam, fromType: FromType, fromId: Int, fromPlace: Int) =
|
||||
useDb {
|
||||
@@ -159,4 +178,4 @@ class EventRelation(id: EntityID<Int>) : IntEntity(id) {
|
||||
enum class FromType {
|
||||
FIGHT, GROUP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,12 @@
|
||||
package de.steamwar.sql
|
||||
|
||||
import de.steamwar.sql.internal.useDb
|
||||
import org.jetbrains.exposed.v1.core.IntegerColumnType
|
||||
import org.jetbrains.exposed.v1.core.VarCharColumnType
|
||||
import org.jetbrains.exposed.v1.core.dao.id.CompositeID
|
||||
import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
|
||||
import org.jetbrains.exposed.v1.core.dao.id.EntityID
|
||||
import org.jetbrains.exposed.v1.core.eq
|
||||
import org.jetbrains.exposed.v1.core.inList
|
||||
import org.jetbrains.exposed.v1.dao.CompositeEntity
|
||||
import org.jetbrains.exposed.v1.dao.CompositeEntityClass
|
||||
@@ -69,6 +72,28 @@ class FightPlayer(id: EntityID<CompositeID>) : CompositeEntity(id) {
|
||||
useDb {
|
||||
find { FightPlayerTable.fightId inList fightIds.toList() }.toList()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun countFights(userId: Int) =
|
||||
useDb {
|
||||
find { FightPlayerTable.userId eq userId }.count()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun countFights(userId: Int, type: String) =
|
||||
useDb {
|
||||
exec(
|
||||
"SELECT COUNT(*) AS FightCount FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID WHERE UserID = ? AND GameMode LIKE ?",
|
||||
args = listOf(IntegerColumnType() to userId, VarCharColumnType() to "$type%")
|
||||
) {
|
||||
if (it.next()) {
|
||||
it.getInt("FightCount")
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
?: 0
|
||||
}
|
||||
}
|
||||
|
||||
val fightID by FightPlayerTable.fightId.transform({ EntityID(it, FightTable) }, { it.value })
|
||||
|
||||
@@ -146,12 +146,12 @@ public final class GameModeConfig<M, W> {
|
||||
public final List<String> CheckQuestions;
|
||||
|
||||
/**
|
||||
* The allowed checkers to check this schematic type denoted by a list of SteamWar ids.
|
||||
* The allowed checkers to check this schematic type denoted by a list of SteamwarUser ids.
|
||||
* The people need the {@link UserPerm#CHECK} to be able to check though.
|
||||
*
|
||||
* @implSpec {@code []} by default -> denoting every person with {@link UserPerm#CHECK} can check it
|
||||
*/
|
||||
public final List<Integer> Checkers;
|
||||
public final Set<Integer> Checkers;
|
||||
|
||||
/**
|
||||
* Bundle for countdowns during the fight
|
||||
@@ -246,7 +246,7 @@ public final class GameModeConfig<M, W> {
|
||||
}
|
||||
|
||||
CheckQuestions = loader.getStringList("CheckQuestions");
|
||||
Checkers = loader.getIntList("Checkers");
|
||||
Checkers = loader.getIntSet("Checkers");
|
||||
Times = new TimesConfig(loader.with("Times"));
|
||||
// Arena would be here to be in config order but needs Schematic.Size and EnterStages loaded afterwards
|
||||
Schematic = new SchematicConfig<>(loader.with("Schematic"));
|
||||
@@ -488,6 +488,27 @@ public final class GameModeConfig<M, W> {
|
||||
*/
|
||||
public final boolean NoFloor;
|
||||
|
||||
/**
|
||||
* Allows Wind Charges to cross the Middle.
|
||||
*
|
||||
* @implSpec {@code false} by default
|
||||
*/
|
||||
public final boolean WindchargesCanCrossMiddle;
|
||||
|
||||
/**
|
||||
* Allows Wind Charge interaction with Blocks.
|
||||
*
|
||||
* @implSpec {@code true} by default
|
||||
*/
|
||||
public final boolean WindchargesInteractWithBlocks;
|
||||
|
||||
/**
|
||||
* Allows Wind Charge to destroy Water.
|
||||
*
|
||||
* @implSpec {@code false} by default
|
||||
*/
|
||||
public final boolean WindchargesDestroyWater;
|
||||
|
||||
private ArenaConfig(YMLWrapper<M, W> loader, SchematicConfig.SizeConfig Size, List<Integer> EnterStages) {
|
||||
loaded = loader.canLoad();
|
||||
WaterDepth = loader.getInt("WaterDepth", 0);
|
||||
@@ -505,6 +526,9 @@ public final class GameModeConfig<M, W> {
|
||||
Leaveable = loader.getBoolean("Leaveable", false);
|
||||
AllowMissiles = loader.getBoolean("AllowMissiles", !EnterStages.isEmpty());
|
||||
NoFloor = loader.getBoolean("NoFloor", false);
|
||||
WindchargesCanCrossMiddle = loader.getBoolean("WindchargesCanCrossMiddle", false);
|
||||
WindchargesInteractWithBlocks = loader.getBoolean("WindchargesInteractWithBlocks", true);
|
||||
WindchargesDestroyWater = loader.getBoolean("WindchargesDestroyWater", false);
|
||||
}
|
||||
|
||||
@ToString
|
||||
@@ -929,6 +953,13 @@ public final class GameModeConfig<M, W> {
|
||||
*/
|
||||
public final boolean PersonalKits;
|
||||
|
||||
/**
|
||||
* Maximal blast resistance for the blocks in the kit
|
||||
*
|
||||
* @implSpec {@code 9.0} by default
|
||||
*/
|
||||
public final double MaxBlastResistance;
|
||||
|
||||
/**
|
||||
* Items (Valid spigot material values) that are not allowed in the personal kit
|
||||
*/
|
||||
@@ -940,7 +971,10 @@ public final class GameModeConfig<M, W> {
|
||||
MemberDefault = loader.getString("MemberDefault", "default");
|
||||
LeaderDefault = loader.getString("LeaderDefault", "default");
|
||||
PersonalKits = loader.getBoolean("PersonalKits", false);
|
||||
ForbiddenItems = loader.getMaterialList("ForbiddenItems");
|
||||
MaxBlastResistance = loader.getDouble("MaxBlastResistance", 9.0);
|
||||
List forbiddenItems = new ArrayList<>(loader.getMaterialList("ForbiddenItems"));
|
||||
forbiddenItems.addAll(SQLWrapper.impl.getMaterialWithGreaterBlastResistance(MaxBlastResistance));
|
||||
ForbiddenItems = Collections.unmodifiableList(forbiddenItems);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -434,7 +434,7 @@ class SchematicNode(id: EntityID<Int>) : IntEntity(id) {
|
||||
private var nodeItem by SchematicNodeTable.item
|
||||
var item: String
|
||||
get() = nodeItem.ifEmpty {
|
||||
if (isDir()) "CHEST" else "CAULDRON_ITEM"
|
||||
if (isDir()) "CHEST" else "CAULDRON"
|
||||
}
|
||||
set(value) = useDb {
|
||||
nodeItem = value
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.exposed.v1.core.dao.id.EntityID
|
||||
import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
|
||||
import org.jetbrains.exposed.v1.core.eq
|
||||
import org.jetbrains.exposed.v1.core.inList
|
||||
import org.jetbrains.exposed.v1.core.neq
|
||||
import org.jetbrains.exposed.v1.dao.IntEntity
|
||||
import org.jetbrains.exposed.v1.dao.IntEntityClass
|
||||
import org.jetbrains.exposed.v1.jdbc.insert
|
||||
@@ -136,6 +137,12 @@ class SteamwarUser(id: EntityID<Int>) : IntEntity(id) {
|
||||
.select(SteamwarUserTable.fields).where { UserPermTable.perm eq perm }.map { wrapRow(it) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getUsersWithDiscordId() =
|
||||
useDb {
|
||||
find { SteamwarUserTable.discordId neq null }.toList()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getServerTeam() =
|
||||
useDb {
|
||||
@@ -175,6 +182,9 @@ class SteamwarUser(id: EntityID<Int>) : IntEntity(id) {
|
||||
leaderInternal = false
|
||||
}
|
||||
|
||||
fun hasTeam() =
|
||||
team != 0
|
||||
|
||||
private var leaderInternal by SteamwarUserTable.leader
|
||||
var leader: Boolean
|
||||
get() = leaderInternal
|
||||
|
||||
@@ -63,11 +63,11 @@ enum class UserPerm {
|
||||
PREFIX_NONE to emptyPrefix,
|
||||
PREFIX_YOUTUBER to Prefix("§x§8§A§2§B§E§5", "CC"), // 8A2BE5
|
||||
PREFIX_GUIDE to Prefix("§x§e§7§6§2§e§d", "Guide"), // E762ED
|
||||
PREFIX_SUPPORTER to Prefix("§x§6§0§9§5§F§B", "Sup"), // 6095FB
|
||||
PREFIX_MODERATOR to Prefix("§x§F§F§A§2§5§C", "Mod"), // FFA25C
|
||||
PREFIX_BUILDER to Prefix("§x§6§0§F§F§6§A", "Arch"), // 60FF6A
|
||||
PREFIX_DEVELOPER to Prefix("§x§0§B§B§C§B§3", "Dev"), // 0BBCB3
|
||||
PREFIX_ADMIN to Prefix("§x§F§F§2§B§2§4", "Admin"), // FF2B24
|
||||
PREFIX_SUPPORTER to Prefix("§x§6§0§9§5§F§B", "Sup", true), // 6095FB
|
||||
PREFIX_MODERATOR to Prefix("§x§F§F§A§2§5§C", "Mod", true), // FFA25C
|
||||
PREFIX_BUILDER to Prefix("§x§6§0§F§F§6§A", "Arch", true), // 60FF6A
|
||||
PREFIX_DEVELOPER to Prefix("§x§0§B§B§C§B§3", "Dev", true), // 0BBCB3
|
||||
PREFIX_ADMIN to Prefix("§x§F§F§2§B§2§4", "Admin", true), // FF2B24
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@@ -94,5 +94,5 @@ enum class UserPerm {
|
||||
}
|
||||
}
|
||||
|
||||
data class Prefix(val colorCode: String, val chatPrefix: String)
|
||||
data class Prefix(val colorCode: String, val chatPrefix: String, val teamPrefix: Boolean = false)
|
||||
}
|
||||
@@ -139,6 +139,12 @@ final class YMLWrapper<M, W> {
|
||||
return get(path, o -> (List<Integer>) o);
|
||||
}
|
||||
|
||||
public Set<Integer> getIntSet(String path) {
|
||||
List<Integer> list = get(path, o -> (List<Integer>) o);
|
||||
if (list.isEmpty()) return Collections.emptySet();
|
||||
return Collections.unmodifiableSet(new HashSet<>(list));
|
||||
}
|
||||
|
||||
public List<SchematicType> getSchematicTypeList(String path) {
|
||||
List<String> list = getStringList(path);
|
||||
if (list.isEmpty()) {
|
||||
|
||||
@@ -29,6 +29,7 @@ java {
|
||||
dependencies {
|
||||
compileOnly(libs.classindex)
|
||||
annotationProcessor(libs.classindex)
|
||||
compileOnly(project(":GameCore", "default"))
|
||||
compileOnly(project(":SpigotCore", "default"))
|
||||
|
||||
compileOnly(libs.netty)
|
||||
@@ -37,4 +38,5 @@ dependencies {
|
||||
compileOnly(libs.authlib)
|
||||
compileOnly(libs.nms)
|
||||
compileOnly(libs.fawe)
|
||||
compileOnly(libs.datafixer)
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@ Arena:
|
||||
AllowMissiles: false # defaults to true if EnterStages are present otherwise 'false'
|
||||
# Denotes that there is no floor for this GameMode
|
||||
NoFloor: false # defaults to false if missing
|
||||
# Allows Wind Charges to cross the Middle.
|
||||
WindchargesCanCrossMiddle: false # defaults to false if missing
|
||||
# Allows Wind Charge interaction with Blocks.
|
||||
WindchargesInteractWithBlocks: false # defaults to false if missing
|
||||
|
||||
Schematic:
|
||||
# The size of the schematics
|
||||
|
||||
@@ -1,56 +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.fightsystem;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
public enum ArenaMode {
|
||||
NORMAL,
|
||||
EVENT,
|
||||
TEST,
|
||||
CHECK,
|
||||
PREPARE,
|
||||
REPLAY;
|
||||
|
||||
public static final Set<ArenaMode> All = Collections.unmodifiableSet(EnumSet.allOf(ArenaMode.class));
|
||||
|
||||
public static final Set<ArenaMode> Normal = Collections.unmodifiableSet(EnumSet.of(NORMAL));
|
||||
public static final Set<ArenaMode> Check = Collections.unmodifiableSet(EnumSet.of(CHECK));
|
||||
public static final Set<ArenaMode> Event = Collections.unmodifiableSet(EnumSet.of(EVENT));
|
||||
public static final Set<ArenaMode> Test = Collections.unmodifiableSet(EnumSet.of(TEST, CHECK));
|
||||
public static final Set<ArenaMode> Prepare = Collections.unmodifiableSet(EnumSet.of(PREPARE));
|
||||
public static final Set<ArenaMode> Replay = Collections.unmodifiableSet(EnumSet.of(REPLAY, TEST));
|
||||
|
||||
public static final Set<ArenaMode> AntiReplay = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(REPLAY)));
|
||||
public static final Set<ArenaMode> AntiTest = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK)));
|
||||
public static final Set<ArenaMode> AntiEvent = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(EVENT)));
|
||||
public static final Set<ArenaMode> AntiTestCheckPrepare = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK, PREPARE)));
|
||||
public static final Set<ArenaMode> AntiPrepare = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(PREPARE)));
|
||||
public static final Set<ArenaMode> VariableTeams = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(EVENT, REPLAY, CHECK)));
|
||||
public static final Set<ArenaMode> ManualTeams = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(EVENT, REPLAY)));
|
||||
public static final Set<ArenaMode> RankedEvent = Collections.unmodifiableSet(EnumSet.of(EVENT, REPLAY));
|
||||
public static final Set<ArenaMode> Restartable = Collections.unmodifiableSet(EnumSet.of(NORMAL, TEST));
|
||||
public static final Set<ArenaMode> NotRestartable = Collections.unmodifiableSet(EnumSet.of(EVENT, REPLAY));
|
||||
public static final Set<ArenaMode> SoloLeader = Collections.unmodifiableSet(EnumSet.of(TEST, CHECK, PREPARE));
|
||||
public static final Set<ArenaMode> NotOnBau = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK, PREPARE, REPLAY)));
|
||||
public static final Set<ArenaMode> SeriousFight = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK, REPLAY)));
|
||||
}
|
||||
@@ -22,6 +22,7 @@ package de.steamwar.fightsystem;
|
||||
import de.steamwar.data.GameModeConfigUtils;
|
||||
import de.steamwar.fightsystem.utils.Region;
|
||||
import de.steamwar.fightsystem.winconditions.Winconditions;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.sql.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@@ -35,7 +36,6 @@ import org.bukkit.util.Vector;
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class Config {
|
||||
@@ -75,8 +75,6 @@ public class Config {
|
||||
public static final String TeamBlueName;
|
||||
public static final String TeamRedColor;
|
||||
public static final String TeamBlueColor;
|
||||
public static final UUID BlueLeader;
|
||||
public static final UUID RedLeader;
|
||||
|
||||
//event parameter
|
||||
public static final EventFight EventKampf;
|
||||
@@ -87,23 +85,12 @@ public class Config {
|
||||
public static final int MaximumTeamMembers;
|
||||
public static final boolean LiveReplay;
|
||||
|
||||
//check parameter
|
||||
public static final int CheckSchemID;
|
||||
public static final int PrepareSchemID;
|
||||
|
||||
public static final ArenaMode mode;
|
||||
|
||||
//replay system parameter
|
||||
public static final String spectateIP = "127.0.0.1";
|
||||
public static final int SpectatePort;
|
||||
public static final int ReplayID;
|
||||
|
||||
static {
|
||||
CheckSchemID = Integer.parseInt(System.getProperty("checkSchemID", "0"));
|
||||
PrepareSchemID = Integer.parseInt(System.getProperty("prepareSchemID", "0"));
|
||||
ReplayID = Integer.parseInt(System.getProperty("replay", "0"));
|
||||
|
||||
String configFile = System.getProperty("config", "config.yml");
|
||||
String configFile = GameConfig.ConfigFile;
|
||||
if (!new File(FightSystem.getPlugin().getDataFolder(), configFile).exists()) {
|
||||
FightSystem.getPlugin().saveDefaultConfig();
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Arenaconfig fehlt!");
|
||||
@@ -209,7 +196,7 @@ public class Config {
|
||||
|
||||
BlueInsetRegion = new Region(BluePasteRegion.getMinX() + GameModeConfig.Schematic.Inset.x, BluePasteRegion.getMinY() + GameModeConfig.Schematic.Inset.bottom, BluePasteRegion.getMinZ() + GameModeConfig.Schematic.Inset.z, BluePasteRegion.getMaxX() - GameModeConfig.Schematic.Inset.x, BluePasteRegion.getMaxY() - GameModeConfig.Schematic.Inset.top, BluePasteRegion.getMaxZ() - GameModeConfig.Schematic.Inset.z);
|
||||
|
||||
int eventKampfID = Integer.parseInt(System.getProperty("fightID", "0"));
|
||||
int eventKampfID = GameConfig.EventKampfID;
|
||||
if (eventKampfID >= 1) {
|
||||
EventKampf = EventFight.byId(eventKampfID);
|
||||
if (EventKampf == null) {
|
||||
@@ -261,43 +248,8 @@ public class Config {
|
||||
Referees = Collections.emptySet();
|
||||
MaximumTeamMembers = Integer.MAX_VALUE;
|
||||
LiveReplay = false;
|
||||
SpectatePort = -ReplayID;
|
||||
SpectatePort = -GameConfig.ReplayID;
|
||||
}
|
||||
|
||||
String blueLeader = System.getProperty("blueLeader", null);
|
||||
String redLeader = System.getProperty("redLeader", null);
|
||||
if (blueLeader != null) {
|
||||
BlueLeader = UUID.fromString(blueLeader);
|
||||
} else {
|
||||
BlueLeader = null;
|
||||
}
|
||||
if (redLeader != null) {
|
||||
RedLeader = UUID.fromString(redLeader);
|
||||
} else {
|
||||
RedLeader = null;
|
||||
}
|
||||
|
||||
if (CheckSchemID != 0) {
|
||||
mode = ArenaMode.CHECK;
|
||||
} else if (PrepareSchemID != 0) {
|
||||
mode = ArenaMode.PREPARE;
|
||||
} else if (eventKampfID >= 1) {
|
||||
mode = ArenaMode.EVENT;
|
||||
} else if (eventKampfID == -1) {
|
||||
mode = ArenaMode.TEST;
|
||||
} else if (ReplayID != 0) {
|
||||
mode = ArenaMode.REPLAY;
|
||||
} else {
|
||||
mode = ArenaMode.NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean test() {
|
||||
return ArenaMode.Test.contains(mode);
|
||||
}
|
||||
|
||||
public static boolean replayserver() {
|
||||
return ReplayID < 0;
|
||||
}
|
||||
|
||||
public static boolean blueNegZ() {
|
||||
|
||||
@@ -32,7 +32,12 @@ import de.steamwar.fightsystem.record.GlobalRecorder;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.OneShotStateDependent;
|
||||
import de.steamwar.fightsystem.states.StateDependentListener;
|
||||
import de.steamwar.fightsystem.utils.*;
|
||||
import de.steamwar.fightsystem.utils.FightUI;
|
||||
import de.steamwar.fightsystem.utils.HullHider;
|
||||
import de.steamwar.fightsystem.utils.SWSound;
|
||||
import de.steamwar.fightsystem.utils.TechHiderWrapper;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.linkage.AbstractLinker;
|
||||
import de.steamwar.linkage.SpigotLinker;
|
||||
import de.steamwar.message.Message;
|
||||
@@ -41,6 +46,9 @@ import de.steamwar.sql.SchematicNode;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerPickupArrowEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class FightSystem extends JavaPlugin {
|
||||
@@ -69,7 +77,7 @@ public class FightSystem extends JavaPlugin {
|
||||
}
|
||||
if (Config.SpectatePort != 0) {
|
||||
Core.setServerName("Spectate");
|
||||
} else if (Config.ReplayID != 0) {
|
||||
} else if (GameConfig.ReplayID != 0) {
|
||||
Core.setServerName("Replay");
|
||||
}
|
||||
|
||||
@@ -95,20 +103,27 @@ public class FightSystem extends JavaPlugin {
|
||||
getMessage().broadcast("PISTON_PUSHED_OUTSIDE");
|
||||
shutdown();
|
||||
});
|
||||
new StateDependentListener(ArenaMode.All, FightState.All, BountifulWrapper.impl.newDenyArrowPickupListener());
|
||||
new StateDependentListener(ArenaMode.All, FightState.All, new Listener() {
|
||||
@EventHandler
|
||||
public void onArrowPickup(PlayerPickupArrowEvent e) {
|
||||
if (Fight.fighting(e.getPlayer())) e.setCancelled(true);
|
||||
}
|
||||
});
|
||||
new OneShotStateDependent(ArenaMode.All, FightState.PreSchemSetup, () -> Fight.playSound(SWSound.BLOCK_NOTE_PLING.getSound(), 100.0f, 2.0f));
|
||||
new OneShotStateDependent(ArenaMode.Test, FightState.All, WorldEditRendererCUIEditor::new);
|
||||
Config.world.setGameRule(GameRule.REDUCED_DEBUG_INFO, ArenaMode.AntiTest.contains(Config.mode));
|
||||
Config.world.setGameRule(GameRule.REDUCED_DEBUG_INFO, ArenaMode.AntiTest.contains(GameConfig.mode));
|
||||
|
||||
techHider = new TechHiderWrapper();
|
||||
hullHider = new HullHider();
|
||||
techHider = new TechHiderWrapper(hullHider);
|
||||
FightSystem.getHullHider().getHullMap().values().forEach(hull -> hull.fill(true));
|
||||
|
||||
|
||||
FileSource.startReplay();
|
||||
|
||||
if (Config.mode == ArenaMode.EVENT) {
|
||||
if (GameConfig.mode == ArenaMode.EVENT) {
|
||||
FightState.setFightState(FightState.PRE_SCHEM_SETUP);
|
||||
} else if (Config.mode == ArenaMode.CHECK) {
|
||||
SchematicNode checkSchematicNode = SchematicNode.getSchematicNode(Config.CheckSchemID);
|
||||
} else if (GameConfig.mode == ArenaMode.CHECK) {
|
||||
SchematicNode checkSchematicNode = SchematicNode.getSchematicNode(GameConfig.CheckSchemID);
|
||||
Fight.getBlueTeam().setSchem(checkSchematicNode);
|
||||
|
||||
if (checkSchematicNode.isPrepared()) {
|
||||
@@ -116,11 +131,11 @@ public class FightSystem extends JavaPlugin {
|
||||
}
|
||||
|
||||
new TechareaCommand();
|
||||
} else if (Config.mode == ArenaMode.PREPARE) {
|
||||
Fight.getUnrotated().setSchem(SchematicNode.getSchematicNode(Config.PrepareSchemID));
|
||||
} else if (GameConfig.mode == ArenaMode.PREPARE) {
|
||||
Fight.getUnrotated().setSchem(SchematicNode.getSchematicNode(GameConfig.PrepareSchemID));
|
||||
}
|
||||
|
||||
CraftbukkitWrapper.impl.setupGamerule();
|
||||
Config.world.setGameRule(GameRule.LOCATOR_BAR, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
package de.steamwar.fightsystem.ai;
|
||||
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
package de.steamwar.fightsystem.ai;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.fightsystem.fight.FightTeam;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
@@ -35,7 +35,7 @@ import java.util.stream.Collectors;
|
||||
@AllArgsConstructor
|
||||
public class AIManager {
|
||||
private static final List<AIManager> AIs = Arrays.asList(
|
||||
new AIManager("DummyAI", DummyAI::new, Material.STONE, () -> ArenaMode.Test.contains(Config.mode))
|
||||
new AIManager("DummyAI", DummyAI::new, Material.STONE, () -> ArenaMode.Test.contains(GameConfig.mode))
|
||||
);
|
||||
|
||||
public static List<AIManager> availableAIs() {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.core.Core;
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.fight.Kit;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.ai.AIManager;
|
||||
@@ -56,7 +57,7 @@ public class GUI {
|
||||
inv.setItem(pos, ColorConverter.chat2dye(team.getColor()), msg.parse("JOIN_REQUEST_TEAM", p, team.getColor() + name), click -> {
|
||||
p.closeInventory();
|
||||
|
||||
if (ArenaMode.ManualTeams.contains(Config.mode) && team.canbeLeader(p)) {
|
||||
if (ArenaMode.ManualTeams.contains(GameConfig.mode) && team.canbeLeader(p)) {
|
||||
team.addMember(p);
|
||||
} else {
|
||||
JoinRequest.forPlayer(p, team);
|
||||
@@ -198,7 +199,7 @@ public class GUI {
|
||||
}
|
||||
|
||||
public static void preSchemDialog(Player p) {
|
||||
if (!Config.test() && FightState.getFightState() != FightState.PRE_SCHEM_SETUP) {
|
||||
if (!GameConfig.test() && FightState.getFightState() != FightState.PRE_SCHEM_SETUP) {
|
||||
msg.sendPrefixless("SCHEM_NO_ENEMY", p, ChatMessageType.ACTION_BAR);
|
||||
return;
|
||||
}
|
||||
@@ -209,7 +210,7 @@ public class GUI {
|
||||
for (int i = 0; i < Config.GameModeConfig.Schematic.SubTypes.size(); i++) {
|
||||
setupSchemTypeRow(p, inv, Config.GameModeConfig.Schematic.SubTypes.get(i), i + 1);
|
||||
}
|
||||
if (!Config.test() && SteamwarUser.get(p.getUniqueId()).hasPerm(UserPerm.TEAM)) {
|
||||
if (!GameConfig.test() && SteamwarUser.get(p.getUniqueId()).hasPerm(UserPerm.TEAM)) {
|
||||
SchematicNode node = SchematicNode.getSchematicNode(-1, Config.GameModeConfig.GameName, (Integer) null);
|
||||
if (node != null) {
|
||||
inv.setItem(2, new SWItem(SWItem.getMaterial(node.getItem()), msg.parse("SCHEM_DIRT", p), click -> {
|
||||
@@ -233,14 +234,14 @@ public class GUI {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type.checkType() != null && type.checkType() != type && ArenaMode.AntiEvent.contains(Config.mode) && !SchematicNode.getAllAccessibleSchematicsOfType(SteamwarUser.get(p.getUniqueId()).getId(), type.checkType().toDB()).isEmpty()) {
|
||||
if (type.checkType() != null && type.checkType() != type && ArenaMode.AntiEvent.contains(GameConfig.mode) && !SchematicNode.getAllAccessibleSchematicsOfType(SteamwarUser.get(p.getUniqueId()).getId(), type.checkType().toDB()).isEmpty()) {
|
||||
inv.setItem(row * 9 + 4, Material.ANVIL, msg.parse("SCHEM_UNCHECKED", p, type.name()), (ClickType click) -> {
|
||||
p.closeInventory();
|
||||
schemDialog(p, type, false, true);
|
||||
});
|
||||
}
|
||||
|
||||
if (SchematicNode.getAllAccessibleSchematicsOfType(SteamwarUser.get(p.getUniqueId()).getId(), type.toDB()).isEmpty() && !Config.test()) {
|
||||
if (SchematicNode.getAllAccessibleSchematicsOfType(SteamwarUser.get(p.getUniqueId()).getId(), type.toDB()).isEmpty() && !GameConfig.test()) {
|
||||
inv.setItem(row * 9, Material.GRAY_DYE, (byte) 8, msg.parse("SCHEM_NO_PRIVATE", p, type.name()), (ClickType click) -> {
|
||||
});
|
||||
return;
|
||||
@@ -253,7 +254,7 @@ public class GUI {
|
||||
}
|
||||
|
||||
private static void schemDialog(Player p, SchematicType type, boolean publicSchems, boolean unchecked) {
|
||||
SchematicSelector selector = new SchematicSelector(p, Config.test() ? SchematicSelector.selectSchematic() : SchematicSelector.selectSchematicType(unchecked ? type.checkType() : type), node -> {
|
||||
SchematicSelector selector = new SchematicSelector(p, GameConfig.test() ? SchematicSelector.selectSchematic() : SchematicSelector.selectSchematicType(unchecked ? type.checkType() : type), node -> {
|
||||
schemSelect(p, node);
|
||||
});
|
||||
selector.setPublicMode(publicSchems ? SchematicSelector.PublicMode.PUBLIC_ONLY : SchematicSelector.PublicMode.PRIVATE_ONLY);
|
||||
@@ -263,7 +264,7 @@ public class GUI {
|
||||
private static void schemSelect(Player p, SchematicNode node) {
|
||||
FightTeam fightTeam = Fight.getPlayerTeam(p);
|
||||
if (fightTeam == null) return;
|
||||
if (Config.test() || FightState.getFightState() != FightState.POST_SCHEM_SETUP) {
|
||||
if (GameConfig.test() || FightState.getFightState() != FightState.POST_SCHEM_SETUP) {
|
||||
fightTeam.pasteSchem(node);
|
||||
}
|
||||
p.closeInventory();
|
||||
|
||||
+2
-1
@@ -22,6 +22,7 @@ package de.steamwar.fightsystem.commands;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -65,7 +66,7 @@ public class GamemodeCommand extends BukkitCommand {
|
||||
|
||||
Player p = (Player) sender;
|
||||
|
||||
if (!(Config.test() || Config.isReferee(p))) {
|
||||
if (!(GameConfig.test() || Config.isReferee(p))) {
|
||||
FightSystem.getMessage().sendPrefixless("GAMEMODE_NOT_ALLOWED", p, ChatMessageType.ACTION_BAR);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
import de.steamwar.fightsystem.fight.FightTeam;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCommand;
|
||||
import de.steamwar.linkage.Linked;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCommand;
|
||||
import de.steamwar.linkage.Linked;
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
import de.steamwar.fightsystem.fight.FightTeam;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCommand;
|
||||
import de.steamwar.linkage.Linked;
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCommand;
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
import de.steamwar.fightsystem.fight.FightPlayer;
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
import de.steamwar.fightsystem.record.PacketProcessor;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
@@ -35,7 +35,7 @@ import org.bukkit.entity.Player;
|
||||
public class SkipCommand implements CommandExecutor {
|
||||
|
||||
public SkipCommand() {
|
||||
new StateDependentCommand(ArenaMode.AntiPrepare, ArenaMode.Replay.contains(Config.mode) ? FightState.All : FightState.TeamFix, "skip", this);
|
||||
new StateDependentCommand(ArenaMode.AntiPrepare, ArenaMode.Replay.contains(GameConfig.mode) ? FightState.All : FightState.TeamFix, "skip", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCommand;
|
||||
import de.steamwar.linkage.Linked;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCommand;
|
||||
|
||||
+3
-4
@@ -17,12 +17,12 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCommand;
|
||||
import de.steamwar.fightsystem.utils.TpsWarper;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -45,8 +45,7 @@ public class TPSWarpCommand implements CommandExecutor {
|
||||
return false;
|
||||
}
|
||||
|
||||
TpsWarper warper = TpsWarper.impl;
|
||||
warper.warp(tps);
|
||||
MinecraftServer.getServer().tickRateManager().setTickRate(tps);
|
||||
|
||||
FightSystem.getMessage().broadcastActionbar("TPSWARP_SET", tps);
|
||||
return false;
|
||||
|
||||
+3
-2
@@ -20,7 +20,8 @@
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
@@ -49,7 +50,7 @@ public class TechhiderbugCommand implements CommandExecutor {
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
try {
|
||||
writer.append("ArenaMode: ").append(Config.mode.name()).append('\n');
|
||||
writer.append("ArenaMode: ").append(GameConfig.mode.name()).append('\n');
|
||||
writer.append("FightState: ").append(FightState.getFightState().name()).append('\n');
|
||||
writer.append("TechHider enabled: ").append(FightState.getStateDependentFeatures().get(FightSystem.getTechHider()).toString()).append('\n');
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
import de.steamwar.fightsystem.fight.FightWorld;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package de.steamwar.fightsystem.commands;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
|
||||
@@ -1,151 +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.fightsystem.countdown;
|
||||
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
import de.steamwar.fightsystem.record.GlobalRecorder;
|
||||
import de.steamwar.fightsystem.utils.FightUI;
|
||||
import de.steamwar.fightsystem.utils.Message;
|
||||
import de.steamwar.fightsystem.utils.SWSound;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class Countdown {
|
||||
|
||||
private static final List<Countdown> currentCountdowns = new ArrayList<>();
|
||||
|
||||
protected final Message appendix;
|
||||
|
||||
private final int totalTime;
|
||||
protected final Sound sound;
|
||||
private final boolean level;
|
||||
|
||||
protected int time;
|
||||
private BukkitTask task = null;
|
||||
|
||||
public abstract void countdownFinished();
|
||||
|
||||
protected Countdown(int time, Message appendix, SWSound sound, boolean level) {
|
||||
this.totalTime = time;
|
||||
this.time = time;
|
||||
this.appendix = appendix;
|
||||
this.sound = sound != null ? sound.getSound() : null;
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
time = totalTime;
|
||||
task = Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), this::count, 20, 20);
|
||||
currentCountdowns.add(this);
|
||||
show();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
currentCountdowns.remove(this);
|
||||
task = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void skip() {
|
||||
if (currentCountdowns.isEmpty()) return;
|
||||
|
||||
int smallestTime = currentCountdowns.get(0).time;
|
||||
for (Countdown countdown : currentCountdowns) {
|
||||
if (countdown.time < smallestTime) smallestTime = countdown.time;
|
||||
}
|
||||
|
||||
for (Countdown countdown : new ArrayList<>(currentCountdowns)) {
|
||||
countdown.time -= smallestTime;
|
||||
countdown.show();
|
||||
}
|
||||
|
||||
FightUI.addSubtitle("UI_SKIP");
|
||||
}
|
||||
|
||||
public static void sendCountdownMessage(Player p, String message, int displaytime, Message appendix) {
|
||||
FightSystem.getMessage().sendPrefixless(message, p, ChatMessageType.ACTION_BAR, displaytime, FightSystem.getMessage().parse(appendix.getMsg(), p, appendix.getParams()));
|
||||
}
|
||||
|
||||
protected void broadcast(String message, int divisor) {
|
||||
if (this.sound != null && divisor == 1) {
|
||||
Fight.playSound(this.sound, 100.0F, 1.0F);
|
||||
}
|
||||
|
||||
GlobalRecorder.getInstance().countdown(message, time / divisor, appendix);
|
||||
Bukkit.getOnlinePlayers().forEach(p -> sendCountdownMessage(p, message, time / divisor, appendix));
|
||||
}
|
||||
|
||||
public int getTimeLeft() {
|
||||
return time;
|
||||
}
|
||||
|
||||
private void count() {
|
||||
time--;
|
||||
show();
|
||||
}
|
||||
|
||||
private void show() {
|
||||
switch (time) {
|
||||
case 900:
|
||||
case 600:
|
||||
case 300:
|
||||
case 180:
|
||||
case 120:
|
||||
broadcast("COUNTDOWN_MINUTES", 60);
|
||||
break;
|
||||
case 60:
|
||||
case 30:
|
||||
case 20:
|
||||
case 15:
|
||||
case 10:
|
||||
case 5:
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
broadcast("COUNTDOWN_SECONDS", 1);
|
||||
break;
|
||||
case 1:
|
||||
broadcast("COUNTDOWN_SECOND", 1);
|
||||
break;
|
||||
case 0:
|
||||
if (this.sound != null) {
|
||||
Fight.playSound(this.sound, 100.0F, 2.0F);
|
||||
}
|
||||
|
||||
disable();
|
||||
countdownFinished();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
if (this.level) {
|
||||
Bukkit.getServer().getOnlinePlayers().forEach(player -> player.setLevel(time));
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-14
@@ -27,13 +27,12 @@ import de.steamwar.fightsystem.fight.FightPlayer;
|
||||
import de.steamwar.fightsystem.utils.Message;
|
||||
import de.steamwar.fightsystem.utils.Region;
|
||||
import de.steamwar.fightsystem.utils.SWSound;
|
||||
import de.steamwar.techhider.ProtocolUtils;
|
||||
import de.steamwar.gamecore.countdown.Countdown;
|
||||
import de.steamwar.gamecore.countdown.StandardCountdown;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EnternCountdown extends Countdown {
|
||||
public class EnternCountdown extends StandardCountdown {
|
||||
|
||||
private static int calcTime(FightPlayer fp, Countdown countdown) {
|
||||
int time = Config.GameModeConfig.EnterStages.get(fp.getKit().getEnterStage());
|
||||
@@ -47,16 +46,19 @@ public class EnternCountdown extends Countdown {
|
||||
}
|
||||
|
||||
private final FightPlayer fightPlayer;
|
||||
private List<ProtocolUtils.ChunkPos> chunkPos;
|
||||
|
||||
public EnternCountdown(FightPlayer fp, Countdown countdown) {
|
||||
super(calcTime(fp, countdown), new Message("ENTERN_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, false);
|
||||
super(
|
||||
FightSystem.getPlugin(),
|
||||
calcTime(fp, countdown),
|
||||
FightCountdownAdapter.playerPresentation(fp, new Message("ENTERN_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING)
|
||||
);
|
||||
fightPlayer = fp;
|
||||
enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void countdownFinished() {
|
||||
protected void countdownFinished() {
|
||||
Bukkit.getPluginManager().callEvent(new BoardingEvent(fightPlayer));
|
||||
FightSystem.getMessage().sendPrefixless("ENTERN_ALLOWED", fightPlayer.getEntity(), ChatMessageType.ACTION_BAR);
|
||||
fightPlayer.ifPlayer(player -> {
|
||||
@@ -65,11 +67,4 @@ public class EnternCountdown extends Countdown {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void broadcast(String message, int divisor) {
|
||||
fightPlayer.ifPlayer(player -> {
|
||||
player.playSound(player.getLocation(), sound, 100.0f, 1.0f);
|
||||
sendCountdownMessage(player, message, time / divisor, appendix);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+8
-6
@@ -19,25 +19,27 @@
|
||||
|
||||
package de.steamwar.fightsystem.countdown;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.gamecore.countdown.StandardCountdown;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCountdown;
|
||||
import de.steamwar.gamecore.state.StateDependentCountdown;
|
||||
import de.steamwar.fightsystem.utils.Message;
|
||||
import de.steamwar.fightsystem.utils.SWSound;
|
||||
import de.steamwar.linkage.Linked;
|
||||
|
||||
@Linked
|
||||
public class EventSpectateCountdown extends Countdown {
|
||||
public class EventSpectateCountdown extends StandardCountdown {
|
||||
|
||||
public EventSpectateCountdown() {
|
||||
super(Config.GameModeConfig.Times.SpectatorDuration, new Message("SHUTDOWN_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, false);
|
||||
new StateDependentCountdown(ArenaMode.NotRestartable.contains(Config.mode) && !Config.replayserver(), FightState.Spectate, this);
|
||||
super(FightSystem.getPlugin(), Config.GameModeConfig.Times.SpectatorDuration, FightCountdownAdapter.presentation(new Message("SHUTDOWN_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, false));
|
||||
new StateDependentCountdown<>(FightState.lifecycle, ArenaMode.NotRestartable.contains(GameConfig.mode) && !GameConfig.replayserver(), FightState.Spectate, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void countdownFinished() {
|
||||
protected void countdownFinished() {
|
||||
FightSystem.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package de.steamwar.fightsystem.countdown;
|
||||
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
import de.steamwar.fightsystem.fight.FightPlayer;
|
||||
import de.steamwar.fightsystem.record.GlobalRecorder;
|
||||
import de.steamwar.fightsystem.utils.Message;
|
||||
import de.steamwar.fightsystem.utils.SWSound;
|
||||
import de.steamwar.gamecore.countdown.CountdownMessageSink;
|
||||
import de.steamwar.gamecore.countdown.CountdownPresentation;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* Binds FightSystem's transports to GameCore's presentation engine.
|
||||
*/
|
||||
public final class FightCountdownAdapter {
|
||||
private FightCountdownAdapter() {
|
||||
}
|
||||
|
||||
public static CountdownPresentation presentation(Message appendix, SWSound sound, boolean level) {
|
||||
return presentation(
|
||||
appendix,
|
||||
sound,
|
||||
level,
|
||||
(message, displayTime) -> {
|
||||
GlobalRecorder.getInstance().countdown(message.getKey(), displayTime, appendix);
|
||||
Bukkit.getOnlinePlayers().forEach(player ->
|
||||
sendCountdownMessage(player, message.getKey(), displayTime, appendix)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static CountdownPresentation presentation(
|
||||
Message appendix,
|
||||
SWSound sound,
|
||||
boolean level,
|
||||
CountdownMessageSink messageSink
|
||||
) {
|
||||
return new CountdownPresentation(
|
||||
messageSink,
|
||||
sound != null
|
||||
? pitch -> Fight.playSound(sound.getSound(), 100.0F, pitch)
|
||||
: null,
|
||||
level
|
||||
? timeLeft -> Bukkit.getOnlinePlayers().forEach(player -> player.setLevel(timeLeft))
|
||||
: null
|
||||
);
|
||||
}
|
||||
|
||||
public static CountdownPresentation playerPresentation(
|
||||
FightPlayer fightPlayer,
|
||||
Message appendix,
|
||||
SWSound sound
|
||||
) {
|
||||
return new CountdownPresentation(
|
||||
(message, displayTime) -> fightPlayer.ifPlayer(player ->
|
||||
sendCountdownMessage(player, message.getKey(), displayTime, appendix)
|
||||
),
|
||||
pitch -> fightPlayer.ifPlayer(player ->
|
||||
player.playSound(player.getLocation(), sound.getSound(), 100.0F, pitch)
|
||||
),
|
||||
pitch -> Fight.playSound(sound.getSound(), 100.0F, pitch),
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
public static void sendCountdownMessage(Player player, String message, int displayTime, Message appendix) {
|
||||
FightSystem.getMessage().sendPrefixless(
|
||||
message,
|
||||
player,
|
||||
ChatMessageType.ACTION_BAR,
|
||||
displayTime,
|
||||
FightSystem.getMessage().parse(appendix.getMsg(), player, appendix.getParams())
|
||||
);
|
||||
}
|
||||
}
|
||||
+9
-6
@@ -19,27 +19,30 @@
|
||||
|
||||
package de.steamwar.fightsystem.countdown;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCountdown;
|
||||
import de.steamwar.gamecore.state.StateDependentCountdown;
|
||||
import de.steamwar.fightsystem.utils.Message;
|
||||
import de.steamwar.gamecore.countdown.StandardCountdown;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
@Linked
|
||||
public class NoPlayersOnlineCountdown extends Countdown {
|
||||
public class NoPlayersOnlineCountdown extends StandardCountdown {
|
||||
|
||||
public NoPlayersOnlineCountdown() {
|
||||
super(Config.GameModeConfig.Times.NoPlayersOnlineDuration, new Message("SHUTDOWN_COUNTDOWN"), null, false);
|
||||
super(FightSystem.getPlugin(), Config.GameModeConfig.Times.NoPlayersOnlineDuration, FightCountdownAdapter.presentation(new Message("SHUTDOWN_COUNTDOWN"), null, false));
|
||||
|
||||
if (!Config.GameModeConfig.Arena.Leaveable) {
|
||||
new StateDependentCountdown(ArenaMode.AntiReplay, FightState.PreLeaderSetup, this);
|
||||
new StateDependentCountdown<>(FightState.lifecycle, ArenaMode.AntiReplay.contains(GameConfig.mode), FightState.PreLeaderSetup, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void countdownFinished() {
|
||||
protected void countdownFinished() {
|
||||
Bukkit.getServer().shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
+10
-7
@@ -19,27 +19,30 @@
|
||||
|
||||
package de.steamwar.fightsystem.countdown;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCountdown;
|
||||
import de.steamwar.gamecore.state.StateDependentCountdown;
|
||||
import de.steamwar.fightsystem.utils.Message;
|
||||
import de.steamwar.gamecore.countdown.StandardCountdown;
|
||||
import de.steamwar.linkage.Linked;
|
||||
|
||||
@Linked
|
||||
public class PostSchemCountdown extends Countdown {
|
||||
public class PostSchemCountdown extends StandardCountdown {
|
||||
|
||||
public PostSchemCountdown() {
|
||||
super(Config.GameModeConfig.Times.SetupDuration, new Message("POST_SCHEM_COUNTDOWN"), null, false);
|
||||
if (Config.mode == ArenaMode.PREPARE && Config.GameModeConfig.Schematic.UnlimitedPrepare) {
|
||||
super(FightSystem.getPlugin(), Config.GameModeConfig.Times.SetupDuration, FightCountdownAdapter.presentation(new Message("POST_SCHEM_COUNTDOWN"), null, false));
|
||||
if (GameConfig.mode == ArenaMode.PREPARE && Config.GameModeConfig.Schematic.UnlimitedPrepare) {
|
||||
return;
|
||||
}
|
||||
|
||||
new StateDependentCountdown(ArenaMode.SeriousFight, FightState.PostSchemSetup, this);
|
||||
new StateDependentCountdown<>(FightState.lifecycle, ArenaMode.SeriousFight.contains(GameConfig.mode), FightState.PostSchemSetup, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void countdownFinished() {
|
||||
protected void countdownFinished() {
|
||||
FightState.setFightState(FightState.PRE_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-6
@@ -19,24 +19,27 @@
|
||||
|
||||
package de.steamwar.fightsystem.countdown;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCountdown;
|
||||
import de.steamwar.gamecore.state.StateDependentCountdown;
|
||||
import de.steamwar.fightsystem.utils.Message;
|
||||
import de.steamwar.fightsystem.utils.SWSound;
|
||||
import de.steamwar.gamecore.countdown.StandardCountdown;
|
||||
import de.steamwar.linkage.Linked;
|
||||
|
||||
@Linked
|
||||
public class PreRunningCountdown extends Countdown {
|
||||
public class PreRunningCountdown extends StandardCountdown {
|
||||
|
||||
public PreRunningCountdown() {
|
||||
super(Config.GameModeConfig.Times.PreFightDuration, new Message("PRE_RUNNING_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, true);
|
||||
new StateDependentCountdown(ArenaMode.AntiReplay, FightState.PreRunning, this);
|
||||
super(FightSystem.getPlugin(), Config.GameModeConfig.Times.PreFightDuration, FightCountdownAdapter.presentation(new Message("PRE_RUNNING_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, true));
|
||||
new StateDependentCountdown<>(FightState.lifecycle, ArenaMode.AntiReplay.contains(GameConfig.mode), FightState.PreRunning, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void countdownFinished() {
|
||||
protected void countdownFinished() {
|
||||
FightState.setFightState(FightState.RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-6
@@ -19,24 +19,27 @@
|
||||
|
||||
package de.steamwar.fightsystem.countdown;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCountdown;
|
||||
import de.steamwar.gamecore.state.StateDependentCountdown;
|
||||
import de.steamwar.fightsystem.utils.Message;
|
||||
import de.steamwar.fightsystem.utils.SWSound;
|
||||
import de.steamwar.gamecore.countdown.StandardCountdown;
|
||||
import de.steamwar.linkage.Linked;
|
||||
|
||||
@Linked
|
||||
public class PreSchemCountdown extends Countdown {
|
||||
public class PreSchemCountdown extends StandardCountdown {
|
||||
|
||||
public PreSchemCountdown() {
|
||||
super(Config.GameModeConfig.Times.PreSchemPasteDuration, new Message("PRE_SCHEM_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, false);
|
||||
new StateDependentCountdown(ArenaMode.AntiReplay, FightState.PreSchemSetup, this);
|
||||
super(FightSystem.getPlugin(), Config.GameModeConfig.Times.PreSchemPasteDuration, FightCountdownAdapter.presentation(new Message("PRE_SCHEM_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, false));
|
||||
new StateDependentCountdown<>(FightState.lifecycle, ArenaMode.AntiReplay.contains(GameConfig.mode), FightState.PreSchemSetup, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void countdownFinished() {
|
||||
protected void countdownFinished() {
|
||||
FightState.setFightState(FightState.POST_SCHEM_SETUP);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-6
@@ -19,24 +19,27 @@
|
||||
|
||||
package de.steamwar.fightsystem.countdown;
|
||||
|
||||
import de.steamwar.fightsystem.ArenaMode;
|
||||
import de.steamwar.gamecore.ArenaMode;
|
||||
import de.steamwar.gamecore.GameConfig;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.states.FightState;
|
||||
import de.steamwar.fightsystem.states.StateDependentCountdown;
|
||||
import de.steamwar.gamecore.state.StateDependentCountdown;
|
||||
import de.steamwar.fightsystem.utils.Message;
|
||||
import de.steamwar.fightsystem.utils.SWSound;
|
||||
import de.steamwar.gamecore.countdown.StandardCountdown;
|
||||
import de.steamwar.linkage.Linked;
|
||||
|
||||
@Linked
|
||||
public class SpectateOverCountdown extends Countdown {
|
||||
public class SpectateOverCountdown extends StandardCountdown {
|
||||
|
||||
public SpectateOverCountdown() {
|
||||
super(Config.test() ? 3600 : Config.GameModeConfig.Times.SpectatorDuration, new Message("SPECTATE_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, false);
|
||||
new StateDependentCountdown(ArenaMode.Restartable.contains(Config.mode) || Config.replayserver(), FightState.Spectate, this);
|
||||
super(FightSystem.getPlugin(), GameConfig.test() ? 3600 : Config.GameModeConfig.Times.SpectatorDuration, FightCountdownAdapter.presentation(new Message("SPECTATE_COUNTDOWN"), SWSound.BLOCK_NOTE_PLING, false));
|
||||
new StateDependentCountdown<>(FightState.lifecycle, ArenaMode.Restartable.contains(GameConfig.mode) || GameConfig.replayserver(), FightState.Spectate, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void countdownFinished() {
|
||||
protected void countdownFinished() {
|
||||
FightState.setFightState(FightState.PRE_LEADER_SETUP);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user