feat: working block implementation
This commit is contained in:
parent
23981fb9ca
commit
802bbb6c7b
31 changed files with 1580 additions and 51 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -19,3 +19,5 @@ hs_err_pid*
|
||||||
|
|
||||||
# Common working directory
|
# Common working directory
|
||||||
run
|
run
|
||||||
|
/src/generated/resources/.cache/
|
||||||
|
/repo/
|
||||||
|
|
|
||||||
71
.kotlin/errors/errors-1775391978696.log
Normal file
71
.kotlin/errors/errors-1775391978696.log
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
kotlin version: 2.0.0
|
||||||
|
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 1. The daemon process output:
|
||||||
|
... (53 more lines)
|
||||||
|
54. at java.base/sun.nio.ch.Net.bind0(Native Method)
|
||||||
|
55. at java.base/sun.nio.ch.Net.bind(Net.java:555)
|
||||||
|
56. at java.base/sun.nio.ch.Net.bind(Net.java:544)
|
||||||
|
57. at java.base/sun.nio.ch.NioSocketImpl.bind(NioSocketImpl.java:640)
|
||||||
|
58. at java.base/java.net.ServerSocket.bind(ServerSocket.java:392)
|
||||||
|
59. at java.base/java.net.ServerSocket.<init>(ServerSocket.java:274)
|
||||||
|
60. at org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface$ServerLoopbackSocketFactory.createServerSocket(NetworkUtils.kt:69)
|
||||||
|
61. at java.rmi/sun.rmi.transport.tcp.TCPEndpoint.newServerSocket(TCPEndpoint.java:673)
|
||||||
|
62. at java.rmi/sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:344)
|
||||||
|
63. ... 14 more
|
||||||
|
|
||||||
|
error message: The daemon has terminated unexpectedly on startup attempt #2 with error code: 1. The daemon process output:
|
||||||
|
... (53 more lines)
|
||||||
|
54. at java.base/sun.nio.ch.Net.bind0(Native Method)
|
||||||
|
55. at java.base/sun.nio.ch.Net.bind(Net.java:555)
|
||||||
|
56. at java.base/sun.nio.ch.Net.bind(Net.java:544)
|
||||||
|
57. at java.base/sun.nio.ch.NioSocketImpl.bind(NioSocketImpl.java:640)
|
||||||
|
58. at java.base/java.net.ServerSocket.bind(ServerSocket.java:392)
|
||||||
|
59. at java.base/java.net.ServerSocket.<init>(ServerSocket.java:274)
|
||||||
|
60. at org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface$ServerLoopbackSocketFactory.createServerSocket(NetworkUtils.kt:69)
|
||||||
|
61. at java.rmi/sun.rmi.transport.tcp.TCPEndpoint.newServerSocket(TCPEndpoint.java:673)
|
||||||
|
62. at java.rmi/sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:344)
|
||||||
|
63. ... 14 more
|
||||||
|
|
||||||
|
error message: Failed connecting to the daemon in 3 retries
|
||||||
|
|
||||||
|
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
|
||||||
|
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:76)
|
||||||
|
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
|
||||||
|
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
|
||||||
|
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
|
||||||
|
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
|
||||||
|
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
|
||||||
|
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174)
|
||||||
|
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:187)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:120)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:162)
|
||||||
|
at org.gradle.internal.Factories$1.create(Factories.java:31)
|
||||||
|
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:264)
|
||||||
|
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:128)
|
||||||
|
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:133)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:157)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:126)
|
||||||
|
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
|
||||||
|
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
|
||||||
|
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
|
||||||
|
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:833)
|
||||||
|
|
||||||
|
|
||||||
71
.kotlin/errors/errors-1775393382933.log
Normal file
71
.kotlin/errors/errors-1775393382933.log
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
kotlin version: 2.0.0
|
||||||
|
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 1. The daemon process output:
|
||||||
|
... (53 more lines)
|
||||||
|
54. at java.base/sun.nio.ch.Net.bind0(Native Method)
|
||||||
|
55. at java.base/sun.nio.ch.Net.bind(Net.java:565)
|
||||||
|
56. at java.base/sun.nio.ch.Net.bind(Net.java:554)
|
||||||
|
57. at java.base/sun.nio.ch.NioSocketImpl.bind(NioSocketImpl.java:636)
|
||||||
|
58. at java.base/java.net.ServerSocket.bind(ServerSocket.java:391)
|
||||||
|
59. at java.base/java.net.ServerSocket.<init>(ServerSocket.java:278)
|
||||||
|
60. at org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface$ServerLoopbackSocketFactory.createServerSocket(NetworkUtils.kt:69)
|
||||||
|
61. at java.rmi/sun.rmi.transport.tcp.TCPEndpoint.newServerSocket(TCPEndpoint.java:672)
|
||||||
|
62. at java.rmi/sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:344)
|
||||||
|
63. ... 14 more
|
||||||
|
|
||||||
|
error message: The daemon has terminated unexpectedly on startup attempt #2 with error code: 1. The daemon process output:
|
||||||
|
... (53 more lines)
|
||||||
|
54. at java.base/sun.nio.ch.Net.bind0(Native Method)
|
||||||
|
55. at java.base/sun.nio.ch.Net.bind(Net.java:565)
|
||||||
|
56. at java.base/sun.nio.ch.Net.bind(Net.java:554)
|
||||||
|
57. at java.base/sun.nio.ch.NioSocketImpl.bind(NioSocketImpl.java:636)
|
||||||
|
58. at java.base/java.net.ServerSocket.bind(ServerSocket.java:391)
|
||||||
|
59. at java.base/java.net.ServerSocket.<init>(ServerSocket.java:278)
|
||||||
|
60. at org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface$ServerLoopbackSocketFactory.createServerSocket(NetworkUtils.kt:69)
|
||||||
|
61. at java.rmi/sun.rmi.transport.tcp.TCPEndpoint.newServerSocket(TCPEndpoint.java:672)
|
||||||
|
62. at java.rmi/sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:344)
|
||||||
|
63. ... 14 more
|
||||||
|
|
||||||
|
error message: Failed connecting to the daemon in 3 retries
|
||||||
|
|
||||||
|
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
|
||||||
|
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:76)
|
||||||
|
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
|
||||||
|
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
|
||||||
|
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
|
||||||
|
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
|
||||||
|
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
|
||||||
|
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174)
|
||||||
|
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:187)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:120)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:162)
|
||||||
|
at org.gradle.internal.Factories$1.create(Factories.java:31)
|
||||||
|
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:264)
|
||||||
|
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:128)
|
||||||
|
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:133)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:157)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:126)
|
||||||
|
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
|
||||||
|
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
|
||||||
|
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
|
||||||
|
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1583)
|
||||||
|
|
||||||
|
|
||||||
71
.kotlin/errors/errors-1775393603849.log
Normal file
71
.kotlin/errors/errors-1775393603849.log
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
kotlin version: 2.0.0
|
||||||
|
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 1. The daemon process output:
|
||||||
|
... (53 more lines)
|
||||||
|
54. at java.base/sun.nio.ch.Net.bind0(Native Method)
|
||||||
|
55. at java.base/sun.nio.ch.Net.bind(Net.java:565)
|
||||||
|
56. at java.base/sun.nio.ch.Net.bind(Net.java:554)
|
||||||
|
57. at java.base/sun.nio.ch.NioSocketImpl.bind(NioSocketImpl.java:636)
|
||||||
|
58. at java.base/java.net.ServerSocket.bind(ServerSocket.java:391)
|
||||||
|
59. at java.base/java.net.ServerSocket.<init>(ServerSocket.java:278)
|
||||||
|
60. at org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface$ServerLoopbackSocketFactory.createServerSocket(NetworkUtils.kt:69)
|
||||||
|
61. at java.rmi/sun.rmi.transport.tcp.TCPEndpoint.newServerSocket(TCPEndpoint.java:672)
|
||||||
|
62. at java.rmi/sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:344)
|
||||||
|
63. ... 14 more
|
||||||
|
|
||||||
|
error message: The daemon has terminated unexpectedly on startup attempt #2 with error code: 1. The daemon process output:
|
||||||
|
... (53 more lines)
|
||||||
|
54. at java.base/sun.nio.ch.Net.bind0(Native Method)
|
||||||
|
55. at java.base/sun.nio.ch.Net.bind(Net.java:565)
|
||||||
|
56. at java.base/sun.nio.ch.Net.bind(Net.java:554)
|
||||||
|
57. at java.base/sun.nio.ch.NioSocketImpl.bind(NioSocketImpl.java:636)
|
||||||
|
58. at java.base/java.net.ServerSocket.bind(ServerSocket.java:391)
|
||||||
|
59. at java.base/java.net.ServerSocket.<init>(ServerSocket.java:278)
|
||||||
|
60. at org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface$ServerLoopbackSocketFactory.createServerSocket(NetworkUtils.kt:69)
|
||||||
|
61. at java.rmi/sun.rmi.transport.tcp.TCPEndpoint.newServerSocket(TCPEndpoint.java:672)
|
||||||
|
62. at java.rmi/sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:344)
|
||||||
|
63. ... 14 more
|
||||||
|
|
||||||
|
error message: Failed connecting to the daemon in 3 retries
|
||||||
|
|
||||||
|
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
|
||||||
|
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
|
||||||
|
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:76)
|
||||||
|
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
|
||||||
|
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
|
||||||
|
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
|
||||||
|
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
|
||||||
|
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
|
||||||
|
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
|
||||||
|
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174)
|
||||||
|
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:187)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:120)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:162)
|
||||||
|
at org.gradle.internal.Factories$1.create(Factories.java:31)
|
||||||
|
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:264)
|
||||||
|
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:128)
|
||||||
|
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:133)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:157)
|
||||||
|
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:126)
|
||||||
|
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
|
||||||
|
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
|
||||||
|
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
|
||||||
|
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
|
||||||
|
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
|
||||||
|
at java.base/java.lang.Thread.run(Thread.java:1583)
|
||||||
|
|
||||||
|
|
||||||
104
EnchantmentTransfer.ipr
Normal file
104
EnchantmentTransfer.ipr
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<option name="DEFAULT_COMPILER" value="Javac"/>
|
||||||
|
<resourceExtensions>
|
||||||
|
<entry name=".+\.(properties|xml|html|dtd|tld)"/>
|
||||||
|
<entry name=".+\.(gif|png|jpeg|jpg)"/>
|
||||||
|
</resourceExtensions>
|
||||||
|
<wildcardResourcePatterns>
|
||||||
|
<entry name="!?*.class"/>
|
||||||
|
<entry name="!?*.scala"/>
|
||||||
|
<entry name="!?*.groovy"/>
|
||||||
|
<entry name="!?*.java"/>
|
||||||
|
</wildcardResourcePatterns>
|
||||||
|
<annotationProcessing enabled="false" useClasspath="true"/>
|
||||||
|
<bytecodeTargetLevel target="21"/>
|
||||||
|
</component>
|
||||||
|
<component name="CopyrightManager" default="">
|
||||||
|
<module2copyright/>
|
||||||
|
</component>
|
||||||
|
<component name="DependencyValidationManager">
|
||||||
|
<option name="SKIP_IMPORT_STATEMENTS" value="false"/>
|
||||||
|
</component>
|
||||||
|
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false"/>
|
||||||
|
<component name="GradleUISettings">
|
||||||
|
<setting name="root"/>
|
||||||
|
</component>
|
||||||
|
<component name="GradleUISettings2">
|
||||||
|
<setting name="root"/>
|
||||||
|
</component>
|
||||||
|
<component name="IdProvider" IDEtalkID="11DA1DB66DD62DDA1ED602B7079FE97C"/>
|
||||||
|
<component name="JavadocGenerationManager">
|
||||||
|
<option name="OUTPUT_DIRECTORY"/>
|
||||||
|
<option name="OPTION_SCOPE" value="protected"/>
|
||||||
|
<option name="OPTION_HIERARCHY" value="true"/>
|
||||||
|
<option name="OPTION_NAVIGATOR" value="true"/>
|
||||||
|
<option name="OPTION_INDEX" value="true"/>
|
||||||
|
<option name="OPTION_SEPARATE_INDEX" value="true"/>
|
||||||
|
<option name="OPTION_DOCUMENT_TAG_USE" value="false"/>
|
||||||
|
<option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false"/>
|
||||||
|
<option name="OPTION_DOCUMENT_TAG_VERSION" value="false"/>
|
||||||
|
<option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true"/>
|
||||||
|
<option name="OPTION_DEPRECATED_LIST" value="true"/>
|
||||||
|
<option name="OTHER_OPTIONS" value=""/>
|
||||||
|
<option name="HEAP_SIZE"/>
|
||||||
|
<option name="LOCALE"/>
|
||||||
|
<option name="OPEN_IN_BROWSER" value="true"/>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/EnchantmentTransfer.iml" filepath="$PROJECT_DIR$/EnchantmentTransfer.iml"/>
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" assert-keyword="true" jdk-15="true" project-jdk-type="JavaSDK" assert-jdk-15="true" project-jdk-name="21">
|
||||||
|
<output url="file://$PROJECT_DIR$/out"/>
|
||||||
|
</component>
|
||||||
|
<component name="SvnBranchConfigurationManager">
|
||||||
|
<option name="mySupportsUserInfoFilter" value="true"/>
|
||||||
|
</component>
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs=""/>
|
||||||
|
</component>
|
||||||
|
<component name="masterDetails">
|
||||||
|
<states>
|
||||||
|
<state key="ArtifactsStructureConfigurable.UI">
|
||||||
|
<UIState>
|
||||||
|
<splitter-proportions>
|
||||||
|
<SplitterProportionsDataImpl/>
|
||||||
|
</splitter-proportions>
|
||||||
|
<settings/>
|
||||||
|
</UIState>
|
||||||
|
</state>
|
||||||
|
<state key="Copyright.UI">
|
||||||
|
<UIState>
|
||||||
|
<splitter-proportions>
|
||||||
|
<SplitterProportionsDataImpl/>
|
||||||
|
</splitter-proportions>
|
||||||
|
</UIState>
|
||||||
|
</state>
|
||||||
|
<state key="ProjectJDKs.UI">
|
||||||
|
<UIState>
|
||||||
|
<splitter-proportions>
|
||||||
|
<SplitterProportionsDataImpl>
|
||||||
|
<option name="proportions">
|
||||||
|
<list>
|
||||||
|
<option value="0.2"/>
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</SplitterProportionsDataImpl>
|
||||||
|
</splitter-proportions>
|
||||||
|
<last-edited>1.6</last-edited>
|
||||||
|
</UIState>
|
||||||
|
</state>
|
||||||
|
<state key="ScopeChooserConfigurable.UI">
|
||||||
|
<UIState>
|
||||||
|
<splitter-proportions>
|
||||||
|
<SplitterProportionsDataImpl/>
|
||||||
|
</splitter-proportions>
|
||||||
|
<settings/>
|
||||||
|
</UIState>
|
||||||
|
</state>
|
||||||
|
</states>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
207
EnchantmentTransfer.iws
Normal file
207
EnchantmentTransfer.iws
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<option name="TRACKING_ENABLED" value="true"/>
|
||||||
|
<option name="SHOW_DIALOG" value="false"/>
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true"/>
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false"/>
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE"/>
|
||||||
|
</component>
|
||||||
|
<component name="ChangesViewManager" flattened_view="true" show_ignored="false"/>
|
||||||
|
<component name="CreatePatchCommitExecutor">
|
||||||
|
<option name="PATCH_PATH" value=""/>
|
||||||
|
<option name="REVERSE_PATCH" value="false"/>
|
||||||
|
</component>
|
||||||
|
<component name="DaemonCodeAnalyzer">
|
||||||
|
<disable_hints/>
|
||||||
|
</component>
|
||||||
|
<component name="DebuggerManager">
|
||||||
|
<breakpoint_any>
|
||||||
|
<breakpoint>
|
||||||
|
<option name="NOTIFY_CAUGHT" value="true"/>
|
||||||
|
<option name="NOTIFY_UNCAUGHT" value="true"/>
|
||||||
|
<option name="ENABLED" value="false"/>
|
||||||
|
<option name="LOG_ENABLED" value="false"/>
|
||||||
|
<option name="LOG_EXPRESSION_ENABLED" value="false"/>
|
||||||
|
<option name="SUSPEND_POLICY" value="SuspendAll"/>
|
||||||
|
<option name="COUNT_FILTER_ENABLED" value="false"/>
|
||||||
|
<option name="COUNT_FILTER" value="0"/>
|
||||||
|
<option name="CONDITION_ENABLED" value="false"/>
|
||||||
|
<option name="CLASS_FILTERS_ENABLED" value="false"/>
|
||||||
|
<option name="INSTANCE_FILTERS_ENABLED" value="false"/>
|
||||||
|
<option name="CONDITION" value=""/>
|
||||||
|
<option name="LOG_MESSAGE" value=""/>
|
||||||
|
</breakpoint>
|
||||||
|
<breakpoint>
|
||||||
|
<option name="NOTIFY_CAUGHT" value="true"/>
|
||||||
|
<option name="NOTIFY_UNCAUGHT" value="true"/>
|
||||||
|
<option name="ENABLED" value="false"/>
|
||||||
|
<option name="LOG_ENABLED" value="false"/>
|
||||||
|
<option name="LOG_EXPRESSION_ENABLED" value="false"/>
|
||||||
|
<option name="SUSPEND_POLICY" value="SuspendAll"/>
|
||||||
|
<option name="COUNT_FILTER_ENABLED" value="false"/>
|
||||||
|
<option name="COUNT_FILTER" value="0"/>
|
||||||
|
<option name="CONDITION_ENABLED" value="false"/>
|
||||||
|
<option name="CLASS_FILTERS_ENABLED" value="false"/>
|
||||||
|
<option name="INSTANCE_FILTERS_ENABLED" value="false"/>
|
||||||
|
<option name="CONDITION" value=""/>
|
||||||
|
<option name="LOG_MESSAGE" value=""/>
|
||||||
|
</breakpoint>
|
||||||
|
</breakpoint_any>
|
||||||
|
<breakpoint_rules/>
|
||||||
|
<ui_properties/>
|
||||||
|
</component>
|
||||||
|
<component name="ModuleEditorState">
|
||||||
|
<option name="LAST_EDITED_MODULE_NAME"/>
|
||||||
|
<option name="LAST_EDITED_TAB_NAME"/>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||||
|
<entry key="Project Default">
|
||||||
|
<profile-state/>
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectLevelVcsManager">
|
||||||
|
<OptionsSetting value="true" id="Add"/>
|
||||||
|
<OptionsSetting value="true" id="Remove"/>
|
||||||
|
<OptionsSetting value="true" id="Checkout"/>
|
||||||
|
<OptionsSetting value="true" id="Update"/>
|
||||||
|
<OptionsSetting value="true" id="Status"/>
|
||||||
|
<OptionsSetting value="true" id="Edit"/>
|
||||||
|
<ConfirmationsSetting value="0" id="Add"/>
|
||||||
|
<ConfirmationsSetting value="0" id="Remove"/>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectReloadState">
|
||||||
|
<option name="STATE" value="0"/>
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="GoToFile.includeJavaFiles" value="false"/>
|
||||||
|
<property name="GoToClass.toSaveIncludeLibraries" value="false"/>
|
||||||
|
<property name="MemberChooser.sorted" value="false"/>
|
||||||
|
<property name="MemberChooser.showClasses" value="true"/>
|
||||||
|
<property name="GoToClass.includeLibraries" value="false"/>
|
||||||
|
<property name="MemberChooser.copyJavadoc" value="false"/>
|
||||||
|
</component>
|
||||||
|
<component name="RunManager">
|
||||||
|
<configuration default="true" type="Remote" factoryName="Remote">
|
||||||
|
<option name="USE_SOCKET_TRANSPORT" value="true"/>
|
||||||
|
<option name="SERVER_MODE" value="false"/>
|
||||||
|
<option name="SHMEM_ADDRESS" value="javadebug"/>
|
||||||
|
<option name="HOST" value="localhost"/>
|
||||||
|
<option name="PORT" value="5005"/>
|
||||||
|
<method>
|
||||||
|
<option name="BuildArtifacts" enabled="false"/>
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="Applet" factoryName="Applet">
|
||||||
|
<module name=""/>
|
||||||
|
<option name="MAIN_CLASS_NAME"/>
|
||||||
|
<option name="HTML_FILE_NAME"/>
|
||||||
|
<option name="HTML_USED" value="false"/>
|
||||||
|
<option name="WIDTH" value="400"/>
|
||||||
|
<option name="HEIGHT" value="300"/>
|
||||||
|
<option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy"/>
|
||||||
|
<option name="VM_PARAMETERS"/>
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false"/>
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH"/>
|
||||||
|
<method>
|
||||||
|
<option name="BuildArtifacts" enabled="false"/>
|
||||||
|
<option name="Make" enabled="true"/>
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="Application" factoryName="Application">
|
||||||
|
<extension name="coverage" enabled="false" merge="false"/>
|
||||||
|
<option name="MAIN_CLASS_NAME"/>
|
||||||
|
<option name="VM_PARAMETERS"/>
|
||||||
|
<option name="PROGRAM_PARAMETERS"/>
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$"/>
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false"/>
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH"/>
|
||||||
|
<option name="ENABLE_SWING_INSPECTOR" value="false"/>
|
||||||
|
<option name="ENV_VARIABLES"/>
|
||||||
|
<option name="PASS_PARENT_ENVS" value="true"/>
|
||||||
|
<module name=""/>
|
||||||
|
<envs/>
|
||||||
|
<method>
|
||||||
|
<option name="BuildArtifacts" enabled="false"/>
|
||||||
|
<option name="Make" enabled="true"/>
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="JUnit" factoryName="JUnit">
|
||||||
|
<extension name="coverage" enabled="false" merge="false"/>
|
||||||
|
<module name=""/>
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false"/>
|
||||||
|
<option name="ALTERNATIVE_JRE_PATH"/>
|
||||||
|
<option name="PACKAGE_NAME"/>
|
||||||
|
<option name="MAIN_CLASS_NAME"/>
|
||||||
|
<option name="METHOD_NAME"/>
|
||||||
|
<option name="TEST_OBJECT" value="class"/>
|
||||||
|
<option name="VM_PARAMETERS"/>
|
||||||
|
<option name="PARAMETERS"/>
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$"/>
|
||||||
|
<option name="ENV_VARIABLES"/>
|
||||||
|
<option name="PASS_PARENT_ENVS" value="true"/>
|
||||||
|
<option name="TEST_SEARCH_SCOPE">
|
||||||
|
<value defaultName="moduleWithDependencies"/>
|
||||||
|
</option>
|
||||||
|
<envs/>
|
||||||
|
<method>
|
||||||
|
<option name="BuildArtifacts" enabled="false"/>
|
||||||
|
<option name="Make" enabled="true"/>
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
<list size="0"/>
|
||||||
|
<configuration name="<template>" type="WebApp" default="true" selected="false">
|
||||||
|
<Host>localhost</Host>
|
||||||
|
<Port>5050</Port>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
|
<component name="ShelveChangesManager" show_recycled="false"/>
|
||||||
|
<component name="SvnConfiguration" maxAnnotateRevisions="500">
|
||||||
|
<option name="USER" value=""/>
|
||||||
|
<option name="PASSWORD" value=""/>
|
||||||
|
<option name="LAST_MERGED_REVISION"/>
|
||||||
|
<option name="UPDATE_RUN_STATUS" value="false"/>
|
||||||
|
<option name="MERGE_DRY_RUN" value="false"/>
|
||||||
|
<option name="MERGE_DIFF_USE_ANCESTRY" value="true"/>
|
||||||
|
<option name="UPDATE_LOCK_ON_DEMAND" value="false"/>
|
||||||
|
<option name="IGNORE_SPACES_IN_MERGE" value="false"/>
|
||||||
|
<option name="DETECT_NESTED_COPIES" value="true"/>
|
||||||
|
<option name="IGNORE_SPACES_IN_ANNOTATE" value="true"/>
|
||||||
|
<option name="SHOW_MERGE_SOURCES_IN_ANNOTATE" value="true"/>
|
||||||
|
<myIsUseDefaultProxy>false</myIsUseDefaultProxy>
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task"/>
|
||||||
|
<servers/>
|
||||||
|
</component>
|
||||||
|
<component name="VcsManagerConfiguration">
|
||||||
|
<option name="OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT" value="true"/>
|
||||||
|
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="true"/>
|
||||||
|
<option name="PERFORM_UPDATE_IN_BACKGROUND" value="true"/>
|
||||||
|
<option name="PERFORM_COMMIT_IN_BACKGROUND" value="true"/>
|
||||||
|
<option name="PERFORM_EDIT_IN_BACKGROUND" value="true"/>
|
||||||
|
<option name="PERFORM_CHECKOUT_IN_BACKGROUND" value="true"/>
|
||||||
|
<option name="PERFORM_ADD_REMOVE_IN_BACKGROUND" value="true"/>
|
||||||
|
<option name="PERFORM_ROLLBACK_IN_BACKGROUND" value="false"/>
|
||||||
|
<option name="CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND" value="false"/>
|
||||||
|
<option name="ENABLE_BACKGROUND_PROCESSES" value="false"/>
|
||||||
|
<option name="CHANGED_ON_SERVER_INTERVAL" value="60"/>
|
||||||
|
<option name="FORCE_NON_EMPTY_COMMENT" value="false"/>
|
||||||
|
<option name="LAST_COMMIT_MESSAGE"/>
|
||||||
|
<option name="MAKE_NEW_CHANGELIST_ACTIVE" value="true"/>
|
||||||
|
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="false"/>
|
||||||
|
<option name="CHECK_FILES_UP_TO_DATE_BEFORE_COMMIT" value="false"/>
|
||||||
|
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="false"/>
|
||||||
|
<option name="REFORMAT_BEFORE_FILE_COMMIT" value="false"/>
|
||||||
|
<option name="FILE_HISTORY_DIALOG_COMMENTS_SPLITTER_PROPORTION" value="0.8"/>
|
||||||
|
<option name="FILE_HISTORY_DIALOG_SPLITTER_PROPORTION" value="0.5"/>
|
||||||
|
<option name="ACTIVE_VCS_NAME"/>
|
||||||
|
<option name="UPDATE_GROUP_BY_PACKAGES" value="false"/>
|
||||||
|
<option name="UPDATE_GROUP_BY_CHANGELIST" value="false"/>
|
||||||
|
<option name="SHOW_FILE_HISTORY_AS_TREE" value="false"/>
|
||||||
|
<option name="FILE_HISTORY_SPLITTER_PROPORTION" value="0.6"/>
|
||||||
|
</component>
|
||||||
|
<component name="XDebuggerManager">
|
||||||
|
<breakpoint-manager/>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
51
README.en.md
Normal file
51
README.en.md
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
[Русская версия](README.md)
|
||||||
|
|
||||||
|
# Enchantment Transfer Mod
|
||||||
|
|
||||||
|
A mod for Minecraft 1.21.1 that adds a machine for transferring enchantments between items.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Enchantment Transfer**: Transfers enchantments from one item to another (as well as to books)
|
||||||
|
- **Charge System**: Machine requires energy in the form of items
|
||||||
|
- **Redstone Control**: Only works with redstone signal
|
||||||
|
- **Processing Progress**: Processing time depends on amount and level of enchantments
|
||||||
|
|
||||||
|
## Accepted Fuel Sources
|
||||||
|
|
||||||
|
| Item | Charge |
|
||||||
|
|-----------------|-------|
|
||||||
|
| Redstone | 16 |
|
||||||
|
| Copper Ingot | 1 |
|
||||||
|
| Iron Ingot | 4 |
|
||||||
|
| Gold Ingot | 2 |
|
||||||
|
| Diamond | 32 |
|
||||||
|
| Netherite Ingot | 64 |
|
||||||
|
|
||||||
|
Maximum charge capacity: 1 000 000 units
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
1. Place the **Enchantment Transferrer** block in the world
|
||||||
|
2. Put an enchanted item, target item and, optionally, a **book**
|
||||||
|
3. Put **fuel items** in the fuel slot
|
||||||
|
4. Provide a **redstone signal** to activate
|
||||||
|
5. Wait for the process to complete
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Install NeoForge 21.1.219 for Minecraft 1.21.1
|
||||||
|
2. Place the `.jar` mod file in the `mods` folder
|
||||||
|
3. Launch the game
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gradlew.bat build
|
||||||
|
```
|
||||||
|
|
||||||
|
The built file will be located in `build/libs/`
|
||||||
|
|
||||||
|
## 3rd-party Assets
|
||||||
|
|
||||||
|
UI and block textures were taken from [Ycarx/artoftecharium](https://github.com/Ycarx/artoftecharium) and altered to suite my needs.
|
||||||
51
README.md
Normal file
51
README.md
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
[English version](README.en.md)
|
||||||
|
|
||||||
|
# Мод Enchantment Transfer
|
||||||
|
|
||||||
|
Мод для Minecraft 1.21.1, добавляющий машину для переноса зачарований.
|
||||||
|
|
||||||
|
## Возможности
|
||||||
|
|
||||||
|
- **Перенос зачарований**: Переносит зачарования с одного предмета на другой (в т.ч. - на книги)
|
||||||
|
- **Система заряда**: Машина требует энергию в виде предметов
|
||||||
|
- **Редстоун контроль**: Работает только при наличии редстоун сигнала
|
||||||
|
- **Прогресс обработки**: Время обработки зависит от количества и уровня зачарований
|
||||||
|
|
||||||
|
## Принимаемые источники энергии
|
||||||
|
|
||||||
|
| Предмет | Заряд |
|
||||||
|
|----------|-------|
|
||||||
|
| Редстоун | 16 |
|
||||||
|
| Медь | 1 |
|
||||||
|
| Железо | 4 |
|
||||||
|
| Золото | 2 |
|
||||||
|
| Алмаз | 32 |
|
||||||
|
| Незерит | 64 |
|
||||||
|
|
||||||
|
Максимальная вместимость заряда: 1 000 000 единиц
|
||||||
|
|
||||||
|
## Как использовать
|
||||||
|
|
||||||
|
1. Поместите **Enchantment Transferrer** в мир
|
||||||
|
2. Поместите зачарованный предмет, целевой предмет в **средний слот**, опционально - книгу
|
||||||
|
3. Поместите **топливо** в слот
|
||||||
|
4. Подайте **редстоун сигнал** для активации
|
||||||
|
5. Дождитесь завершения процесса
|
||||||
|
|
||||||
|
## Установка
|
||||||
|
|
||||||
|
1. Установите NeoForge 21.1.219 для Minecraft 1.21.1
|
||||||
|
2. Поместите `.jar` файл мода в папку `mods`
|
||||||
|
3. Запустите игру
|
||||||
|
|
||||||
|
## Сборка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gradlew.bat build
|
||||||
|
```
|
||||||
|
|
||||||
|
Собранный файл будет находиться в `build/libs/`
|
||||||
|
|
||||||
|
## Чужие ассеты
|
||||||
|
|
||||||
|
Текстуры для UI и блоков были взяты из [Ycarx/artoftecharium](https://github.com/Ycarx/artoftecharium) из изменены по потребности
|
||||||
|
|
@ -3,7 +3,7 @@ plugins {
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
id 'idea'
|
id 'idea'
|
||||||
id 'net.neoforged.moddev' version '2.0.141'
|
id 'net.neoforged.moddev' version '2.0.141'
|
||||||
id 'org.jetbrains.kotlin.jvm' version '2.0.0'
|
id 'org.jetbrains.kotlin.jvm' version '2.3.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
version = mod_version
|
version = mod_version
|
||||||
|
|
@ -103,7 +103,7 @@ sourceSets.main.resources { srcDir 'src/generated/resources' }
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'thedarkcolour:kotlinforforge-neoforge:5.3.0'
|
implementation 'thedarkcolour:kotlinforforge-neoforge:5.11.0'
|
||||||
|
|
||||||
// Example mod dependency with JEI
|
// Example mod dependency with JEI
|
||||||
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
|
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
|
||||||
|
|
|
||||||
18
generate_textures.py
Normal file
18
generate_textures.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
from PIL import Image
|
||||||
|
import os
|
||||||
|
|
||||||
|
textures_dir = "src/main/resources/assets/enct/textures/block"
|
||||||
|
os.makedirs(textures_dir, exist_ok=True)
|
||||||
|
|
||||||
|
colors = {
|
||||||
|
"enchantment_transferrer_top": (120, 80, 200),
|
||||||
|
"enchantment_transferrer_bottom": (80, 80, 80),
|
||||||
|
"enchantment_transferrer_side": (100, 100, 120),
|
||||||
|
"enchantment_transferrer_front": (140, 100, 220),
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, color in colors.items():
|
||||||
|
img = Image.new('RGBA', (16, 16), color + (255,))
|
||||||
|
img.save(f"{textures_dir}/{name}.png", 'PNG')
|
||||||
|
|
||||||
|
print("Textures generated successfully!")
|
||||||
|
|
@ -4,6 +4,7 @@ org.gradle.daemon=true
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
org.gradle.configuration-cache=true
|
org.gradle.configuration-cache=true
|
||||||
|
kotlin.compiler.execution.strategy=in-process
|
||||||
## Environment Properties
|
## Environment Properties
|
||||||
# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge
|
# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge
|
||||||
# The Minecraft version must agree with the Neo version to get a valid artifact
|
# The Minecraft version must agree with the Neo version to get a valid artifact
|
||||||
|
|
@ -35,6 +36,6 @@ mod_version=1.0.0
|
||||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||||
mod_group_id=xyz.nuark.mcmod
|
mod_group_id=xyz.nuark.mcmod
|
||||||
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
|
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
|
||||||
mod_authors=
|
mod_authors=nuark
|
||||||
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
|
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
|
||||||
mod_description=
|
mod_description=Ever been in a situation, when you have new toy, but now you need to move enchantments from previous one? Say no more!
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:recipes/root",
|
||||||
|
"criteria": {
|
||||||
|
"has_ench_table": {
|
||||||
|
"conditions": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"items": "minecraft:enchanting_table"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"trigger": "minecraft:inventory_changed"
|
||||||
|
},
|
||||||
|
"has_the_recipe": {
|
||||||
|
"conditions": {
|
||||||
|
"recipe": "enct:enchantment_transferrer"
|
||||||
|
},
|
||||||
|
"trigger": "minecraft:recipe_unlocked"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requirements": [
|
||||||
|
[
|
||||||
|
"has_the_recipe",
|
||||||
|
"has_ench_table"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"rewards": {
|
||||||
|
"recipes": [
|
||||||
|
"enct:enchantment_transferrer"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"type": "minecraft:crafting_shaped",
|
||||||
|
"category": "redstone",
|
||||||
|
"key": {
|
||||||
|
"B": {
|
||||||
|
"item": "minecraft:blaze_rod"
|
||||||
|
},
|
||||||
|
"E": {
|
||||||
|
"item": "minecraft:enchanting_table"
|
||||||
|
},
|
||||||
|
"I": {
|
||||||
|
"item": "minecraft:iron_block"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pattern": [
|
||||||
|
"III",
|
||||||
|
"BEB",
|
||||||
|
"III"
|
||||||
|
],
|
||||||
|
"result": {
|
||||||
|
"count": 1,
|
||||||
|
"id": "enct:enchantment_transferrer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,63 +1,83 @@
|
||||||
package xyz.nuark.mcmod.enct
|
package xyz.nuark.mcmod.enct
|
||||||
|
|
||||||
import xyz.nuark.mcmod.enct.block.ModBlocks
|
import net.minecraft.core.registries.Registries
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.world.flag.FeatureFlags
|
||||||
|
import net.minecraft.world.inventory.MenuType
|
||||||
|
import net.minecraft.world.item.CreativeModeTabs
|
||||||
import net.neoforged.bus.api.SubscribeEvent
|
import net.neoforged.bus.api.SubscribeEvent
|
||||||
import net.neoforged.fml.common.EventBusSubscriber
|
import net.neoforged.fml.common.EventBusSubscriber
|
||||||
import net.neoforged.fml.common.Mod
|
import net.neoforged.fml.common.Mod
|
||||||
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent
|
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent
|
||||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent
|
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent
|
||||||
import net.neoforged.fml.event.lifecycle.FMLDedicatedServerSetupEvent
|
import net.neoforged.neoforge.capabilities.Capabilities
|
||||||
|
import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent
|
||||||
|
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent
|
||||||
|
import net.neoforged.neoforge.network.IContainerFactory
|
||||||
|
import net.neoforged.neoforge.registries.DeferredHolder
|
||||||
|
import net.neoforged.neoforge.registries.DeferredRegister
|
||||||
import org.apache.logging.log4j.Level
|
import org.apache.logging.log4j.Level
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.apache.logging.log4j.Logger
|
|
||||||
import thedarkcolour.kotlinforforge.neoforge.forge.MOD_BUS
|
import thedarkcolour.kotlinforforge.neoforge.forge.MOD_BUS
|
||||||
import thedarkcolour.kotlinforforge.neoforge.forge.runForDist
|
import xyz.nuark.mcmod.enct.block.ModBlocks
|
||||||
|
import xyz.nuark.mcmod.enct.block.entity.EnchantmentTransferrerBlockEntity
|
||||||
|
import xyz.nuark.mcmod.enct.menu.EnchantmentTransferrerMenu
|
||||||
|
import xyz.nuark.mcmod.enct.screen.EnchantmentTransferrerScreen
|
||||||
|
import java.util.function.Supplier
|
||||||
|
|
||||||
/**
|
|
||||||
* Main mod class.
|
|
||||||
*
|
|
||||||
* An example for blocks is in the `blocks` package of this mod.
|
|
||||||
*/
|
|
||||||
@Mod(Enchantmenttransfer.ID)
|
@Mod(Enchantmenttransfer.ID)
|
||||||
@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD)
|
@EventBusSubscriber
|
||||||
object Enchantmenttransfer {
|
object Enchantmenttransfer {
|
||||||
const val ID = "enct"
|
const val ID = "enct"
|
||||||
|
|
||||||
// the logger for our mod
|
val LOGGER = LogManager.getLogger(ID)
|
||||||
val LOGGER: Logger = LogManager.getLogger(ID)
|
|
||||||
|
val MENU_TYPES: DeferredRegister<MenuType<*>> = DeferredRegister.create(Registries.MENU, ID)
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val ENCHANTMENT_TRANSFERRER_MENU_TYPE: DeferredHolder<MenuType<*>, MenuType<EnchantmentTransferrerMenu>> = MENU_TYPES.register("enchantment_transferrer", Supplier {
|
||||||
|
MenuType<EnchantmentTransferrerMenu>(
|
||||||
|
IContainerFactory { containerId, playerInventory, buf ->
|
||||||
|
val pos = buf.readBlockPos()
|
||||||
|
val level = playerInventory.player.level()
|
||||||
|
val blockEntity = level.getBlockEntity(pos) as? EnchantmentTransferrerBlockEntity
|
||||||
|
if (blockEntity != null) {
|
||||||
|
EnchantmentTransferrerMenu(containerId, playerInventory, blockEntity, blockEntity.dataAccess)
|
||||||
|
} else {
|
||||||
|
throw IllegalStateException("BlockEntity not found at $pos")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FeatureFlags.VANILLA_SET
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
init {
|
init {
|
||||||
LOGGER.log(Level.INFO, "Hello world!")
|
ModBlocks.register(MOD_BUS)
|
||||||
|
MENU_TYPES.register(MOD_BUS)
|
||||||
|
|
||||||
// Register the KDeferredRegister to the mod-specific event bus
|
MOD_BUS.addListener<net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent> { event ->
|
||||||
ModBlocks.REGISTRY.register(MOD_BUS)
|
event.registerBlockEntity(
|
||||||
|
Capabilities.ItemHandler.BLOCK,
|
||||||
val obj = runForDist(clientTarget = {
|
ModBlocks.ENCHANTMENT_TRANSFERRER_BE.value(),
|
||||||
MOD_BUS.addListener(::onClientSetup)
|
{ be, side -> be.getHandlerForSide(side) }
|
||||||
Minecraft.getInstance()
|
)
|
||||||
}, serverTarget = {
|
}
|
||||||
MOD_BUS.addListener(::onServerSetup)
|
|
||||||
"test"
|
|
||||||
})
|
|
||||||
|
|
||||||
println(obj)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@SubscribeEvent
|
||||||
* This is used for initializing client specific
|
fun onBuildCreativeTabContents(event: BuildCreativeModeTabContentsEvent) {
|
||||||
* things such as renderers and keymaps
|
if (event.tabKey == CreativeModeTabs.REDSTONE_BLOCKS) {
|
||||||
* Fired on the mod specific event bus.
|
event.accept(ModBlocks.ENCHANTMENT_TRANSFERRER_ITEM.get())
|
||||||
*/
|
}
|
||||||
private fun onClientSetup(event: FMLClientSetupEvent) {
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
fun onClientSetup(event: FMLClientSetupEvent) {
|
||||||
LOGGER.log(Level.INFO, "Initializing client...")
|
LOGGER.log(Level.INFO, "Initializing client...")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@SubscribeEvent
|
||||||
* Fired on the global Forge bus.
|
fun onRegisterMenuScreens(event: RegisterMenuScreensEvent) {
|
||||||
*/
|
event.register(ENCHANTMENT_TRANSFERRER_MENU_TYPE.value(), ::EnchantmentTransferrerScreen)
|
||||||
private fun onServerSetup(event: FMLDedicatedServerSetupEvent) {
|
|
||||||
LOGGER.log(Level.INFO, "Server starting...")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
package xyz.nuark.mcmod.enct.block
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec
|
||||||
|
import xyz.nuark.mcmod.enct.block.entity.EnchantmentTransferrerBlockEntity
|
||||||
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.world.InteractionResult
|
||||||
|
import net.minecraft.world.entity.LivingEntity
|
||||||
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.level.Level
|
||||||
|
import net.minecraft.world.level.block.BaseEntityBlock
|
||||||
|
import net.minecraft.world.level.block.RenderShape
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||||
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
|
import net.minecraft.world.phys.BlockHitResult
|
||||||
|
import net.neoforged.neoforge.capabilities.Capabilities
|
||||||
|
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent
|
||||||
|
import org.jetbrains.annotations.Nullable
|
||||||
|
|
||||||
|
class EnchantmentTransferrerBlock(properties: Properties) : BaseEntityBlock(properties) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val CODEC: MapCodec<EnchantmentTransferrerBlock> = MapCodec.unit { EnchantmentTransferrerBlock(Properties.of()) }
|
||||||
|
|
||||||
|
fun registerCapabilities(event: RegisterCapabilitiesEvent) {
|
||||||
|
event.registerBlockEntity(
|
||||||
|
Capabilities.ItemHandler.BLOCK,
|
||||||
|
ModBlocks.ENCHANTMENT_TRANSFERRER_BE.value(),
|
||||||
|
) { be, side ->
|
||||||
|
be.getHandlerForSide(side)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun codec(): MapCodec<out EnchantmentTransferrerBlock> = CODEC
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
|
||||||
|
return EnchantmentTransferrerBlockEntity(pos, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun useWithoutItem(
|
||||||
|
state: BlockState,
|
||||||
|
level: Level,
|
||||||
|
pos: BlockPos,
|
||||||
|
player: Player,
|
||||||
|
hitResult: BlockHitResult
|
||||||
|
): InteractionResult {
|
||||||
|
if (level.isClientSide) {
|
||||||
|
return InteractionResult.SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
val blockEntity = level.getBlockEntity(pos)
|
||||||
|
if (blockEntity is EnchantmentTransferrerBlockEntity) {
|
||||||
|
player.openMenu(blockEntity) { buf ->
|
||||||
|
buf.writeBlockPos(pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return InteractionResult.CONSUME
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setPlacedBy(level: Level, pos: BlockPos, state: BlockState, @Nullable placer: LivingEntity?, stack: ItemStack) {
|
||||||
|
super.setPlacedBy(level, pos, state, placer, stack)
|
||||||
|
if (level.isClientSide) return
|
||||||
|
|
||||||
|
val blockEntity = level.getBlockEntity(pos)
|
||||||
|
// TODO: Maybe link machine to player? XP usage instead of fuel :thinking:
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemove(state: BlockState, level: Level, pos: BlockPos, newState: BlockState, isMoving: Boolean) {
|
||||||
|
if (state.block !== newState.block) {
|
||||||
|
val blockEntity = level.getBlockEntity(pos)
|
||||||
|
if (blockEntity is EnchantmentTransferrerBlockEntity) {
|
||||||
|
for (i in 0 until EnchantmentTransferrerBlockEntity.TOTAL_SLOTS) {
|
||||||
|
val stack = blockEntity.getItemHandler().getStackInSlot(i)
|
||||||
|
if (!stack.isEmpty) {
|
||||||
|
popResource(level, pos, stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.onRemove(state, level, pos, newState, isMoving)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRenderShape(state: BlockState): RenderShape {
|
||||||
|
return RenderShape.MODEL
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
override fun <T : BlockEntity> getTicker(
|
||||||
|
level: Level,
|
||||||
|
state: BlockState,
|
||||||
|
type: BlockEntityType<T>
|
||||||
|
): BlockEntityTicker<T>? {
|
||||||
|
if (level.isClientSide) return null
|
||||||
|
|
||||||
|
val blockEntityType = ModBlocks.ENCHANTMENT_TRANSFERRER_BE.value()
|
||||||
|
if (type !== blockEntityType) return null
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return BlockEntityTicker<T> { l, pos, s, be ->
|
||||||
|
EnchantmentTransferrerBlockEntity.serverTick(l, pos, s, be as EnchantmentTransferrerBlockEntity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,41 @@
|
||||||
package xyz.nuark.mcmod.enct.block
|
package xyz.nuark.mcmod.enct.block
|
||||||
|
|
||||||
import xyz.nuark.mcmod.enct.Enchantmenttransfer
|
import xyz.nuark.mcmod.enct.Enchantmenttransfer
|
||||||
|
import xyz.nuark.mcmod.enct.block.entity.EnchantmentTransferrerBlockEntity
|
||||||
|
import net.minecraft.core.registries.Registries
|
||||||
|
import net.minecraft.world.item.BlockItem
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.level.block.Block
|
import net.minecraft.world.level.block.Block
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||||
import net.minecraft.world.level.block.state.BlockBehaviour
|
import net.minecraft.world.level.block.state.BlockBehaviour
|
||||||
|
import net.neoforged.bus.api.IEventBus
|
||||||
import net.neoforged.neoforge.registries.DeferredRegister
|
import net.neoforged.neoforge.registries.DeferredRegister
|
||||||
|
import net.neoforged.neoforge.registries.DeferredHolder
|
||||||
// THIS LINE IS REQUIRED FOR USING PROPERTY DELEGATES
|
import java.util.function.Supplier
|
||||||
import thedarkcolour.kotlinforforge.neoforge.forge.getValue
|
|
||||||
|
|
||||||
object ModBlocks {
|
object ModBlocks {
|
||||||
val REGISTRY = DeferredRegister.createBlocks(Enchantmenttransfer.ID)
|
val BLOCKS = DeferredRegister.create(Registries.BLOCK, Enchantmenttransfer.ID)
|
||||||
|
val ITEMS = DeferredRegister.create(Registries.ITEM, Enchantmenttransfer.ID)
|
||||||
|
val BLOCK_ENTITIES = DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, Enchantmenttransfer.ID)
|
||||||
|
|
||||||
// If you get an "overload resolution ambiguity" error, include the arrow at the start of the closure.
|
val ENCHANTMENT_TRANSFERRER: DeferredHolder<Block, Block> = BLOCKS.register("enchantment_transferrer", Supplier {
|
||||||
val EXAMPLE_BLOCK by REGISTRY.register("example_block") { ->
|
EnchantmentTransferrerBlock(BlockBehaviour.Properties.of().strength(3.0f).requiresCorrectToolForDrops())
|
||||||
Block(BlockBehaviour.Properties.of().lightLevel { 15 }.strength(3.0f))
|
})
|
||||||
|
|
||||||
|
val ENCHANTMENT_TRANSFERRER_ITEM: DeferredHolder<Item, Item> = ITEMS.register("enchantment_transferrer", Supplier {
|
||||||
|
BlockItem(ENCHANTMENT_TRANSFERRER.get(), Item.Properties())
|
||||||
|
})
|
||||||
|
|
||||||
|
val ENCHANTMENT_TRANSFERRER_BE: DeferredHolder<BlockEntityType<*>, BlockEntityType<EnchantmentTransferrerBlockEntity>> = BLOCK_ENTITIES.register("enchantment_transferrer", Supplier {
|
||||||
|
BlockEntityType.Builder.of(
|
||||||
|
{ pos, state -> EnchantmentTransferrerBlockEntity(pos, state) },
|
||||||
|
ENCHANTMENT_TRANSFERRER.get()
|
||||||
|
).build(null)
|
||||||
|
})
|
||||||
|
|
||||||
|
fun register(eventBus: IEventBus) {
|
||||||
|
BLOCKS.register(eventBus)
|
||||||
|
ITEMS.register(eventBus)
|
||||||
|
BLOCK_ENTITIES.register(eventBus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,339 @@
|
||||||
|
package xyz.nuark.mcmod.enct.block.entity
|
||||||
|
|
||||||
|
import xyz.nuark.mcmod.enct.Enchantmenttransfer
|
||||||
|
import xyz.nuark.mcmod.enct.block.ModBlocks
|
||||||
|
import xyz.nuark.mcmod.enct.menu.EnchantmentTransferrerMenu
|
||||||
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.core.Direction
|
||||||
|
import net.minecraft.core.HolderLookup
|
||||||
|
import net.minecraft.core.component.DataComponents
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.network.protocol.Packet
|
||||||
|
import net.minecraft.network.protocol.game.ClientGamePacketListener
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket
|
||||||
|
import net.minecraft.world.MenuProvider
|
||||||
|
import net.minecraft.world.Nameable
|
||||||
|
import net.minecraft.world.WorldlyContainer
|
||||||
|
import net.minecraft.world.entity.player.Inventory
|
||||||
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
|
import net.minecraft.world.inventory.ContainerData
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper
|
||||||
|
import net.minecraft.world.item.enchantment.ItemEnchantments
|
||||||
|
import net.minecraft.world.level.Level
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity
|
||||||
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
|
import net.neoforged.neoforge.items.IItemHandler
|
||||||
|
import net.neoforged.neoforge.items.ItemStackHandler
|
||||||
|
import net.neoforged.neoforge.items.wrapper.SidedInvWrapper
|
||||||
|
import org.jetbrains.annotations.Nullable
|
||||||
|
|
||||||
|
class EnchantmentTransferrerBlockEntity(
|
||||||
|
pos: BlockPos,
|
||||||
|
state: BlockState
|
||||||
|
) : BlockEntity(ModBlocks.ENCHANTMENT_TRANSFERRER_BE.value(), pos, state), MenuProvider, Nameable, WorldlyContainer {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val SLOT_MAIN = 0
|
||||||
|
const val SLOT_BOOK = 1
|
||||||
|
const val SLOT_TARGET = 2
|
||||||
|
const val SLOT_FUEL = 3
|
||||||
|
const val TOTAL_SLOTS = 4
|
||||||
|
|
||||||
|
const val MAX_CHARGE = 1_000_000
|
||||||
|
|
||||||
|
// Charge values for different items
|
||||||
|
val CHARGE_VALUES = mapOf(
|
||||||
|
Items.COPPER_INGOT to 1,
|
||||||
|
Items.IRON_INGOT to 4,
|
||||||
|
Items.GOLD_INGOT to 2,
|
||||||
|
Items.DIAMOND to 32,
|
||||||
|
Items.NETHERITE_INGOT to 64,
|
||||||
|
Items.REDSTONE to 16
|
||||||
|
)
|
||||||
|
|
||||||
|
// Base time per enchantment (in ticks)
|
||||||
|
const val BASE_TIME_PER_ENCHANTMENT = 100
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun serverTick(level: Level, pos: BlockPos, state: BlockState, be: EnchantmentTransferrerBlockEntity) {
|
||||||
|
be.tick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val itemHandler = object : ItemStackHandler(TOTAL_SLOTS) {
|
||||||
|
override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
|
||||||
|
return when (slot) {
|
||||||
|
SLOT_MAIN -> EnchantmentHelper.hasAnyEnchantments(stack)
|
||||||
|
SLOT_TARGET -> !EnchantmentHelper.hasAnyEnchantments(stack) && EnchantmentHelper.canStoreEnchantments(stack)
|
||||||
|
SLOT_BOOK -> stack.item == Items.BOOK || stack.item == Items.ENCHANTED_BOOK
|
||||||
|
SLOT_FUEL -> CHARGE_VALUES.containsKey(stack.item)
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSlotsForFace(side: Direction): IntArray {
|
||||||
|
return when (side) {
|
||||||
|
Direction.UP -> intArrayOf(SLOT_BOOK)
|
||||||
|
Direction.DOWN -> intArrayOf()
|
||||||
|
else -> intArrayOf(SLOT_FUEL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canPlaceItemThroughFace(index: Int, itemStack: ItemStack, @Nullable direction: Direction?): Boolean {
|
||||||
|
return itemHandler.isItemValid(index, itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canTakeItemThroughFace(index: Int, itemStack: ItemStack, direction: Direction): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getContainerSize(): Int = TOTAL_SLOTS
|
||||||
|
|
||||||
|
override fun isEmpty(): Boolean = (0 until TOTAL_SLOTS).all { itemHandler.getStackInSlot(it).isEmpty }
|
||||||
|
|
||||||
|
override fun getItem(slot: Int): ItemStack = itemHandler.getStackInSlot(slot)
|
||||||
|
|
||||||
|
override fun removeItem(slot: Int, amount: Int): ItemStack {
|
||||||
|
return itemHandler.extractItem(slot, amount, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeItemNoUpdate(slot: Int): ItemStack {
|
||||||
|
val stack = itemHandler.getStackInSlot(slot)
|
||||||
|
itemHandler.setStackInSlot(slot, ItemStack.EMPTY)
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setItem(slot: Int, stack: ItemStack) {
|
||||||
|
itemHandler.setStackInSlot(slot, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stillValid(player: Player): Boolean = true
|
||||||
|
|
||||||
|
override fun clearContent() {
|
||||||
|
for (i in 0 until TOTAL_SLOTS) {
|
||||||
|
itemHandler.setStackInSlot(i, ItemStack.EMPTY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val handlerUp = SidedInvWrapper(this, Direction.UP)
|
||||||
|
private val handlerSides = SidedInvWrapper(this, Direction.NORTH)
|
||||||
|
|
||||||
|
private var charge: Int = 0
|
||||||
|
private var processTime: Int = 0
|
||||||
|
private var totalTime: Int = 0
|
||||||
|
private var isProcessing: Boolean = false
|
||||||
|
private var wasPowered: Boolean = false
|
||||||
|
|
||||||
|
// ContainerData for GUI sync
|
||||||
|
val dataAccess = object : ContainerData {
|
||||||
|
override fun get(index: Int): Int = when (index) {
|
||||||
|
0 -> this@EnchantmentTransferrerBlockEntity.charge
|
||||||
|
1 -> this@EnchantmentTransferrerBlockEntity.processTime
|
||||||
|
2 -> this@EnchantmentTransferrerBlockEntity.totalTime
|
||||||
|
3 -> if (this@EnchantmentTransferrerBlockEntity.isProcessing) 1 else 0
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun set(index: Int, value: Int) {
|
||||||
|
when (index) {
|
||||||
|
0 -> this@EnchantmentTransferrerBlockEntity.charge = value
|
||||||
|
1 -> this@EnchantmentTransferrerBlockEntity.processTime = value
|
||||||
|
2 -> this@EnchantmentTransferrerBlockEntity.totalTime = value
|
||||||
|
3 -> this@EnchantmentTransferrerBlockEntity.isProcessing = value == 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCount(): Int = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getItemHandler(): IItemHandler = itemHandler
|
||||||
|
|
||||||
|
fun getHandlerForSide(side: Direction?): IItemHandler? {
|
||||||
|
return when (side) {
|
||||||
|
Direction.UP -> handlerUp
|
||||||
|
Direction.DOWN -> null
|
||||||
|
else -> handlerSides
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(): Component = Component.translatable("block.${Enchantmenttransfer.ID}.enchantment_transferrer")
|
||||||
|
|
||||||
|
override fun getDisplayName(): Component = name
|
||||||
|
|
||||||
|
override fun createMenu(containerId: Int, playerInventory: Inventory, player: Player): AbstractContainerMenu {
|
||||||
|
return EnchantmentTransferrerMenu(containerId, playerInventory, this, dataAccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveAdditional(tag: CompoundTag, registries: net.minecraft.core.HolderLookup.Provider) {
|
||||||
|
super.saveAdditional(tag, registries)
|
||||||
|
tag.put("items", itemHandler.serializeNBT(registries))
|
||||||
|
tag.putInt("charge", charge)
|
||||||
|
tag.putInt("processTime", processTime)
|
||||||
|
tag.putInt("totalTime", totalTime)
|
||||||
|
tag.putBoolean("isProcessing", isProcessing)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||||
|
super.loadAdditional(tag, registries)
|
||||||
|
|
||||||
|
itemHandler.deserializeNBT(registries, tag.getCompound("items"))
|
||||||
|
charge = tag.getInt("charge")
|
||||||
|
processTime = tag.getInt("processTime")
|
||||||
|
totalTime = tag.getInt("totalTime")
|
||||||
|
isProcessing = tag.getBoolean("isProcessing")
|
||||||
|
|
||||||
|
setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getUpdateTag(registries: HolderLookup.Provider): CompoundTag {
|
||||||
|
val tag = CompoundTag()
|
||||||
|
saveAdditional(tag, registries)
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getUpdatePacket(): Packet<ClientGamePacketListener>? {
|
||||||
|
return ClientboundBlockEntityDataPacket.create(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tick() {
|
||||||
|
if (level?.isClientSide == true) return
|
||||||
|
|
||||||
|
val isPowered = level?.hasNeighborSignal(worldPosition) == true
|
||||||
|
|
||||||
|
if (charge < MAX_CHARGE) {
|
||||||
|
consumeFuel()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPowered) {
|
||||||
|
if (wasPowered) {
|
||||||
|
setChanged()
|
||||||
|
}
|
||||||
|
wasPowered = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wasPowered = true
|
||||||
|
|
||||||
|
if (!isProcessing) {
|
||||||
|
if (canProcess()) {
|
||||||
|
startProcessing()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charge > 0) {
|
||||||
|
if (!canProcess()) {
|
||||||
|
processTime = 0
|
||||||
|
setChanged()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
processTime++
|
||||||
|
charge--
|
||||||
|
|
||||||
|
if (processTime >= totalTime) {
|
||||||
|
finishProcessing()
|
||||||
|
}
|
||||||
|
setChanged()
|
||||||
|
level?.sendBlockUpdated(worldPosition, blockState, blockState, 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun consumeFuel() {
|
||||||
|
val stack = getItem(SLOT_FUEL)
|
||||||
|
if (!stack.isEmpty) {
|
||||||
|
val chargeValue = CHARGE_VALUES[stack.item] ?: 0
|
||||||
|
if (chargeValue > 0 && charge + chargeValue <= MAX_CHARGE) {
|
||||||
|
stack.shrink(1)
|
||||||
|
setItem(SLOT_FUEL, stack)
|
||||||
|
charge += chargeValue
|
||||||
|
setChanged()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun canProcess(): Boolean {
|
||||||
|
val mainStack = getItem(SLOT_MAIN)
|
||||||
|
if (mainStack.isEmpty || !EnchantmentHelper.hasAnyEnchantments(mainStack)) return false
|
||||||
|
|
||||||
|
val targetStack = getItem(SLOT_TARGET)
|
||||||
|
|
||||||
|
val mainEnchantments = EnchantmentHelper.getEnchantmentsForCrafting(mainStack)
|
||||||
|
if (mainEnchantments.isEmpty) return false
|
||||||
|
|
||||||
|
val targetEnchantments = EnchantmentHelper.getEnchantmentsForCrafting(targetStack)
|
||||||
|
if (!targetEnchantments.isEmpty) return false
|
||||||
|
|
||||||
|
val hasValidTarget = !targetStack.isEmpty
|
||||||
|
return hasValidTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startProcessing() {
|
||||||
|
val mainStack = getItem(SLOT_MAIN)
|
||||||
|
val mainEnchantments = EnchantmentHelper.getEnchantmentsForCrafting(mainStack).entrySet()
|
||||||
|
|
||||||
|
var totalLevels = 0
|
||||||
|
mainEnchantments.forEach { entry ->
|
||||||
|
totalLevels += entry.intValue
|
||||||
|
}
|
||||||
|
|
||||||
|
val enchantmentCount = mainEnchantments.size
|
||||||
|
val avgLevel = if (enchantmentCount > 0) totalLevels.toFloat() / enchantmentCount else 1f
|
||||||
|
totalTime = (enchantmentCount * avgLevel * BASE_TIME_PER_ENCHANTMENT).toInt().coerceAtLeast(100)
|
||||||
|
|
||||||
|
processTime = 0
|
||||||
|
isProcessing = true
|
||||||
|
setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun finishProcessing() {
|
||||||
|
val mainStack = getItem(SLOT_MAIN)
|
||||||
|
val targetStack = getItem(SLOT_TARGET)
|
||||||
|
val bookStack = getItem(SLOT_BOOK)
|
||||||
|
|
||||||
|
val originalEnchantments = EnchantmentHelper.getEnchantmentsForCrafting(mainStack).entrySet()
|
||||||
|
val (possible, impossible) = originalEnchantments.partition { targetStack.supportsEnchantment(it.key) }
|
||||||
|
|
||||||
|
val possibleEnchantments = ItemEnchantments.Mutable(ItemEnchantments.EMPTY).apply {
|
||||||
|
possible.forEach{
|
||||||
|
set(it.key, it.intValue)
|
||||||
|
}
|
||||||
|
}.toImmutable()
|
||||||
|
val impossibleEnchantments = ItemEnchantments.Mutable(ItemEnchantments.EMPTY).apply {
|
||||||
|
impossible.forEach{
|
||||||
|
set(it.key, it.intValue)
|
||||||
|
}
|
||||||
|
}.toImmutable()
|
||||||
|
|
||||||
|
if (possible.isNotEmpty()) {
|
||||||
|
EnchantmentHelper.setEnchantments(targetStack, possibleEnchantments)
|
||||||
|
}
|
||||||
|
if (bookStack.isEmpty) {
|
||||||
|
setItem(SLOT_MAIN, mainStack.apply {
|
||||||
|
set(DataComponents.ENCHANTMENTS, impossibleEnchantments)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setItem(SLOT_MAIN, mainStack.apply {
|
||||||
|
set(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY)
|
||||||
|
})
|
||||||
|
setItem(SLOT_BOOK, ItemStack(Items.ENCHANTED_BOOK).apply {
|
||||||
|
EnchantmentHelper.setEnchantments(this, impossibleEnchantments)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resetProcessing()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetProcessing() {
|
||||||
|
processTime = 0
|
||||||
|
totalTime = 0
|
||||||
|
isProcessing = false
|
||||||
|
setChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package xyz.nuark.mcmod.enct.datagen
|
||||||
|
|
||||||
|
import net.minecraft.core.HolderLookup
|
||||||
|
import net.minecraft.data.DataGenerator
|
||||||
|
import net.minecraft.data.PackOutput
|
||||||
|
import net.neoforged.bus.api.SubscribeEvent
|
||||||
|
import net.neoforged.fml.common.EventBusSubscriber
|
||||||
|
import net.neoforged.neoforge.data.event.GatherDataEvent
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
@EventBusSubscriber
|
||||||
|
object DataGenerators {
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
fun gatherData(event: GatherDataEvent) {
|
||||||
|
val generator: DataGenerator = event.generator
|
||||||
|
val packOutput: PackOutput = generator.packOutput
|
||||||
|
val registries: CompletableFuture<HolderLookup.Provider> = event.lookupProvider
|
||||||
|
|
||||||
|
if (event.includeServer()) {
|
||||||
|
generator.addProvider(true, ModRecipeProvider(packOutput, registries))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package xyz.nuark.mcmod.enct.datagen
|
||||||
|
|
||||||
|
import xyz.nuark.mcmod.enct.block.ModBlocks
|
||||||
|
import net.minecraft.core.HolderLookup
|
||||||
|
import net.minecraft.data.PackOutput
|
||||||
|
import net.minecraft.data.recipes.RecipeCategory
|
||||||
|
import net.minecraft.data.recipes.RecipeOutput
|
||||||
|
import net.minecraft.data.recipes.RecipeProvider
|
||||||
|
import net.minecraft.data.recipes.ShapedRecipeBuilder
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
|
class ModRecipeProvider(
|
||||||
|
output: PackOutput,
|
||||||
|
registries: CompletableFuture<HolderLookup.Provider>
|
||||||
|
) : RecipeProvider(output, registries) {
|
||||||
|
|
||||||
|
override fun buildRecipes(recipeOutput: RecipeOutput) {
|
||||||
|
ShapedRecipeBuilder.shaped(RecipeCategory.REDSTONE, ModBlocks.ENCHANTMENT_TRANSFERRER_ITEM.get())
|
||||||
|
.define('I', Items.IRON_BLOCK)
|
||||||
|
.define('B', Items.BLAZE_ROD)
|
||||||
|
.define('E', Items.ENCHANTING_TABLE)
|
||||||
|
.pattern("III")
|
||||||
|
.pattern("BEB")
|
||||||
|
.pattern("III")
|
||||||
|
.unlockedBy("has_ench_table", has(Items.ENCHANTING_TABLE))
|
||||||
|
.save(recipeOutput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
package xyz.nuark.mcmod.enct.menu
|
||||||
|
|
||||||
|
import xyz.nuark.mcmod.enct.Enchantmenttransfer
|
||||||
|
import xyz.nuark.mcmod.enct.block.entity.EnchantmentTransferrerBlockEntity
|
||||||
|
import net.minecraft.world.Container
|
||||||
|
import net.minecraft.world.entity.player.Inventory
|
||||||
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
|
import net.minecraft.world.inventory.ContainerData
|
||||||
|
import net.minecraft.world.inventory.SimpleContainerData
|
||||||
|
import net.minecraft.world.inventory.Slot
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
import net.minecraft.world.item.enchantment.EnchantmentHelper
|
||||||
|
import xyz.nuark.mcmod.enct.block.entity.EnchantmentTransferrerBlockEntity.Companion.CHARGE_VALUES
|
||||||
|
|
||||||
|
class EnchantmentTransferrerMenu(
|
||||||
|
containerId: Int,
|
||||||
|
private val playerInventory: Inventory,
|
||||||
|
private val container: Container,
|
||||||
|
private val data: ContainerData = SimpleContainerData(4)
|
||||||
|
) : AbstractContainerMenu(Enchantmenttransfer.ENCHANTMENT_TRANSFERRER_MENU_TYPE.value(), containerId) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
checkContainerSize(container, EnchantmentTransferrerBlockEntity.TOTAL_SLOTS)
|
||||||
|
checkContainerDataCount(data, 4)
|
||||||
|
|
||||||
|
// Block inventory slots
|
||||||
|
addSlot(object : Slot(container, EnchantmentTransferrerBlockEntity.SLOT_MAIN, 35, 23) {
|
||||||
|
override fun mayPlace(stack: ItemStack): Boolean = EnchantmentHelper.hasAnyEnchantments(stack)
|
||||||
|
})
|
||||||
|
addSlot(object : Slot(container, EnchantmentTransferrerBlockEntity.SLOT_BOOK, 65, 23) {
|
||||||
|
override fun mayPlace(stack: ItemStack): Boolean = stack.item == Items.BOOK || stack.item == Items.ENCHANTED_BOOK
|
||||||
|
|
||||||
|
override fun getMaxStackSize(): Int = 1
|
||||||
|
})
|
||||||
|
addSlot(object : Slot(container, EnchantmentTransferrerBlockEntity.SLOT_TARGET, 124, 23) {
|
||||||
|
override fun mayPlace(stack: ItemStack): Boolean = !EnchantmentHelper.hasAnyEnchantments(stack) && EnchantmentHelper.canStoreEnchantments(stack)
|
||||||
|
})
|
||||||
|
addSlot(object : Slot(container, EnchantmentTransferrerBlockEntity.SLOT_FUEL, 3, 23) {
|
||||||
|
override fun mayPlace(stack: ItemStack): Boolean = CHARGE_VALUES.containsKey(stack.item)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Player inventory slots
|
||||||
|
for (row in 0 until 3) {
|
||||||
|
for (col in 0 until 9) {
|
||||||
|
addSlot(Slot(playerInventory, col + row * 9 + 9, 8 + col * 18, 72 + row * 18))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Player hotbar
|
||||||
|
for (col in 0 until 9) {
|
||||||
|
addSlot(Slot(playerInventory, col, 8 + col * 18, 130))
|
||||||
|
}
|
||||||
|
|
||||||
|
addDataSlots(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stillValid(player: Player): Boolean {
|
||||||
|
return container.stillValid(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun quickMoveStack(player: Player, index: Int): ItemStack {
|
||||||
|
var movedStack = ItemStack.EMPTY
|
||||||
|
val slot = this.slots[index]
|
||||||
|
|
||||||
|
if (slot.hasItem()) {
|
||||||
|
val slotStack = slot.item
|
||||||
|
movedStack = slotStack.copy()
|
||||||
|
|
||||||
|
if (index < EnchantmentTransferrerBlockEntity.TOTAL_SLOTS) {
|
||||||
|
if (!this.moveItemStackTo(slotStack, EnchantmentTransferrerBlockEntity.TOTAL_SLOTS, this.slots.size, true)) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val item = slotStack.item
|
||||||
|
|
||||||
|
if (CHARGE_VALUES.containsKey(item)) {
|
||||||
|
if (!this.moveItemStackTo(slotStack, EnchantmentTransferrerBlockEntity.SLOT_FUEL, EnchantmentTransferrerBlockEntity.SLOT_FUEL+1, false)) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!this.moveItemStackTo(slotStack, 0, EnchantmentTransferrerBlockEntity.SLOT_FUEL, false)) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slotStack.isEmpty) {
|
||||||
|
slot.setByPlayer(ItemStack.EMPTY)
|
||||||
|
} else {
|
||||||
|
slot.setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slotStack.count == movedStack.count) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
slot.onTake(player, slotStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
return movedStack
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCharge(): Int = data.get(0)
|
||||||
|
fun getProcessTime(): Int = data.get(1)
|
||||||
|
fun getTotalTime(): Int = data.get(2)
|
||||||
|
fun isProcessing(): Boolean = data.get(3) == 1
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
package xyz.nuark.mcmod.enct.screen
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.GuiGraphics
|
||||||
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
|
||||||
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.resources.ResourceLocation
|
||||||
|
import net.minecraft.world.entity.player.Inventory
|
||||||
|
import xyz.nuark.mcmod.enct.Enchantmenttransfer
|
||||||
|
import xyz.nuark.mcmod.enct.block.entity.EnchantmentTransferrerBlockEntity
|
||||||
|
import xyz.nuark.mcmod.enct.menu.EnchantmentTransferrerMenu
|
||||||
|
|
||||||
|
class EnchantmentTransferrerScreen(
|
||||||
|
menu: EnchantmentTransferrerMenu,
|
||||||
|
playerInventory: Inventory,
|
||||||
|
title: Component
|
||||||
|
) : AbstractContainerScreen<EnchantmentTransferrerMenu>(menu, playerInventory, title) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val BACKGROUND_LOCATION: ResourceLocation = ResourceLocation.fromNamespaceAndPath(Enchantmenttransfer.ID, "textures/gui/enchantment_transferrer.png")
|
||||||
|
val PROGRESS_GAUGE: ResourceLocation = ResourceLocation.fromNamespaceAndPath(Enchantmenttransfer.ID, "textures/gui/ets_gauge.png")
|
||||||
|
|
||||||
|
const val GAUGE_WIDTH = 117
|
||||||
|
const val GAUGE_HEIGHT = 7
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun init() {
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
imageWidth = 176
|
||||||
|
imageHeight = 154
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renderBg(guiGraphics: GuiGraphics, partialTick: Float, mouseX: Int, mouseY: Int) {
|
||||||
|
guiGraphics.blit(BACKGROUND_LOCATION, leftPos, topPos, 0, 0, imageWidth, imageHeight)
|
||||||
|
|
||||||
|
// Progress bar
|
||||||
|
if (menu.isProcessing()) {
|
||||||
|
val progress = menu.getProcessTime()
|
||||||
|
val total = menu.getTotalTime()
|
||||||
|
if (total > 0) {
|
||||||
|
val progressWidth = ((progress.toDouble() / total) * GAUGE_WIDTH).toInt()
|
||||||
|
guiGraphics.blit(PROGRESS_GAUGE, leftPos+33, topPos+5, 0f, 0f, progressWidth, GAUGE_HEIGHT, GAUGE_WIDTH, GAUGE_HEIGHT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Charge bar
|
||||||
|
val charge = menu.getCharge()
|
||||||
|
val maxCharge = EnchantmentTransferrerBlockEntity.MAX_CHARGE
|
||||||
|
if (charge > 0) {
|
||||||
|
val chargeWidth = ((charge.toDouble() / maxCharge) * GAUGE_WIDTH).toInt()
|
||||||
|
guiGraphics.blit(PROGRESS_GAUGE, leftPos+33, topPos+50, 0f, 0f, chargeWidth, GAUGE_HEIGHT, GAUGE_WIDTH, GAUGE_HEIGHT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renderLabels(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int) {
|
||||||
|
// No labels for me, thanks
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renderTooltip(guiGraphics: GuiGraphics, x: Int, y: Int) {
|
||||||
|
val xRange = (leftPos + 33)..(leftPos + 33 + GAUGE_WIDTH)
|
||||||
|
|
||||||
|
when (y) {
|
||||||
|
in (topPos + 5)..(topPos + 5 + GAUGE_HEIGHT) if x in xRange -> { // Over progress bar
|
||||||
|
val progress = menu.getProcessTime()
|
||||||
|
val total = menu.getTotalTime()
|
||||||
|
val processing = menu.isProcessing()
|
||||||
|
|
||||||
|
val status = if (total > 0 && processing) {
|
||||||
|
val perc = ((progress.toDouble() / total) * 100).toInt()
|
||||||
|
"$perc%"
|
||||||
|
} else if (total > 0) {
|
||||||
|
Component.translatable("container.enct.processing.waiting").withColor(0xFFFF00)
|
||||||
|
} else {
|
||||||
|
Component.translatable("container.enct.processing.idle").withColor(0x00FFFF)
|
||||||
|
}
|
||||||
|
|
||||||
|
guiGraphics.renderTooltip(
|
||||||
|
this.font,
|
||||||
|
Component.translatable("container.enct.processing", status),
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
)
|
||||||
|
}
|
||||||
|
in (topPos + 50)..(topPos + 50 + GAUGE_HEIGHT) if x in xRange -> { // Over charge bar
|
||||||
|
val charge = menu.getCharge()
|
||||||
|
guiGraphics.renderTooltip(
|
||||||
|
this.font,
|
||||||
|
Component.translatable("container.enct.charge", charge.toString()),
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val hoveredSlot = this.hoveredSlot
|
||||||
|
if (hoveredSlot != null && !hoveredSlot.hasItem()) { // Showing tooltips for empty slots
|
||||||
|
when (hoveredSlot.slotIndex) {
|
||||||
|
EnchantmentTransferrerBlockEntity.SLOT_MAIN -> guiGraphics.renderTooltip(
|
||||||
|
this.font,
|
||||||
|
Component.translatable("container.enct.info.main"),
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
)
|
||||||
|
EnchantmentTransferrerBlockEntity.SLOT_TARGET -> guiGraphics.renderTooltip(
|
||||||
|
this.font,
|
||||||
|
Component.translatable("container.enct.info.target"),
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
)
|
||||||
|
EnchantmentTransferrerBlockEntity.SLOT_BOOK -> guiGraphics.renderTooltip(
|
||||||
|
this.font,
|
||||||
|
Component.translatable("container.enct.info.book"),
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
)
|
||||||
|
EnchantmentTransferrerBlockEntity.SLOT_FUEL -> guiGraphics.renderTooltip(
|
||||||
|
this.font,
|
||||||
|
Component.translatable("container.enct.info.fuel"),
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.renderTooltip(guiGraphics, x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
|
||||||
|
renderBackground(guiGraphics, mouseX, mouseY, partialTick)
|
||||||
|
super.render(guiGraphics, mouseX, mouseY, partialTick)
|
||||||
|
renderTooltip(guiGraphics, mouseX, mouseY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "enct:block/enchantment_transferrer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
{
|
{
|
||||||
"itemGroup.enct": "Example Mod Tab",
|
"block.enct.enchantment_transferrer": "Enchantment Transferrer",
|
||||||
"block.enct.example_block": "Example Block",
|
"container.enct.enchantment_transferrer": "Enchantment Transferrer",
|
||||||
"item.enct.example_item": "Example Item"
|
"container.enct.charge": "Charge: %s",
|
||||||
|
"container.enct.processing": "Process: %s",
|
||||||
|
"container.enct.processing.waiting": "waiting",
|
||||||
|
"container.enct.processing.idle": "idle",
|
||||||
|
"container.enct.info.main": "Item with enchantments",
|
||||||
|
"container.enct.info.target": "Item to transfer enchantments to",
|
||||||
|
"container.enct.info.book": "Optional book",
|
||||||
|
"container.enct.info.fuel": "\"Charge\" fuel: copper, iron, gold, diamonds, redstone or netherite"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
src/main/resources/assets/enct/lang/ru_ru.json
Normal file
12
src/main/resources/assets/enct/lang/ru_ru.json
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"block.enct.enchantment_transferrer": "Переносчик зачарований",
|
||||||
|
"container.enct.enchantment_transferrer": "Переносчик зачарований",
|
||||||
|
"container.enct.charge": "Заряд: %s",
|
||||||
|
"container.enct.processing": "Процесс: %s",
|
||||||
|
"container.enct.processing.waiting": "ждём",
|
||||||
|
"container.enct.processing.idle": "спим",
|
||||||
|
"container.enct.info.main": "Зачарованный предмет",
|
||||||
|
"container.enct.info.target": "Цель для переноса",
|
||||||
|
"container.enct.info.book": "Опциональная книга",
|
||||||
|
"container.enct.info.fuel": "Топливо для \"заряда\": медь, железо, золото, алмазы, редстоун or незерит"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"parent": "block/cube",
|
||||||
|
"textures": {
|
||||||
|
"down": "enct:block/enchantment_transferrer_bottom",
|
||||||
|
"up": "enct:block/enchantment_transferrer_top",
|
||||||
|
"north": "enct:block/enchantment_transferrer_side",
|
||||||
|
"east": "enct:block/enchantment_transferrer_side",
|
||||||
|
"south": "enct:block/enchantment_transferrer_side",
|
||||||
|
"west": "enct:block/enchantment_transferrer_side",
|
||||||
|
"particle": "enct:block/enchantment_transferrer_top"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"parent": "enct:block/enchantment_transferrer"
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
BIN
src/main/resources/assets/enct/textures/gui/ets_gauge.png
Normal file
BIN
src/main/resources/assets/enct/textures/gui/ets_gauge.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 221 B |
Loading…
Add table
Add a link
Reference in a new issue