сборОЧКА

This commit is contained in:
Koshak_Mine 2025-02-07 01:03:28 +03:00
commit 010856f3ae
835 changed files with 31583 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Zoomify-2.14.2+1.20.1.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bobby-5.0.1.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
# Disable autocrlf on generated files, they always generate with LF
# Add any extra files or paths here to make git stop saying they
# are changed when only line endings change.
src/generated/**/.cache/cache text eol=lf
src/generated/**/*.json text eol=lf

View File

@ -0,0 +1,19 @@
---
name: Fabric Bug report
about: Create bug template
title: ''
labels: bug, fabric
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
**Additional context**
- Mod version:
- Fabric version:
- Create version:

View File

@ -0,0 +1,19 @@
---
name: Forge Bug report
about: Create bug template
title: ''
labels: bug, forge
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
**Additional context**
- Mod version:
- Forge version:
- Create version:

View File

@ -0,0 +1,10 @@
---
name: Suggestion
about: Suggest an idea for this project
title: ''
labels: suggestion
assignees: ''
---

View File

@ -0,0 +1,43 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Java CI with Gradle
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'adopt'
- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- uses: actions/upload-artifact@v2
with:
name: Package
path: build/libs
- name: Cleanup Gradle Cache
# Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
# Restoring these files from a GitHub Actions cache might cause problems for future builds.
run: rm -f ~/.gradle/caches/modules-2/modules-2.lock & rm -f ~/.gradle/caches/modules-2/gc.properties

View File

@ -0,0 +1,22 @@
# eclipse
bin
*.launch
.settings
.metadata
.classpath
.project
# idea
out
*.ipr
*.iws
*.iml
.idea
# gradle
build
.gradle
# other
eclipse
run

View File

@ -0,0 +1,6 @@
{
"ExpandedNodes": [
""
],
"PreviewInSolutionExplorer": false
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -0,0 +1,277 @@
# Create Crafts & Additions: Computercraft Peripheral API
Version 1.1
Supported Blocks:
- [Electric Motor](#electric-motor)
- [Accumulator](#accumulator)
- [Portable Energy Interface](#portable-energy-interface-pei)
- [Redstone Relay](#redstone-relay)
- [Digital Adapter](#digital-adapter)
- [Rotational Speed Controller](#rotational-speed-controller)
- [Stressometer](#stressometer)
- [Speedometer](#speedometer)
- [Rope, Hose, and Elevator Pulley](#pulleys)
- [Elevator Pulley](#elevator-pulley)
- [Mechanical Piston](#mechanical-piston)
- [Mechanical Bearing](#mechanical-bearing)
- [Display Link](#display-link)
- [Other](#other)
## Other Languages
[简体中文 (Simplified Chinese)](COMPUTERCRAFT_zh-CN.md)
# Electric Motor
To set the speed of the Electric Motor, call `setSpeed(rpm)` where the argument *rpm* is a number between `-256` and `256`. The function will throw an exception if it is called too many times per second.
```lua
motor.setSpeed(rpm)
```
The function `stop()` is a shorthand for `setSpeed(0)`.
```lua
motor.stop()
```
In the following example, the motor attached to the left of the computer will rotate at 32RPM for 5 seconds and then stop.
```lua
local motor = peripheral.wrap("left")
motor.setSpeed(32)
sleep(5)
motor.stop()
```
The function `rotate(degrees, [rpm])` will return the time it will take to rotate the shaft by the argument *degrees* at the current speed. If the optional argument *rpm* is given it will set the speed of the motor and return the rotation time at the new speed.
```lua
motor.setSpeed(32)
sleep(motor.rotate(90))
motor.stop()
```
In the following example, the motor will first rotate 180 degrees in the clockwise direction, then 180 degrees at half the speed in the anti-clockwise direction and then finaly stop.
```lua
local motor = peripheral.wrap("left")
sleep(motor.rotate(180, 32))
sleep(motor.rotate(-180, 16))
motor.stop()
```
The function `translate(blocks, [rpm])` will return the time it will take to rotate the shaft to push a piston or gantry shaft by distance given by the argument *blocks* at the current speed. If the optional argument *rpm* is given it will set the speed of the motor and return the action time at the new speed.
```lua
motor.setSpeed(32)
sleep(motor.translate(5))
motor.stop()
```
In the following example, the motor attached to a piston will extend the piston by 5 blocks, stop for a second, retract, and then finally stop.
```lua
local motor = peripheral.wrap("left")
sleep(motor.translate(5, 32))
sleep(1)
sleep(motor.translate(-5, 32))
motor.stop()
```
The function `getSpeed()` will return the current motor speed.
```lua
local rpm = motor.getSpeed()
```
The function `getStressCapacity()` will return the produced stress capacity (output su).
```lua
local su = motor.getStressCapacity()
```
The function `getEnergyConsumption()` will return the motor energy consumption in FE/t.
```lua
local fe = motor.getEnergyConsumption()
```
The function `getMaxInsert()` will return the Motor max input in fe.
```lua
local fe = motor.getMaxInsert()
```
The function `getMaxExtract()` will return the Motor max output in fe (Always 0).
```lua
local fe = motor.getMaxExtract()
```
The function `getType()` will return the motor peripheral name, which will always be "electric_motor".
```lua
print("Peripheral: " .. motor.getType())
```
# Accumulator
In the following example, we get the peripheral of an Accumulator on the left.
```lua
local accumulator = peripheral.wrap("left")
```
The function `getEnergy()` will return the accumulator total stored charge in fe.
```lua
local fe = accumulator.getEnergy()
```
The function `getCapacity()` will return the accumulator total capacity in fe.
```lua
local fe = accumulator.getCapacity()
```
The function `getPercent()` will return the accumulator total charge in relation to the total capacity in percent.
```lua
local percent = accumulator.getPercent()
```
The function `getMaxInsert()` will return the accumulator max input per block face in fe.
```lua
local fe = accumulator.getMaxInsert()
```
The function `getMaxExtract()` will return the accumulator max output per block face in fe.
```lua
local fe = accumulator.getMaxExtract()
```
The function `getHeight()` will return the accumulator height in block.
```lua
local blocks = accumulator.getHeight()
```
The function `getWidth()` will return the accumulator width in block.
```lua
local blocks = accumulator.getWidth()
```
The function `getType()` will return the accumulator peripheral name, which will always be "modular_accumulator".
```lua
print("Peripheral: " .. accumulator.getType())
```
# Portable Energy Interface (PEI)
In the following example, we get the peripheral of a PEI on the left.
```lua
local pei = peripheral.wrap("left")
```
The function `getEnergy()` will return the connected contraption total stored charge in fe, (-1 if not connected).
```lua
local fe = pei.getEnergy()
```
The function `getCapacity()` will return the connected contraption total capacity in fe, (-1 if not connected).
```lua
local fe = pei.getCapacity()
```
The function `isConnected()` will return true if a contraption is connected.
```lua
local connected = pei.isConnected()
```
The function `getMaxInsert()` will return the PEI max input in fe.
```lua
local fe = accumulator.getMaxInsert()
```
The function `getMaxExtract()` will return the PEI max output in fe.
```lua
local fe = accumulator.getMaxExtract()
```
The function `getType()` will return the PEI peripheral name, which will always be "portable_energy_interface".
```lua
print("Peripheral: " .. pei.getType())
```
# Redstone Relay
In the following example, we get the peripheral of a Redstone Relay on the left.
```lua
local relay = peripheral.wrap("left")
```
The function `getMaxInsert()` will return the Relay max input in fe.
```lua
local fe = relay.getMaxInsert()
```
The function `getMaxExtract()` will return the Relay max output in fe.
```lua
local fe = relay.getMaxExtract()
```
The function `getThroughput()` will return the current throughput in fe.
```lua
local fe = relay.getThroughput()
```
The function `isPowered()` will return the redstone state of the Relay.
```lua
local powered = relay.isPowered()
```
The function `getType()` will return the Relay peripheral name, which will always be "redstone_relay".
```lua
print("Peripheral: " .. relay.getType())
```
# Digital Adapter
In the following example, we get the peripheral of a Digital Adapter on the left.
```lua
local da = peripheral.wrap("left")
```
The function `getType()` will return the Adapter peripheral name, which will always be "digital_adapter".
```lua
print("Peripheral: " .. da.getType())
```
### Rotational Speed Controller
The function `setTargetSpeed(side, speed)` will set the target speed of a Rotation Speed Controller attached to the side of a Digital Adapter.
```lua
da.setTargetSpeed("top", 64)
```
The function `getTargetSpeed(side, speed)` will get the target speed of a Rotation Speed Controller attached to the side of a Digital Adapter.
```lua
local speed = da.getTargetSpeed("top")
```
### Stressometer
The function `getKineticStress(side)` will get the stress of a Stressometer attached to the side of a Digital Adapter.
```lua
local stress = da.getKineticStress("bottom")
```
The function `getKineticCapacity(side)` will get the stress capacity of a Stressometer attached to the side of a Digital Adapter.
```lua
local capacity = da.getKineticCapacity("bottom")
```
### Speedometer
The function `getKineticSpeed(side)` will get the speed of a Speedometer attached to the side of a Digital Adapter.
```lua
local speed = da.getKineticSpeed("north")
```
The function `getKineticTopSpeed()` will get the top speed as set by Create.
```lua
local topSpeed = da.getKineticTopSpeed()
```
### Pulleys
The function `getPulleyDistance(side)` will get the extended distance of a Rope, Hose, or Elevator -Pulley attached to the side of a Digital Adapter.
```lua
local blocks = da.getPulleyDistance("south")
```
### Elevator Pulley
The function `getElevatorFloor(side)` will get the current floor index of an Elevator Pulley attached to the side of a Digital Adapter.
```lua
local floor = da.getElevatorFloor("south")
```
The function `getElevatorFloors(side)` will get the number of floors of an Elevator Pulley attached to the side of a Digital Adapter.
```lua
local floorCount = da.getElevatorFloors("south")
```
The function `getElevatorFloorName(side, index)` will get floor name at floor index of a Elevator Pulley attached to the side of a Digital Adapter.
```lua
local floorName = da.getElevatorFloorName("south", 0)
```
The function `gotoElevatorFloor(side, index)` will trigger a Elevator Pulley attached to the side of a Digital Adapter to move to the given floor index and returns the delta-y to move.
```lua
local floorName = da.gotoElevatorFloor("south", 0)
```
### Mechanical Piston
The function `getPistonDistance(side)` will get the extended distance of a Mechanical Piston attached to the side of a Digital Adapter.
```lua
local blocks = da.getPistonDistance("east")
```
### Mechanical Bearing
The function `getBearingAngle(side)` will get the angle of a Mechanical Bearing attached to the side of a Digital Adapter.
```lua
local degrees = da.getBearingAngle("west")
```
### Display Link
The function `print(text)` will print a string on the currently selected line to an internal buffer which can be read by a Display Link and put on a Display Board, print will increment the currently selected line.
```lua
print("Hello World!")
```
The function `clearLine()` will clear the text on the currently selected line.
The function `clear()` will clear all the text on all lines.
The function `getLine()` will return the currently selected line (starts at 1).
The function `setLine(line)` will set the currently selected line to *line* (starts at 1).
```lua
da.print("Text on first line")
da.print("Text on second line")
da.setLine(1)
da.print("Text on first line again")
```
The function `getMaxLines()` will return the max number of lines that can be displayable using the Digital Adapter (will always return 16).
### Other
The function `getDurationDistance(blocks, rpm)` will return the time needed to push a Mechanical Piston, Pulley or Gantry a number of blocks at the given rpm.
The function `getDurationAngle(degrees, rpm)` will return the time needed to rotate a Mechanical Bearing by a number of degrees at the given rpm.

View File

@ -0,0 +1,258 @@
# Create Crafts & Additions: Computercraft Peripheral API 中文版本
>If you are using English, please view [COMPUTERCRAFT.md](COMPUTERCRAFT.md). Links to other languages (if any) are in that file too.
>本文件为纯手动翻译,如有不足或错误欢迎修改。
>我已经尽量保证译名与模组翻译文件同步。
>内容可能不是最新,请以英文版本为准。
>This document is a purely manual translation. If there are any shortcomings or errors, please feel free to modify them.
>I have tried my best to ensure that the translated name is synchronized with the mod translation file.
>The content may not be the latest, please refer to the English version.
Version 1.1
支持的方块:
- [电动马达](#电动马达)
- [蓄电池](#蓄电池)
- [移动式能量接口](#移动式能量接口-pei)
- [红石继电器](#红石继电器)
- [数字适配器](#数字适配器)
- [速度表](#速度表)
- [应力表](#应力表)
- [绳索滑轮](#绳索滑轮)
- [动力活塞](#动力活塞)
- [动力轴承](#动力轴承)
- [显示链接器](#显示链接器)
- [Other](#other)
# 电动马达
可以通过调用 `setSpeed(rpm)` 设置电动马达的速度。参数 *rpm* 是一个介于 `-256``256` 之间的数字。如果此函数在每秒被调用的次数过多,它会抛出一个异常。
```lua
motor.setSpeed(rpm)
```
函数 `stop()``setSpeed(0)` 的简写。
```lua
motor.stop()
```
在如下的例子中,连接到电脑左侧的电动马达会以 32RPM 旋转 5s 然后停止。
```lua
local motor = peripheral.wrap("left")
motor.setSpeed(32)
sleep(5)
motor.stop()
```
函数 `rotate(degrees, [rpm])` 会返回以当前速度将轴旋转 *degrees* 角度所需的时间。如果传递了可选的 *rpm* 参数,它会将电动马达设置到该速度并返回以新的速度将轴旋转 *degrees* 角度所需的时间。
```lua
motor.setSpeed(32)
sleep(motor.rotate(90))
motor.stop()
```
在如下的例子中电机将首先沿顺时针方向旋转180度然后沿逆时针方向以一半速度旋转180度最终停止。
```lua
local motor = peripheral.wrap("left")
sleep(motor.rotate(180, 32))
sleep(motor.rotate(-180, 16))
motor.stop()
```
函数 `translate(blocks, [rpm])` 会返回以当前速度推动动力活塞或起重机移动 *blocks* 方块所需的时间。如果传递了可选的 *rpm* 参数,它会将电动马达设置到该速度并返回以新的速度完成动作所需的时间。
```lua
motor.setSpeed(32)
sleep(motor.translate(5))
motor.stop()
```
在如下的例子中,连接到动力活塞上的电机将使动力活塞推出 5 个方块的距离,等待一秒钟,缩回,最终停止。
```lua
local motor = peripheral.wrap("left")
sleep(motor.translate(5, 32))
sleep(1)
sleep(motor.translate(-5, 32))
motor.stop()
```
函数 `getSpeed()` 会返回当前电动马达的速度。
```lua
local rpm = motor.getSpeed()
```
函数 `getStressCapacity()` 将返回产生的应力单位su
```lua
local su = motor.getStressCapacity()
```
函数 `getEnergyConsumption()` 将返回电动马达当前能耗单位FE/t
```lua
local fe = motor.getEnergyConsumption()
```
函数 `getMaxInsert()` 将返回电动马达的最大输入单位FE
```lua
local fe = motor.getMaxInsert()
```
函数 `getMaxExtract()` 将返回以FE为单位的电动马达最大输出始终为0
```lua
local fe = motor.getMaxExtract()
```
函数 `getType()` 将返回电动马达的设备名称,该名称将始终为 "electric_motor"。
```lua
print("Peripheral: " .. motor.getType())
```
# 蓄电池
在如下的例子中,我们获取左侧蓄电池的外围设备句柄。
```lua
local accumulator = peripheral.wrap("left")
```
函数 `getEnergy()` 会返回蓄电池已经存储的能量单位FE
```lua
local fe = accumulator.getEnergy()
```
函数 `getCapacity()` 会返回蓄电池的总容量单位FE
```lua
local fe = accumulator.getCapacity()
```
函数 `getPercent()` 将返回蓄电池相对于总容量的总充电量(单位:%)。
```lua
local percent = accumulator.getPercent()
```
函数 `getMaxInsert()` 将返回蓄电池每个方块表面的最大输入单位FE
```lua
local fe = accumulator.getMaxInsert()
```
函数 `getMaxExtract()` 将返回蓄电池每个方块表面的最大输出单位FE
```lua
local fe = accumulator.getMaxExtract()
```
函数 `getHeight()` 会返回蓄电池多方块结构的高度(单位:方块)。
```lua
local blocks = accumulator.getHeight()
```
函数 `getWidth()` 会返回蓄电池多方块结构的宽度(单位:块)。
```lua
local blocks = accumulator.getWidth()
```
函数 `getType()` 将返回蓄电池的设备名称,该名称将始终为 "modular_accumulator"。
```lua
print("Peripheral: " .. accumulator.getType())
```
# 移动式能量接口 (PEI)
在如下的例子中, 我们可以获得一个左侧 PEI 的外围设备接口。
```lua
local pei = peripheral.wrap("left")
```
函数 `getEnergy()` 会返回连接的可移动结构已经存储的能量(-1 如果没有连接单位FE
```lua
local fe = pei.getEnergy()
```
函数 `getCapacity()` 会返回连接的可移动结构的总容量(-1 如果没有连接单位FE
```lua
local fe = pei.getCapacity()
```
函数 `isConnected()` 会在有可移动结构连接时返回 true 。
```lua
local connected = pei.isConnected()
```
函数 `getMaxInsert()` 会返回 PEI 的最大输入单位FE
```lua
local fe = accumulator.getMaxInsert()
```
函数 `getMaxExtract()` 会返回 PEI 的最大输出单位FE
```lua
local fe = accumulator.getMaxExtract()
```
函数 `getType()` 将返回 PEI 的设备名称,该名称将始终为 "portable_energy_interface".
```lua
print("Peripheral: " .. pei.getType())
```
# 红石继电器
在如下的例子中, 我们可以获得一个左侧红石继电器的外围设备接口。
```lua
local relay = peripheral.wrap("left")
```
函数 `getMaxInsert()` 会返回继电器的最大输入单位FE
```lua
local fe = relay.getMaxInsert()
```
函数 `getMaxExtract()` 会返回继电器的最大输出单位FE
```lua
local fe = relay.getMaxExtract()
```
函数 `getThroughput()` 会返回继电器当前的流量单位FE
```lua
local fe = relay.getThroughput()
```
函数 `isPowered()` 会返回继电器的红石状态。
```lua
local powered = relay.isPowered()
```
函数 `getType()` 将返回红石继电器的外围设备名称,该名称将始终为 "redstone_relay".
```lua
print("Peripheral: " .. relay.getType())
```
函数 `getType()` 将返回数字适配器的外围设备名称,该名称将始终为 "digital_adapter"。
```lua
print("Peripheral: " .. da.getType())
```
### Rotation Speed Controller
函数 `setTargetSpeed(side, speed)` 可以设置数字适配器的 *side* 面上的 转速控制器`(create:rotation_speed_conroller)` 的目标转速到 *speed*
```lua
setTargetSpeed("top", 64)
```
函数 `getTargetSpeed(side, speed)` 可以获得数字适配器的 *side* 面上的 转速控制器 的目标转速到 *speed*
```lua
local speed = da.getTargetSpeed("top")
```
### 应力表
函数 `getKineticStress(side)` 可以获得数字适配器的 *side* 面上的 应力表`(create:stressometer)` 的当前应力。
```lua
local stress = da.getKineticStress("up")
```
函数 `getKineticCapacity(side)` 可以获得数字适配器的 *side* 面上的 应力表 的应力最大值。
```lua
local capacity = da.getKineticCapacity("up")
```
### 速度表
函数 `getKineticSpeed(side)` 可以获得数字适配器的 *side* 面上的 速度表`(create:speedometer)` 的转速。
```lua
local speed = da.getKineticSpeed("up")
```
### 绳索滑轮
函数 `getPulleyDistance(side)` 可以获得连接到数字适配器的 *side* 面的绳索滑轮的伸出长度。
```lua
local blocks = da.getPulleyDistance("south")
```
### 动力活塞
函数 `getPistonDistance(side)` 可以获得连接到数字适配器的 *side* 面的动力活塞的伸出长度。
```lua
local blocks = da.getPistonDistance("east")
```
### 动力轴承
函数 `getBearingAngle(side)` 可以获得连接到数字适配器的 *side* 面的动力轴承的角度。
```lua
local degrees = da.getBearingAngle("west")
```
### 显示链接器
函数 `print(text)` 将当前所选行上的字符串打印到内部缓冲区,该缓冲区可由 显示链接器`(create:display_link)` 读取并显示到 翻牌显示器`(create:display_board)` 上,打印将在当前所选行追加。
>_此段不保证完全准确因为我无法准确翻译最后一句。请以英文文档为准。_
```lua
print("Hello World!")
```
函数 `clearLine()` 将清除所选行的文本。
函数 `clear()` 将清除所有行的所有文本。
函数 `getLine()` 会返回当前选中的行(从 1 开始)。
函数 `setLine(line)` 会设置当前选中的行到 *line*(从 1 开始)。
```lua
da.print("Text on first line")
da.print("Text on second line")
da.setLine(1)
da.print("Text on first line again")
```
函数 `getMaxLines()` 将返回使用数字适配器可以显示的最大行数将始终返回16
### Other
The function `getDurationDistance(blocks, rpm)` will return the time needed to push a Mechanical Piston, Pulley or Gantry a number of blocks at the given rpm.
The function `getDurationAngle(degrees, rpm)` will return the time needed to rotate a Mechanical Bearing by a number of degrees at the given rpm.

View File

@ -0,0 +1,25 @@
MIT License
Copyright (c) 2024 MRH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This repository includes audio from:
- pixabay.com LICENSE: https://pixabay.com/service/license-summary/
- freesound.org LICENSE: https://creativecommons.org/publicdomain/zero/1.0/

View File

@ -0,0 +1,57 @@
# Create Crafts & Additions by MRH0
Addon to the Create mod by the Create Team.
Create Crafts & Aditions
Minecraft Forge Mod by MRH0
# Download
Minecraft 1.16, 1.17, 1.18, 1.19, 1.20
At: https://www.curseforge.com/minecraft/mc-mods/createaddition
# About
Create Crafts & Additions extends Create and acts as a bridge between electricity and kinetic energy from Create.
# Content
![Items](https://raw.githubusercontent.com/mrh0/createaddition/1.18.2/cca_20230412a.png)
- Electric Motor.
- Alternator.
- Rolling Mill.
- Creative Generator.
- Telsa Coil.
- Accumulator.
- Digital Adapter.
- Energy transport.
- Diamond Grit Sandpaper.
And more!
# License
Available under MIT the license more info at: https://tldrlegal.com/license/mit-license
MIT License
Copyright 2022 MRH0
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,2 @@
gradlew build
pause

View File

@ -0,0 +1,156 @@
//file:noinspection GroovyUnusedAssignment
plugins {
id 'fabric-loom' version '1.5-SNAPSHOT'
id 'eclipse'
id 'maven-publish'
//id 'io.github.juuxel.loom-quiltflower' version '1.+'
id 'org.quiltmc.quilt-mappings-on-loom' version '4.2.+'
}
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
version = project.mod_version
group = 'com.mrh0.createaddition'
archivesBaseName = "createaddition-fabric+${project.minecraft_version}"
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
loom {
sourceSets.main.resources { srcDir 'src/generated/resources' }
accessWidenerPath = file("src/main/resources/ca.accesswidener")
}
repositories {
maven {
name 'Shedman maven'
url 'https://maven.shedaniel.me/'
}
maven {
name 'blamejared'
url 'https://maven.blamejared.com'
}
maven { url = "https://api.modrinth.com/maven" }
maven { url = "https://mvn.devos.one/releases/" }
maven { url = "https://mvn.devos.one/snapshots/" }
maven { url = "https://maven.tterrag.com/" }
maven { url = "https://jitpack.io/" }
maven { url = "https://maven.terraformersmc.com/" }
maven {
url 'https://www.cursemaven.com'
content {
includeGroup "curse.maven"
}
}
maven {
url = "https://maven.jamieswhiteshirt.com/libs-release"
content {
includeGroup("com.jamieswhiteshirt")
}
}
maven { url = "https://maven.terraformersmc.com/" }
maven { url = "https://maven.cafeteria.dev/releases" }
maven {
name = 'Ladysnake Mods'
url = 'https://maven.ladysnake.org/releases'
}
/*maven {
name = "Progwml6 maven"
url = "https://dvs1.progwml6.com/files/maven/"
}*/
maven {
name = "ModMaven"
url = "https://modmaven.dev"
}
maven {
name = 'ParchmentMC'
url = 'https://maven.parchmentmc.org'
}
maven {
url "https://maven2.bai.lol"
content {
includeGroup "lol.bai"
includeGroup "mcp.mobius.waila"
}
}
maven { url = "https://maven.terraformersmc.com/" } // Mod Menu, Trinkets
//ComputerCraft
maven {
url "https://squiddev.cc/maven/"
content {
includeGroup("cc.tweaked")
includeModule("org.squiddev", "Cobalt")
}
}
maven { url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" } //forge config api port
}
dependencies {
minecraft("com.mojang:minecraft:${project.minecraft_version}")
mappings loom.layered {
it.officialMojangMappings()
it.parchment("org.parchmentmc.data:parchment-${project.minecraft_version}:${project.parchment_version}")
}
modImplementation("net.fabricmc:fabric-loader:${project.loader_version}")
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}+${project.minecraft_version}"
modImplementation("me.shedaniel:RoughlyEnoughItems-api-fabric:${project.rei_version}")
modImplementation("me.shedaniel:RoughlyEnoughItems-fabric:${project.rei_version}")
modCompileOnly("mezz.jei:jei-$minecraft_version-fabric:$jei_version") { transitive = false }
modCompileOnly("dev.emi:emi-fabric:1.0.9+1.20.1") { transitive = false }
modImplementation("dev.architectury:architectury-fabric:${project.architectury_version}")
modImplementation("dev.onyxstudios.cardinal-components-api:cardinal-components-base:${cardinal_components_version}")
modImplementation("com.simibubi.create:create-fabric-${project.minecraft_version}:" +
"${project.create_version}+mc${project.minecraft_version}")
modCompileOnly("cc.tweaked:cc-tweaked-$minecraft_version-fabric-api:$cc_tweaked_version")
modRuntimeOnly("cc.tweaked:cc-tweaked-$minecraft_version-fabric:$cc_tweaked_version")
modImplementation("appeng:appliedenergistics2-fabric:${project.ae2_version}")
modImplementation("com.tterrag.registrate_fabric:Registrate:MC${project.minecraft_version}-${project.registrate_version}")
modCompileOnly"mcp.mobius.waila:wthit-api:fabric-${wthit_version}"
modApi("me.shedaniel.cloth:cloth-config-fabric:${project.cloth_version}") {
exclude(group: "net.fabricmc.fabric-api")
}
include modApi('teamreborn:energy:2.3.0') {
exclude(group: "net.fabricmc.fabric-api")
}
modLocalRuntime("com.terraformersmc:modmenu:$modmenu_version")
}
processResources {
inputs.property "version", project.version
filesMatching("fabric.mod.json") {
expand "version": project.version
}
}
java {
withSourcesJar()
}
publishing {
publications {
mavenJava(MavenPublication) {
artifact jar
}
}
repositories {
maven {
url "file://${project.projectDir}/mcmodsrepo"
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -0,0 +1,3 @@
files:
- source: /src/main/resources/assets/createaddition/lang/en_us.json
translation: /src/main/resources/assets/createaddition/lang/%locale_with_underscore%.json

View File

@ -0,0 +1 @@
gradlew eclipse -Dorg.gradle.java.home="C:/Program Files/Java/jdk1.8.0_191"

View File

@ -0,0 +1,36 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false
# check these on https://fabricmc.net/develop/
minecraft_version = 1.20.1
loader_version = 0.16.10
fabric_api_version = 0.92.3
mod_version = 1.2.4
cardinal_components_version = 5.0.2
forgegradle_version = 5.1.+
mixingradle_version = 0.7-SNAPSHOT
mixin_version = 0.8.5
librarian_version = 1.+
shadow_version = 7.1.0
cursegradle_version = 1.4.0
create_version = 0.5.1-f-build.1335
registrate_version = 1.1.42
jei_version = 15.2.0.27
cloth_version=11.1.106
ae2_version = 15.0.7-beta
wthit_version = 8.3.1
cc_tweaked_version = 1.108.0
# https://ldtteam.jfrog.io/ui/native/parchmentmc-public/org/parchmentmc/data/parchment-1.18.1/BLEEDING-SNAPSHOT
parchment_version = 2023.08.20
# https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items/files
rei_version = 12.0.645
# https://www.curseforge.com/minecraft/mc-mods/forge-config-api-port-fabric/files
config_api_version = 4633444
# https://www.curseforge.com/minecraft/mc-mods/architectury-fabric
architectury_version = 9.1.12
# https://modrinth.com/mod/modmenu/versions
modmenu_version = 7.2.1

View File

@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -0,0 +1,249 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

View File

@ -0,0 +1,92 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,2 @@
gradlew runClient
pause

View File

@ -0,0 +1,8 @@
pluginManagement {
repositories {
maven { url = 'https://maven.fabricmc.net/' }
maven { url = "https://maven.quiltmc.org/repository/release" }
maven { url = 'https://server.bbkr.space/artifactory/libs-release/' }
gradlePluginPortal()
}
}

View File

@ -0,0 +1,118 @@
package com.mrh0.createaddition;
import com.mrh0.createaddition.blocks.liquid_blaze_burner.LiquidBlazeBurnerBlock;
import com.mrh0.createaddition.commands.CCApiCommand;
import com.mrh0.createaddition.compat.computercraft.ComputerCraftCompat;
import com.mrh0.createaddition.config.Config;
import com.mrh0.createaddition.event.GameEvents;
import com.mrh0.createaddition.groups.ModGroup;
import com.mrh0.createaddition.index.*;
import com.mrh0.createaddition.index.CASounds;
import com.mrh0.createaddition.network.CANetwork;
import com.mrh0.createaddition.trains.schedule.CASchedule;
import com.simibubi.create.content.fluids.tank.BoilerHeaters;
import com.simibubi.create.content.kinetics.BlockStressValues;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.foundation.data.CreateRegistrate;
import com.simibubi.create.foundation.item.ItemDescription;
import com.simibubi.create.foundation.item.KineticStats;
import com.simibubi.create.foundation.item.TooltipHelper;
import com.simibubi.create.foundation.item.TooltipModifier;
import com.simibubi.create.infrastructure.config.AllConfigs;
import fuzs.forgeconfigapiport.api.config.v2.ForgeConfigRegistry;
import io.github.fabricators_of_create.porting_lib.event.common.ModsLoadedCallback;
import me.pepperbell.simplenetworking.SimpleChannel;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.fml.config.ModConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.mojang.brigadier.CommandDispatcher;
import com.mrh0.createaddition.blocks.liquid_blaze_burner.LiquidBlazeBurnerBlock;
import com.mrh0.createaddition.commands.CCApiCommand;
import com.mrh0.createaddition.config.Config;
import com.mrh0.createaddition.groups.ModGroup;
import com.mrh0.createaddition.network.EnergyNetworkPacket;
import com.mrh0.createaddition.network.ObservePacket;
import com.simibubi.create.foundation.data.CreateRegistrate;
import com.simibubi.create.foundation.item.TooltipModifier;
import javax.annotation.Nullable;
public class CreateAddition implements ModInitializer{
public static final Logger LOGGER = LogManager.getLogger();
public static final String MODID = "createaddition";
public static boolean IE_ACTIVE = false;
public static boolean CC_ACTIVE = false;
public static boolean AE2_ACTIVE = false;
public static final CreateRegistrate REGISTRATE = CreateRegistrate.create(CreateAddition.MODID);
private static final String PROTOCOL = "1";
public static final SimpleChannel Network = new SimpleChannel(new ResourceLocation(MODID, "main"));
static {
REGISTRATE.setTooltipModifierFactory(item -> new ItemDescription.Modifier(item, TooltipHelper.Palette.STANDARD_CREATE)
.andThen(TooltipModifier.mapNull(KineticStats.create(item))));
}
@Override
public void onInitialize() {
ModsLoadedCallback.EVENT.register(envType -> setup());
CommandRegistrationCallback.EVENT.register(CCApiCommand::register);
ForgeConfigRegistry.INSTANCE.register(MODID, ModConfig.Type.COMMON, Config.COMMON_CONFIG);
Config.loadConfig(Config.COMMON_CONFIG, FabricLoader.getInstance().getConfigDir().resolve("createaddition-common.toml"));
IE_ACTIVE = FabricLoader.getInstance().isModLoaded("immersiveengineering");
CC_ACTIVE = FabricLoader.getInstance().isModLoaded("computercraft");
AE2_ACTIVE = FabricLoader.getInstance().isModLoaded("ae2");
CAArmInteractions.register();
CABlocks.register();
CABlockEntities.register();
CAItems.register();
CAFluids.register();
CAEffects.register();
CARecipes.register();
CASounds.register();
CASchedule.register();
ModGroup.register();
REGISTRATE.register();
// Setup events
GameEvents.initCommon();
CANetwork.initServer();
System.out.println("Create Crafts & Additions Initialized!");
}
private void setup() {
CAPotatoCannonProjectiles.register();
BlockStressValues.registerProvider(MODID, AllConfigs.server().kinetics.stressValues);
BoilerHeaters.registerHeater(CABlocks.LIQUID_BLAZE_BURNER.get(), (level, pos, state) -> {
BlazeBurnerBlock.HeatLevel value = state.getValue(LiquidBlazeBurnerBlock.HEAT_LEVEL);
if (value == BlazeBurnerBlock.HeatLevel.NONE) return -1;
if (value == BlazeBurnerBlock.HeatLevel.SEETHING) return 2;
if (value.isAtLeast(BlazeBurnerBlock.HeatLevel.FADING)) return 1;
return 0;
});
if(CC_ACTIVE){
ComputerCraftCompat.registerCompat();
}
}
public static ResourceLocation asResource(String path) {
return new ResourceLocation(MODID, path);
}
}

View File

@ -0,0 +1,32 @@
package com.mrh0.createaddition;
import com.mrh0.createaddition.event.ClientEventHandler;
import com.mrh0.createaddition.event.GameEvents;
import com.mrh0.createaddition.index.CABlocks;
import com.mrh0.createaddition.index.CAItemProperties;
import com.mrh0.createaddition.index.CAPartials;
import com.mrh0.createaddition.index.CAPonder;
import com.mrh0.createaddition.network.CANetwork;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.client.renderer.ItemBlockRenderTypes;
import net.minecraft.client.renderer.RenderType;
public class CreateAdditionClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
CANetwork.initClient();
GameEvents.initClient();
CAPonder.register();
//CAEntities.registerRenderers();
CAPartials.init();
CAItemProperties.register();
ClientTickEvents.START_WORLD_TICK.register(ClientEventHandler::playerRendererEvent);
RenderType cutout = RenderType.cutoutMipped();
BlockRenderLayerMap.INSTANCE.putBlocks(cutout, CABlocks.TESLA_COIL.get(), CABlocks.BARBED_WIRE.get(), CABlocks.SMALL_LIGHT_CONNECTOR.get());
}
}

View File

@ -0,0 +1,156 @@
package com.mrh0.createaddition.blocks.accumulator;
import com.mrh0.createaddition.energy.IWireNode;
import com.mrh0.createaddition.energy.NodeRotation;
import com.mrh0.createaddition.index.CABlockEntities;
import com.mrh0.createaddition.util.IComparatorOverride;
import com.simibubi.create.content.contraptions.ITransformableBlock;
import com.simibubi.create.content.contraptions.StructureTransform;
import com.simibubi.create.content.equipment.wrench.IWrenchable;
import com.simibubi.create.foundation.block.IBE;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.nbt.CompoundTag;
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.item.context.BlockPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class AccumulatorBlock extends Block implements IBE<AccumulatorBlockEntity>, IWrenchable, ITransformableBlock {
public static final VoxelShape ACCUMULATOR_SHAPE_MAIN = Block.box(0, 0, 0, 16, 12, 16);
public static final VoxelShape ACCUMULATOR_SHAPE_X = Shapes.or(ACCUMULATOR_SHAPE_MAIN, Block.box(1, 0, 6, 5, 16, 10), Block.box(11, 0, 6, 15, 16, 10));
public static final VoxelShape ACCUMULATOR_SHAPE_Z = Shapes.or(ACCUMULATOR_SHAPE_MAIN, Block.box(6, 0, 1, 10, 16, 5), Block.box(6, 0, 11, 10, 16, 15));
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
public AccumulatorBlock(Properties properties) {
super(properties);
this.registerDefaultState(this.defaultBlockState()
.setValue(FACING, Direction.NORTH)
.setValue(NodeRotation.ROTATION, NodeRotation.NONE));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter worlIn, BlockPos pos, CollisionContext context) {
Axis axis = state.getValue(FACING).getAxis();
return axis == Axis.X ? ACCUMULATOR_SHAPE_X : ACCUMULATOR_SHAPE_Z;
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> builder) {
builder.add(FACING, NodeRotation.ROTATION);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext c) {
return defaultBlockState().setValue(FACING, c.getPlayer().isShiftKeyDown() ? c.getHorizontalDirection().getCounterClockWise() : c.getHorizontalDirection().getClockWise());
}
@Override
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity entity, ItemStack stack) {
BlockEntity te = world.getBlockEntity(pos);
if(te != null) {
if(te instanceof AccumulatorBlockEntity) {
AccumulatorBlockEntity ate = (AccumulatorBlockEntity) te;
if(stack.hasTag()) {
CompoundTag nbt = stack.getTag();
if(nbt.contains("energy"))
ate.setEnergy(nbt.getInt("energy"));
}
}
}
super.setPlacedBy(world, pos, state, entity, stack);
}
@Override
public void playerWillDestroy(Level worldIn, BlockPos pos, BlockState state, Player player) {
super.playerWillDestroy(worldIn, pos, state, player);
if (worldIn.isClientSide()) return;
BlockEntity te = worldIn.getBlockEntity(pos);
if (te == null) return;
if (!(te instanceof IWireNode cte)) return;
cte.dropWires(worldIn, !player.isCreative());
}
@Override
public InteractionResult onSneakWrenched(BlockState state, UseOnContext c) {
BlockEntity te = c.getLevel().getBlockEntity(c.getClickedPos());
if(te == null)
return IWrenchable.super.onSneakWrenched(state, c);
if(!(te instanceof IWireNode))
return IWrenchable.super.onSneakWrenched(state, c);
IWireNode cte = (IWireNode) te;
if (!c.getLevel().isClientSide())
cte.dropWires(c.getLevel(), c.getPlayer(), !c.getPlayer().isCreative());
return IWrenchable.super.onSneakWrenched(state, c);
}
@Override
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
public int getAnalogOutputSignal(BlockState blockState, Level worldIn, BlockPos pos) {
return IComparatorOverride.getComparatorOverride(worldIn, pos);
}
@Override
public BlockState rotate(BlockState state, Rotation direction) {
return state.setValue(FACING, direction.rotate(state.getValue(FACING)));
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return state.setValue(FACING, mirror.mirror(state.getValue(FACING)));
}
@Override
public BlockState transform(BlockState state, StructureTransform transform) {
NodeRotation rotation = NodeRotation.get(transform.rotationAxis, transform.rotation);
// Handle default rotation & mirroring.
if (transform.mirror != null) state = mirror(state, transform.mirror);
if (transform.rotationAxis == Axis.Y) state = rotate(state, transform.rotation);
// Set the rotation state, which will be used to update the nodes.
return state.setValue(NodeRotation.ROTATION, rotation);
}
@Override
public Class<AccumulatorBlockEntity> getBlockEntityClass() {
return AccumulatorBlockEntity.class;
}
@Override
public BlockEntityType<? extends AccumulatorBlockEntity> getBlockEntityType() {
return CABlockEntities.ACCUMULATOR.get();
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return CABlockEntities.ACCUMULATOR.create(pos, state);
}
}

View File

@ -0,0 +1,474 @@
package com.mrh0.createaddition.blocks.accumulator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.mrh0.createaddition.CreateAddition;
import com.mrh0.createaddition.blocks.connector.ConnectorType;
import com.mrh0.createaddition.config.Config;
import com.mrh0.createaddition.energy.*;
import com.mrh0.createaddition.energy.network.EnergyNetwork;
import com.mrh0.createaddition.index.CABlocks;
import com.mrh0.createaddition.network.EnergyNetworkPacket;
import com.mrh0.createaddition.network.IObserveTileEntity;
import com.mrh0.createaddition.network.ObservePacket;
import com.mrh0.createaddition.util.IComparatorOverride;
import com.mrh0.createaddition.util.Util;
import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation;
import io.github.fabricators_of_create.porting_lib.transfer.TransferUtil;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings("UnstableApiUsage")
public class AccumulatorBlockEntity extends BaseElectricBlockEntity implements IWireNode, IHaveGoggleInformation, IComparatorOverride, IObserveTileEntity {
private final Set<LocalNode> wireCache = new HashSet<>();
private final LocalNode[] localNodes;
private final IWireNode[] nodeCache;
private boolean wasContraption = false;
private boolean firstTick = true;
public static Vec3 OFFSET_NORTH = new Vec3( 0f, 9f/16f, -5f/16f);
public static Vec3 OFFSET_WEST = new Vec3( -5f/16f, 9f/16f, 0f);
public static Vec3 OFFSET_SOUTH = new Vec3( 0f, 9f/16f, 5f/16f);
public static Vec3 OFFSET_EAST = new Vec3( 5f/16f, 9f/16f, 0f);
public static final int NODE_COUNT = 8;
public AccumulatorBlockEntity(BlockEntityType<?> tileEntityTypeIn, BlockPos pos, BlockState state) {
super(tileEntityTypeIn, pos, state);
setLazyTickRate(20);
this.localNodes = new LocalNode[getNodeCount()];
this.nodeCache = new IWireNode[getNodeCount()];
}
@Override
public long getCapacity() {
return Config.ACCUMULATOR_CAPACITY.get();
}
@Override
public long getMaxIn() {
return Config.ACCUMULATOR_MAX_INPUT.get();
}
@Override
public long getMaxOut() {
return Config.ACCUMULATOR_MAX_OUTPUT.get();
}
@Override
public @Nullable IWireNode getWireNode(int index) {
return IWireNode.getWireNodeFrom(index, this, this.localNodes, this.nodeCache, level);
}
@Override
public @Nullable LocalNode getLocalNode(int index) {
return this.localNodes[index];
}
@Override
public Vec3 getNodeOffset(int node) {
if(node > 3) {
switch(getBlockState().getValue(AccumulatorBlock.FACING)) {
case NORTH:
return OFFSET_NORTH;
case WEST:
return OFFSET_WEST;
case SOUTH:
return OFFSET_SOUTH;
case EAST:
return OFFSET_EAST;
default:
break;
}
}
else {
switch(getBlockState().getValue(AccumulatorBlock.FACING)) {
case NORTH:
return OFFSET_SOUTH;
case WEST:
return OFFSET_EAST;
case SOUTH:
return OFFSET_NORTH;
case EAST:
return OFFSET_WEST;
default:
break;
}
}
return OFFSET_NORTH;
}
@Override
public boolean isEnergyInput(Direction side) {
return side != Direction.UP;
}
@Override
public boolean isEnergyOutput(Direction side) {
return false;
}
@Override
public boolean isNodeInput(int node) {
return node < 4;
}
@Override
public boolean isNodeOutput(int node) {
return !isNodeInput(node);
}
@Override
public int getAvailableNode(Vec3 pos) {
Direction dir = level.getBlockState(worldPosition).getValue(AccumulatorBlock.FACING);
boolean upper = true;
pos = pos.subtract(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ());
switch(dir) {
case NORTH:
upper = pos.z() < 0.5d;
break;
case WEST:
upper = pos.x() < 0.5d;
break;
case SOUTH:
upper = pos.z() > 0.5d;
break;
case EAST:
upper = pos.x() > 0.5d;
break;
default:
break;
}
for(int i = upper ? 4 : 0; i < (upper ? 8 : 4); i++) {
if(hasConnection(i))
continue;
return i;
}
return -1;
}
@Override
public void setNode(int index, int other, BlockPos pos, WireType type) {
this.localNodes[index] = new LocalNode(this, index, other, type, pos);
notifyUpdate();
// Invalidate
if(networkIn != null)
networkIn.invalidate();
if(networkOut != null)
networkOut.invalidate();
}
@Override
public void removeNode(int index, boolean dropWire) {
LocalNode old = this.localNodes[index];
this.localNodes[index] = null;
this.nodeCache[index] = null;
this.invalidateNodeCache();
notifyUpdate();
// Invalidate
if(networkIn != null)
networkIn.invalidate();
if(networkOut != null)
networkOut.invalidate();
// Drop wire next tick.
if (dropWire && old != null) this.wireCache.add(old);
}
@Override
public BlockPos getPos() {
return getBlockPos();
}
@Override
public void read(CompoundTag nbt, boolean clientPacket) {
super.read(nbt, clientPacket);
// Convert old nbt data. x0, y0, z0, node0 & type0 etc.
if (!clientPacket && nbt.contains("node0")) {
convertOldNbt(nbt);
setChanged();
}
// Read the nodes.
invalidateLocalNodes();
invalidateNodeCache();
ListTag nodes = nbt.getList(LocalNode.NODES, Tag.TAG_COMPOUND);
nodes.forEach(tag -> {
LocalNode localNode = new LocalNode(this, (CompoundTag) tag);
this.localNodes[localNode.getIndex()] = localNode;
});
// Check if this was a contraption.
if (nbt.contains("contraption") && !clientPacket) {
this.wasContraption = nbt.getBoolean("contraption");
NodeRotation rotation = getBlockState().getValue(NodeRotation.ROTATION);
if (rotation != NodeRotation.NONE)
level.setBlock(getBlockPos(), getBlockState().setValue(NodeRotation.ROTATION, NodeRotation.NONE), 0);
// Loop over all nodes and update their relative positions.
for (LocalNode localNode : this.localNodes) {
if (localNode == null) continue;
localNode.updateRelative(rotation);
}
}
// Invalidate the network if we updated the nodes.
if (!nodes.isEmpty() && this.networkIn != null && this.networkOut != null) {
this.networkIn.invalidate();
this.networkOut.invalidate();
}
}
@Override
public void write(CompoundTag nbt, boolean clientPacket) {
super.write(nbt, clientPacket);
// Write nodes.
ListTag nodes = new ListTag();
for (int i = 0; i < getNodeCount(); i++) {
LocalNode localNode = this.localNodes[i];
if (localNode == null) continue;
CompoundTag tag = new CompoundTag();
localNode.write(tag);
nodes.add(tag);
}
nbt.put(LocalNode.NODES, nodes);
}
@Override
public int getNodeCount() {
return NODE_COUNT;
}
public void invalidateLocalNodes() {
for(int i = 0; i < getNodeCount(); i++)
this.localNodes[i] = null;
}
@Override
public void invalidateNodeCache() {
for(int i = 0; i < getNodeCount(); i++)
this.nodeCache[i] = null;
}
private int lastComparator = 0;
int lastEnergy = 0;
@Override
public void lazyTick() {
super.lazyTick();
int comp = getComparatorOverride();
if(comp != lastComparator) {
assert level != null;
level.updateNeighborsAt(worldPosition, CABlocks.ACCUMULATOR.get());
}
lastComparator = comp;
//if(energy.getEnergyStored() != lastEnergy)
// causeBlockUpdate();
//lastEnergy = energy.getEnergyStored();
}
private boolean firstTickState = true;
/**
* Called after the tile entity has been part of a contraption.
* Only runs on the server.
*/
private void validateNodes() {
boolean changed = validateLocalNodes(this.localNodes);
// Always set as changed if we were a contraption, as nodes might have been rotated.
notifyUpdate();
if (changed) {
invalidateNodeCache();
// Invalidate
if (this.networkIn != null) this.networkIn.invalidate();
if (this.networkOut != null) this.networkOut.invalidate();
}
}
@Override
public void tick() {
super.tick();
if (this.firstTick) {
this.firstTick = false;
// Check if this blockentity was a part of a contraption.
// If it was, then make sure all the nodes are valid.
if (this.wasContraption && !level.isClientSide()) {
this.wasContraption = false;
validateNodes();
}
}
// Check if we need to drop any wires due to contraption.
if (!this.wireCache.isEmpty() && !isRemoved()) handleWireCache(level, this.wireCache);
if(firstTickState)
firstTick();
firstTickState = false;
if(level.isClientSide())
return;
networkTick();
}
private long demandOut = 0;
private long demandIn = 0;
private void networkTick() {
if(awakeNetwork(level)) {
//EnergyNetwork.nextNode(world, new EnergyNetwork(world), new HashMap<>(), this, 0);//EnergyNetwork.buildNetwork(world, this);
//causeBlockUpdate();
notifyUpdate();
}
if(networkOut == null) {
//System.out.println("WARN!");
return;
}
try (Transaction t = TransferUtil.getTransaction()) {
long toExtract = 0;
try (Transaction nested = TransferUtil.getTransaction()) {
toExtract = localEnergy.extract(demandOut, nested);
}
localEnergy.extract(networkOut.push(toExtract), t);
t.commit();
}
demandOut = networkOut.getDemand();
try (Transaction t = TransferUtil.getTransaction()) {
long toInsert = 0;
try (Transaction nested = TransferUtil.getTransaction()) {
toInsert = localEnergy.insert(getMaxIn(), nested);
}
localEnergy.insert(networkIn.pull(Math.min(demandIn, toInsert)), t);
t.commit();
}
try (Transaction t = TransferUtil.getTransaction()) {
demandIn = networkIn.demand(localEnergy.insert(getMaxIn(), t));
}
}
@Override
public void remove() {
if (level.isClientSide()) return;
for(int i = 0; i < getNodeCount(); i++) {
LocalNode localNode = getLocalNode(i);
if (localNode == null) continue;
IWireNode otherNode = getWireNode(i);
if(otherNode == null) continue;
int ourNode = localNode.getOtherIndex();
if (localNode.isInvalid()) otherNode.removeNode(ourNode);
else otherNode.removeNode(ourNode, true); // Make the other node drop the wires.
}
invalidateNodeCache();
invalidateCaps();
// Invalidate
if(networkIn != null)
networkIn.invalidate();
if(networkOut != null)
networkOut.invalidate();
}
private EnergyNetwork networkIn;
private EnergyNetwork networkOut;
@Override
public EnergyNetwork getNetwork(int node) {
return isNodeInput(node) ? networkIn : networkOut;
}
@Override
public void setNetwork(int node, EnergyNetwork network) {
if(isNodeInput(node))
networkIn = network;
if(isNodeOutput(node))
networkOut = network;
}
@Override
public boolean isNodeIndeciesConnected(int in, int other) {
return isNodeInput(in) == isNodeInput(other);
}
public void setEnergy(int energy) {
this.localEnergy.setEnergy(energy);
}
@Override
public int getComparatorOverride() {
return (int)((double)localEnergy.getAmount() / (double)localEnergy.getCapacity() * 15d);
}
@Override
public boolean addToGoggleTooltip(List<Component> tooltip, boolean isPlayerSneaking) {
@SuppressWarnings("resource")
HitResult ray = Minecraft.getInstance().hitResult;
if(ray == null)
return false;
int node = getAvailableNode(ray.getLocation());
ObservePacket.send(worldPosition, node);
tooltip.add(Component.literal(spacing)
.append(Component.translatable(CreateAddition.MODID + ".tooltip.accumulator.info").withStyle(ChatFormatting.WHITE)));
tooltip.add(Component.literal(spacing)
.append(Component.translatable(CreateAddition.MODID + ".tooltip.energy.stored").withStyle(ChatFormatting.GRAY)));
tooltip.add(Component.literal(spacing).append(Component.literal(" "))
.append(Util.getTextComponent(localEnergy)));
tooltip.add(Component.literal(spacing)
.append(Component.translatable(CreateAddition.MODID + ".tooltip.energy.selected").withStyle(ChatFormatting.GRAY)));
tooltip.add(Component.literal(spacing).append(Component.literal(" "))
.append(Component.translatable(isNodeInput(node) ? "createaddition.tooltip.energy.push" : "createaddition.tooltip.energy.pull").withStyle(ChatFormatting.AQUA)));
tooltip.add(Component.literal(spacing)
.append(Component.translatable(CreateAddition.MODID + ".tooltip.energy.usage").withStyle(ChatFormatting.GRAY)));
tooltip.add(Component.literal(spacing).append(" ")
.append(Util.format(EnergyNetworkPacket.clientBuff)).append("fe/t").withStyle(ChatFormatting.AQUA));
return true;
}
@Override
public void onObserved(ServerPlayer player, ObservePacket pack) {
if(isNetworkValid(0))
EnergyNetworkPacket.send(worldPosition, getNetwork(pack.node()).getPulled(), getNetwork(pack.node()).getPushed(), player);
//causeBlockUpdate();
notifyUpdate();
}
@Override
public ConnectorType getConnectorType() {
return ConnectorType.Small;
}
@Override
public int getMaxWireLength() {
return Config.SMALL_CONNECTOR_MAX_LENGTH.get();
}
}

View File

@ -0,0 +1,12 @@
package com.mrh0.createaddition.blocks.accumulator;
import com.mrh0.createaddition.rendering.WireNodeRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
public class AccumulatorRenderer extends WireNodeRenderer<AccumulatorBlockEntity> {
public AccumulatorRenderer(BlockEntityRendererProvider.Context context) {
super(context);
}
}

View File

@ -0,0 +1,90 @@
package com.mrh0.createaddition.blocks.alternator;
import com.mrh0.createaddition.index.CABlockEntities;
import com.mrh0.createaddition.shapes.CAShapes;
import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.foundation.block.IBE;
import com.simibubi.create.foundation.utility.VoxelShaper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class AlternatorBlock extends DirectionalKineticBlock implements IBE<AlternatorBlockEntity>, IRotate {
public static final VoxelShaper ALTERNATOR_SHAPE = CAShapes.shape(0, 3, 0, 16, 13, 16).add(2, 0, 2, 14, 14, 14).forDirectional();
@Override
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return ALTERNATOR_SHAPE.get(state.getValue(FACING));
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
Direction preferred = getPreferredFacing(context);
if ((context.getPlayer() != null && context.getPlayer()
.isShiftKeyDown()) || preferred == null)
return super.getStateForPlacement(context);
return defaultBlockState().setValue(FACING, preferred);
}
@Override
public boolean hideStressImpact() {
return false;
}
public AlternatorBlock(Properties properties) {
super(properties);
}
@Override
public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) {
return face == state.getValue(FACING);
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.getValue(FACING)
.getAxis();
}
@Override
public BlockEntityType<? extends AlternatorBlockEntity> getBlockEntityType() {
return CABlockEntities.ALTERNATOR.get();
}
@Override
public Class<AlternatorBlockEntity> getBlockEntityClass() {
return AlternatorBlockEntity.class;
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return CABlockEntities.ALTERNATOR.create(pos, state);
}
@Override
public SpeedLevel getMinimumRequiredSpeedLevel() {
return SpeedLevel.MEDIUM;
}
@Override
public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, boolean isMoving) {
BlockEntity tileentity = state.hasBlockEntity() ? worldIn.getBlockEntity(pos) : null;
if(tileentity != null) {
if(tileentity instanceof AlternatorBlockEntity) {
((AlternatorBlockEntity)tileentity).updateCache();
}
}
}
}

View File

@ -0,0 +1,176 @@
package com.mrh0.createaddition.blocks.alternator;
import java.util.List;
import com.mrh0.createaddition.CreateAddition;
import com.mrh0.createaddition.config.Config;
import com.mrh0.createaddition.energy.InternalEnergyStorage;
import com.mrh0.createaddition.index.CABlocks;
import com.mrh0.createaddition.sound.CASoundScapes;
import com.mrh0.createaddition.sound.CASoundScapes.AmbienceGroup;
import com.mrh0.createaddition.util.Util;
import com.mrh0.createaddition.transfer.EnergyTransferable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.foundation.utility.Lang;
import io.github.fabricators_of_create.porting_lib.util.LazyOptional;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
import team.reborn.energy.api.EnergyStorage;
import team.reborn.energy.api.EnergyStorageUtil;
public class AlternatorBlockEntity extends KineticBlockEntity implements EnergyTransferable {
protected final InternalEnergyStorage energy;
public AlternatorBlockEntity(BlockEntityType<?> typeIn, BlockPos pos, BlockState state) {
super(typeIn, pos, state);
energy = new InternalEnergyStorage(Config.ALTERNATOR_CAPACITY.get(), 0, Config.ALTERNATOR_MAX_OUTPUT.get());
}
@Override
public boolean addToGoggleTooltip(List<Component> tooltip, boolean isPlayerSneaking) {
tooltip.add(Component.literal(spacing).append(Component.translatable(CreateAddition.MODID + ".tooltip.energy.production").withStyle(ChatFormatting.GRAY)));
tooltip.add(Component.literal(spacing).append(Component.literal(" " + Util.format(getEnergyProductionRate((int) (isSpeedRequirementFulfilled() ? getSpeed() : 0))) + "fe/t ") // fix
.withStyle(ChatFormatting.AQUA)).append(Lang.translateDirect("gui.goggles.at_current_speed").withStyle(ChatFormatting.DARK_GRAY)));
return true;
}
@Override
public float calculateStressApplied() {
float impact = Config.MAX_STRESS.get()/256f;
this.lastStressApplied = impact;
return impact;
}
@Override
public EnergyStorage getEnergyStorage(Direction side) {
return energy;
}
public boolean isEnergyInput(Direction side) {
return false;
}
public boolean isEnergyOutput(Direction side) {
return true; //side != getBlockState().getValue(AlternatorBlock.FACING);
}
@Override
public void read(CompoundTag compound, boolean clientPacket) {
super.read(compound, clientPacket);
energy.read(compound);
}
@Override
public void write(CompoundTag compound, boolean clientPacket) {
super.write(compound, clientPacket);
energy.write(compound);
}
private boolean firstTickState = true;
@Override
public void tick() {
super.tick();
if(level.isClientSide()) return;
if(firstTickState) firstTick();
firstTickState = false;
if(Math.abs(getSpeed()) > 0 && isSpeedRequirementFulfilled())
energy.internalProduceEnergy(getEnergyProductionRate((int)getSpeed()));
for(Direction d : Direction.values()) {
if(!isEnergyOutput(d))
continue;
EnergyStorage ies = getCachedEnergy(d);
if(ies == null)
continue;
try(Transaction t = Transaction.openOuter()) {
EnergyStorageUtil.move(energy, ies, Config.ALTERNATOR_MAX_OUTPUT.get(), t);
t.commit();
}
}
}
@Environment(EnvType.CLIENT)
@Override
public void tickAudio() {
super.tickAudio();
float componentSpeed = Math.abs(getSpeed());
if (componentSpeed == 0 || !isSpeedRequirementFulfilled())
return;
float pitch = Mth.clamp((componentSpeed / 256f) + .5f, .5f, 1.5f);
CASoundScapes.play(AmbienceGroup.DYNAMO, worldPosition, pitch);
}
public static int getEnergyProductionRate(int rpm) {
rpm = Math.abs(rpm);
return (int)((double)Config.FE_RPM.get() * ((double)Math.abs(rpm) / 256d) * Config.ALTERNATOR_EFFICIENCY.get());//return (int)((double)Config.FE_TO_SU.get() * ((double)Math.abs(rpm)/256d) * EFFICIENCY);
}
@Override
protected Block getStressConfigKey() {
return CABlocks.ALTERNATOR.get();
}
public void firstTick() {
updateCache();
}
public void updateCache() {
if(level.isClientSide()) return;
for(Direction side : Direction.values()) {
BlockEntity te = level.getBlockEntity(worldPosition.relative(side));
if(te == null) {
setCache(side, LazyOptional.empty());
continue;
}
LazyOptional<EnergyStorage> le = LazyOptional.ofObject(EnergyStorage.SIDED.find(level, worldPosition.relative(side), side.getOpposite()));
setCache(side, le);
}
}
private LazyOptional<EnergyStorage> escacheUp = LazyOptional.empty();
private LazyOptional<EnergyStorage> escacheDown = LazyOptional.empty();
private LazyOptional<EnergyStorage> escacheNorth = LazyOptional.empty();
private LazyOptional<EnergyStorage> escacheEast = LazyOptional.empty();
private LazyOptional<EnergyStorage> escacheSouth = LazyOptional.empty();
private LazyOptional<EnergyStorage> escacheWest = LazyOptional.empty();
public void setCache(Direction side, LazyOptional<EnergyStorage> storage) {
switch (side) {
case DOWN -> escacheDown = storage;
case EAST -> escacheEast = storage;
case NORTH -> escacheNorth = storage;
case SOUTH -> escacheSouth = storage;
case UP -> escacheUp = storage;
case WEST -> escacheWest = storage;
}
}
public EnergyStorage getCachedEnergy(Direction side) {
return switch (side) {
case DOWN -> escacheDown.orElse(null);
case EAST -> escacheEast.orElse(null);
case NORTH -> escacheNorth.orElse(null);
case SOUTH -> escacheSouth.orElse(null);
case UP -> escacheUp.orElse(null);
case WEST -> escacheWest.orElse(null);
};
}
}

View File

@ -0,0 +1,22 @@
package com.mrh0.createaddition.blocks.alternator;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context;
import net.minecraft.world.level.block.state.BlockState;
public class AlternatorRenderer extends KineticBlockEntityRenderer {
public AlternatorRenderer(Context dispatcher) {
super(dispatcher);
}
@Override
protected SuperByteBuffer getRotatedModel(KineticBlockEntity te, BlockState state) {
return CachedBufferer.partialFacing(AllPartialModels.SHAFT_HALF, state);
}
}

View File

@ -0,0 +1,53 @@
package com.mrh0.createaddition.blocks.barbed_wire;
import com.mrh0.createaddition.config.Config;
import com.mrh0.createaddition.index.CADamageSources;
import io.github.fabricators_of_create.porting_lib.extensions.extensions.IShearable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.Vec3;
public class BarbedWireBlock extends Block implements IShearable {
public static final BooleanProperty VERTICAL = BooleanProperty.create("vertical");
public static final DirectionProperty HORIZONTAL_FACING = BlockStateProperties.HORIZONTAL_FACING;
public BarbedWireBlock(Properties props) {
super(props);
this.registerDefaultState(this.defaultBlockState().setValue(VERTICAL, false).setValue(HORIZONTAL_FACING, Direction.NORTH));
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
double delta = Math.abs(entity.getX() - entity.xOld) + Math.abs(entity.getY() - entity.yOld) + Math.abs(entity.getZ() - entity.zOld);
if((entity instanceof LivingEntity) && delta > 0d) {
if(entity.hurt(CADamageSources.barbedWire(level), Config.BARBED_WIRE_DAMAGE.get().floatValue()))
entity.playSound(SoundEvents.PLAYER_HURT_SWEET_BERRY_BUSH, 1f, 1f);
}
entity.makeStuckInBlock(state, new Vec3(0.25D, (double)0.05F, 0.25D));
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> builder) {
builder.add(VERTICAL, HORIZONTAL_FACING);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext c) {
if(c.getClickedFace().getAxis() == Axis.Y)
return defaultBlockState().setValue(HORIZONTAL_FACING, c.getPlayer().isShiftKeyDown() ? c.getHorizontalDirection().getClockWise() : c.getHorizontalDirection()).setValue(VERTICAL, false);
else
return defaultBlockState().setValue(HORIZONTAL_FACING, c.getClickedFace().getOpposite()).setValue(VERTICAL, true);
}
}

View File

@ -0,0 +1,48 @@
package com.mrh0.createaddition.blocks.cake;
import net.minecraft.core.BlockPos;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.CakeBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
public class CACakeBlock extends CakeBlock {
public CACakeBlock(Properties props) {
super(props);
}
@Override
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player,
InteractionHand hand, BlockHitResult ray) {
if (world.isClientSide) {
ItemStack itemstack = player.getItemInHand(hand);
if (eat(world, pos, state, player).consumesAction())
return InteractionResult.SUCCESS;
if (itemstack.isEmpty())
return InteractionResult.CONSUME;
}
return eat(world, pos, state, player);
}
protected static InteractionResult eat(LevelAccessor world, BlockPos pos, BlockState state, Player player) {
if (!player.canEat(false))
return InteractionResult.PASS;
else {
player.awardStat(Stats.EAT_CAKE_SLICE);
player.getFoodData().eat(3, 0.3F);
int i = state.getValue(BITES);
if (i < 6)
world.setBlock(pos, state.setValue(BITES, Integer.valueOf(i + 1)), 3);
else
world.removeBlock(pos, false);
return InteractionResult.SUCCESS;
}
}
}

View File

@ -0,0 +1,4 @@
package com.mrh0.createaddition.blocks.centrifugal_governor;
public class CentrifugalGovernor {
}

View File

@ -0,0 +1,14 @@
package com.mrh0.createaddition.blocks.connector;
import com.mrh0.createaddition.config.Config;
public enum ConnectorType {
Small("small"),
Large("large");
public final String name;
ConnectorType(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,40 @@
package com.mrh0.createaddition.blocks.connector;
import com.mrh0.createaddition.blocks.connector.base.AbstractConnectorBlock;
import com.mrh0.createaddition.index.CABlockEntities;
import com.mrh0.createaddition.shapes.CAShapes;
import com.simibubi.create.foundation.utility.VoxelShaper;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class LargeConnectorBlock extends AbstractConnectorBlock<LargeConnectorBlockEntity> {
public static final VoxelShaper CONNECTOR_SHAPE = CAShapes.shape(5, 0, 5, 11, 7, 11).forDirectional();
public LargeConnectorBlock(Properties properties) {
super(properties);
}
@Override
public Class<LargeConnectorBlockEntity> getBlockEntityClass() {
return LargeConnectorBlockEntity.class;
}
@Override
public BlockEntityType<? extends LargeConnectorBlockEntity> getBlockEntityType() {
return CABlockEntities.LARGE_CONNECTOR.get();
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return CABlockEntities.LARGE_CONNECTOR.create(pos, state);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return CONNECTOR_SHAPE.get(state.getValue(FACING).getOpposite());
}
}

View File

@ -0,0 +1,66 @@
package com.mrh0.createaddition.blocks.connector;
import com.mrh0.createaddition.blocks.connector.base.AbstractConnectorBlock;
import com.mrh0.createaddition.blocks.connector.base.AbstractConnectorBlockEntity;
import com.mrh0.createaddition.config.Config;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import java.util.List;
public class LargeConnectorBlockEntity extends AbstractConnectorBlockEntity {
private final static float OFFSET_HEIGHT = 1f;
public final static Vec3 OFFSET_DOWN = new Vec3(0f, -OFFSET_HEIGHT/16f, 0f);
public final static Vec3 OFFSET_UP = new Vec3(0f, OFFSET_HEIGHT/16f, 0f);
public final static Vec3 OFFSET_NORTH = new Vec3(0f, 0f, -OFFSET_HEIGHT/16f);
public final static Vec3 OFFSET_WEST = new Vec3(-OFFSET_HEIGHT/16f, 0f, 0f);
public final static Vec3 OFFSET_SOUTH = new Vec3(0f, 0f, OFFSET_HEIGHT/16f);
public final static Vec3 OFFSET_EAST = new Vec3(OFFSET_HEIGHT/16f, 0f, 0f);
public LargeConnectorBlockEntity(BlockEntityType<?> blockEntityTypeIn, BlockPos pos, BlockState state) {
super(blockEntityTypeIn, pos, state);
}
@Override
public void addBehaviours(List<BlockEntityBehaviour> list) {}
@Override
public long getMaxIn() {
return Config.LARGE_CONNECTOR_MAX_INPUT.get();
}
@Override
public long getMaxOut() {
return Config.LARGE_CONNECTOR_MAX_OUTPUT.get();
}
@Override
public int getNodeCount() {
return 6;
}
@Override
public Vec3 getNodeOffset(int node) {
return switch (getBlockState().getValue(AbstractConnectorBlock.FACING)) {
case DOWN -> OFFSET_DOWN;
case UP -> OFFSET_UP;
case NORTH -> OFFSET_NORTH;
case WEST -> OFFSET_WEST;
case SOUTH -> OFFSET_SOUTH;
case EAST -> OFFSET_EAST;
};
}
@Override
public ConnectorType getConnectorType() {
return ConnectorType.Large;
}
public int getMaxWireLength() {
return Config.LARGE_CONNECTOR_MAX_LENGTH.get();
}
}

View File

@ -0,0 +1,41 @@
package com.mrh0.createaddition.blocks.connector;
import com.mrh0.createaddition.blocks.connector.base.AbstractConnectorBlock;
import com.mrh0.createaddition.index.CABlockEntities;
import com.mrh0.createaddition.shapes.CAShapes;
import com.simibubi.create.foundation.utility.VoxelShaper;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.NotNull;
public class SmallConnectorBlock extends AbstractConnectorBlock<SmallConnectorBlockEntity> {
public static final VoxelShaper CONNECTOR_SHAPE = CAShapes.shape(6, 0, 6, 10, 5, 10).forDirectional();
public SmallConnectorBlock(Properties properties) {
super(properties);
}
@Override
public Class<SmallConnectorBlockEntity> getBlockEntityClass() {
return SmallConnectorBlockEntity.class;
}
@Override
public BlockEntityType<? extends SmallConnectorBlockEntity> getBlockEntityType() {
return CABlockEntities.SMALL_CONNECTOR.get();
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return CABlockEntities.SMALL_CONNECTOR.create(pos, state);
}
@Override
public @NotNull VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return CONNECTOR_SHAPE.get(state.getValue(FACING).getOpposite());
}
}

View File

@ -0,0 +1,66 @@
package com.mrh0.createaddition.blocks.connector;
import com.mrh0.createaddition.blocks.connector.base.AbstractConnectorBlock;
import com.mrh0.createaddition.blocks.connector.base.AbstractConnectorBlockEntity;
import com.mrh0.createaddition.config.Config;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import java.util.List;
public class SmallConnectorBlockEntity extends AbstractConnectorBlockEntity {
private final static float OFFSET_HEIGHT = 3f;
public final static Vec3 OFFSET_DOWN = new Vec3(0f, -OFFSET_HEIGHT/16f, 0f);
public final static Vec3 OFFSET_UP = new Vec3(0f, OFFSET_HEIGHT/16f, 0f);
public final static Vec3 OFFSET_NORTH = new Vec3(0f, 0f, -OFFSET_HEIGHT/16f);
public final static Vec3 OFFSET_WEST = new Vec3(-OFFSET_HEIGHT/16f, 0f, 0f);
public final static Vec3 OFFSET_SOUTH = new Vec3(0f, 0f, OFFSET_HEIGHT/16f);
public final static Vec3 OFFSET_EAST = new Vec3(OFFSET_HEIGHT/16f, 0f, 0f);
public SmallConnectorBlockEntity(BlockEntityType<?> blockEntityTypeIn, BlockPos pos, BlockState state) {
super(blockEntityTypeIn, pos, state);
}
@Override
public void addBehaviours(List<BlockEntityBehaviour> list) {}
@Override
public long getMaxIn() {
return Config.SMALL_CONNECTOR_MAX_INPUT.get();
}
@Override
public long getMaxOut() {
return Config.SMALL_CONNECTOR_MAX_OUTPUT.get();
}
@Override
public int getNodeCount() {
return 4;
}
@Override
public Vec3 getNodeOffset(int node) {
return switch (getBlockState().getValue(AbstractConnectorBlock.FACING)) {
case DOWN -> OFFSET_DOWN;
case UP -> OFFSET_UP;
case NORTH -> OFFSET_NORTH;
case WEST -> OFFSET_WEST;
case SOUTH -> OFFSET_SOUTH;
case EAST -> OFFSET_EAST;
};
}
@Override
public ConnectorType getConnectorType() {
return ConnectorType.Small;
}
public int getMaxWireLength() {
return Config.SMALL_CONNECTOR_MAX_LENGTH.get();
}
}

View File

@ -0,0 +1,58 @@
package com.mrh0.createaddition.blocks.connector;
import com.mrh0.createaddition.blocks.connector.base.AbstractConnectorBlock;
import com.mrh0.createaddition.energy.NodeRotation;
import com.mrh0.createaddition.index.CABlockEntities;
import com.mrh0.createaddition.shapes.CAShapes;
import com.simibubi.create.foundation.utility.VoxelShaper;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class SmallLightConnectorBlock extends AbstractConnectorBlock<SmallLightConnectorBlockEntity> {
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public static final VoxelShaper CONNECTOR_SHAPE = CAShapes.shape(6, 0, 6, 10, 5, 10).add(5, 4, 5, 11, 10, 11).forDirectional();
public SmallLightConnectorBlock(Properties properties) {
super(properties);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext c) {
return super.getStateForPlacement(c).setValue(POWERED, false);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING, MODE, NodeRotation.ROTATION, VARIANT, POWERED);
}
@Override
public Class<SmallLightConnectorBlockEntity> getBlockEntityClass() {
return SmallLightConnectorBlockEntity.class;
}
@Override
public BlockEntityType<? extends SmallLightConnectorBlockEntity> getBlockEntityType() {
return CABlockEntities.SMALL_LIGHT_CONNECTOR.get();
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return CABlockEntities.SMALL_LIGHT_CONNECTOR.create(pos, state);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return CONNECTOR_SHAPE.get(state.getValue(FACING).getOpposite());
}
}

View File

@ -0,0 +1,108 @@
package com.mrh0.createaddition.blocks.connector;
import com.mrh0.createaddition.blocks.connector.base.AbstractConnectorBlock;
import com.mrh0.createaddition.blocks.connector.base.AbstractConnectorBlockEntity;
import com.mrh0.createaddition.config.Config;
import com.mrh0.createaddition.energy.network.EnergyNetwork;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import java.util.List;
public class SmallLightConnectorBlockEntity extends AbstractConnectorBlockEntity {
private final static float OFFSET_HEIGHT = 5.5f;
public final static Vec3 OFFSET_DOWN = new Vec3(0f, -OFFSET_HEIGHT/16f, 0f);
public final static Vec3 OFFSET_UP = new Vec3(0f, OFFSET_HEIGHT/16f, 0f);
public final static Vec3 OFFSET_NORTH = new Vec3(0f, 0f, -OFFSET_HEIGHT/16f);
public final static Vec3 OFFSET_WEST = new Vec3(-OFFSET_HEIGHT/16f, 0f, 0f);
public final static Vec3 OFFSET_SOUTH = new Vec3(0f, 0f, OFFSET_HEIGHT/16f);
public final static Vec3 OFFSET_EAST = new Vec3(OFFSET_HEIGHT/16f, 0f, 0f);
private int posTimeOffset = 0;
public SmallLightConnectorBlockEntity(BlockEntityType<?> blockEntityTypeIn, BlockPos pos, BlockState state) {
super(blockEntityTypeIn, pos, state);
posTimeOffset = 10 + (Math.abs(pos.getX()*31 + pos.getY()*45 + pos.getZ()*33) % 7) * 3;
}
@Override
public void read(CompoundTag nbt, boolean clientPacket) {
tickToggleTimer = nbt.getInt("tick_toggle_timer");
super.read(nbt, clientPacket);
}
@Override
public void write(CompoundTag nbt, boolean clientPacket) {
nbt.putInt("tick_toggle_timer", tickToggleTimer);
super.write(nbt, clientPacket);
}
@Override
public void addBehaviours(List<BlockEntityBehaviour> list) {}
@Override
public long getMaxIn() {
return Config.SMALL_CONNECTOR_MAX_INPUT.get();
}
@Override
public long getMaxOut() {
return Config.SMALL_CONNECTOR_MAX_OUTPUT.get();
}
@Override
public int getNodeCount() {
return 4;
}
@Override
public Vec3 getNodeOffset(int node) {
return switch (getBlockState().getValue(AbstractConnectorBlock.FACING)) {
case DOWN -> OFFSET_DOWN;
case UP -> OFFSET_UP;
case NORTH -> OFFSET_NORTH;
case WEST -> OFFSET_WEST;
case SOUTH -> OFFSET_SOUTH;
case EAST -> OFFSET_EAST;
};
}
@Override
public ConnectorType getConnectorType() {
return ConnectorType.Small;
}
public int getMaxWireLength() {
return Config.SMALL_CONNECTOR_MAX_LENGTH.get();
}
private int tickToggleTimer = 0;
@Override
protected void specialTick() {
if(getLevel() == null) return;
if(level.isClientSide()) return;
EnergyNetwork network = getNetwork(0);
boolean hasEnergy = network != null && network.pull(Config.SMALL_LIGHT_CONNECTOR_CONSUMPTION.get()) > 0;
tickToggleTimer = tickToggleTimer + (hasEnergy ? 1 : -1);
if (tickToggleTimer >= posTimeOffset) {
tickToggleTimer = posTimeOffset;
if (!getBlockState().getValue(SmallLightConnectorBlock.POWERED))
getLevel().setBlockAndUpdate(getBlockPos(), getBlockState()
.setValue(SmallLightConnectorBlock.POWERED, true));
}
if (tickToggleTimer <= -posTimeOffset) {
tickToggleTimer = -posTimeOffset;
if (getBlockState().getValue(SmallLightConnectorBlock.POWERED))
getLevel().setBlockAndUpdate(getBlockPos(), getBlockState()
.setValue(SmallLightConnectorBlock.POWERED, false));
}
}
}

View File

@ -0,0 +1,145 @@
package com.mrh0.createaddition.blocks.connector.base;
import com.mrh0.createaddition.config.Config;
import com.mrh0.createaddition.energy.IWireNode;
import com.mrh0.createaddition.energy.NodeRotation;
import com.simibubi.create.content.contraptions.ITransformableBlock;
import com.simibubi.create.content.contraptions.StructureTransform;
import com.simibubi.create.content.equipment.wrench.IWrenchable;
import com.simibubi.create.foundation.block.IBE;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.SupportType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public abstract class AbstractConnectorBlock<BE extends AbstractConnectorBlockEntity> extends Block implements IBE<BE>, IWrenchable, ITransformableBlock {
public static final DirectionProperty FACING = BlockStateProperties.FACING;
public static final EnumProperty<ConnectorMode> MODE = EnumProperty.create("mode", ConnectorMode.class);
public static final EnumProperty<ConnectorVariant> VARIANT = EnumProperty.create("variant", ConnectorVariant.class);
private static final VoxelShape boxwe = Block.box(0,7,7,10,9,9);
private static final VoxelShape boxsn = Block.box(7,7,0,9,9,10);
public AbstractConnectorBlock(Properties properties) {
super(properties);
this.registerDefaultState(this.defaultBlockState()
.setValue(FACING, Direction.NORTH)
.setValue(MODE, ConnectorMode.None)
.setValue(NodeRotation.ROTATION, NodeRotation.NONE)
.setValue(VARIANT, ConnectorVariant.Default));
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> builder) {
builder.add(FACING, MODE, NodeRotation.ROTATION, VARIANT);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext c) {
Direction dir = c.getClickedFace().getOpposite();
ConnectorMode mode = ConnectorMode.test(c.getLevel(), c.getClickedPos().relative(dir), c.getClickedFace());
ConnectorVariant variant = ConnectorVariant.test(c.getLevel(), c.getClickedPos().relative(dir), c.getClickedFace());
return this.defaultBlockState().setValue(FACING, dir).setValue(MODE, mode).setValue(VARIANT, variant);
}
@Override
public void playerWillDestroy(Level worldIn, BlockPos pos, BlockState state, Player player) {
super.playerWillDestroy(worldIn, pos, state, player);
if (worldIn.isClientSide()) return;
BlockEntity te = worldIn.getBlockEntity(pos);
if (te == null) return;
if (!(te instanceof IWireNode cte)) return;
cte.dropWires(worldIn, !player.isCreative());
}
@Override
public InteractionResult onWrenched(BlockState state, UseOnContext c) {
if (c.getLevel().isClientSide()) {
c.getLevel().playLocalSound(c.getClickedPos().getX(), c.getClickedPos().getY(), c.getClickedPos().getZ(), SoundEvents.BONE_BLOCK_HIT, SoundSource.BLOCKS, 1f, 1f, false);
}
c.getLevel().setBlockAndUpdate(c.getClickedPos(), state.setValue(MODE, state.getValue(MODE).getNext()));
return InteractionResult.SUCCESS;
}
@Override
public InteractionResult onSneakWrenched(BlockState state, UseOnContext c) {
BlockEntity be = c.getLevel().getBlockEntity(c.getClickedPos());
if(be == null) return IWrenchable.super.onSneakWrenched(state, c);
if(!(be instanceof IWireNode cbe)) return IWrenchable.super.onSneakWrenched(state, c);
// if(be instanceof AbstractConnectorBlockEntity acbe) acbe.updateExternalEnergyStorage();
if (!c.getLevel().isClientSide() && c.getPlayer() != null)
cbe.dropWires(c.getLevel(), c.getPlayer(), !c.getPlayer().isCreative());
return IWrenchable.super.onSneakWrenched(state, c);
}
@Override
public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, boolean isMoving) {
BlockEntity blockEntity = state.hasBlockEntity() ? worldIn.getBlockEntity(pos) : null;
if(blockEntity != null) {
if(blockEntity instanceof AbstractConnectorBlockEntity) {
((AbstractConnectorBlockEntity)blockEntity).updateExternalEnergyStorage();
}
}
if (!state.canSurvive(worldIn, pos)) {
dropResources(state, worldIn, pos, blockEntity);
if(blockEntity instanceof IWireNode)
((IWireNode) blockEntity).dropWires(worldIn, true);
worldIn.removeBlock(pos, false);
for (Direction direction : Direction.values())
worldIn.updateNeighborsAt(pos.relative(direction), this);
}
}
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
Direction dir = state.getValue(FACING);
return
!Shapes.joinIsNotEmpty(world.getBlockState(pos.relative(dir)).getBlockSupportShape(world,pos.relative(dir)).getFaceShape(dir.getOpposite()), boxwe, BooleanOp.ONLY_SECOND) ||
!Shapes.joinIsNotEmpty(world.getBlockState(pos.relative(dir)).getBlockSupportShape(world,pos.relative(dir)).getFaceShape(dir.getOpposite()), boxsn, BooleanOp.ONLY_SECOND) ||
world.getBlockState(pos.relative(dir)).isFaceSturdy(world, pos, dir.getOpposite(), SupportType.CENTER) || Config.CONNECTOR_IGNORE_FACE_CHECK.get();
}
@Override
public BlockState rotate(BlockState state, Rotation direction) {
// Handle old rotation.
return state.setValue(FACING, direction.rotate(state.getValue(FACING)));
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return state.setValue(FACING, mirror.mirror(state.getValue(FACING)));
}
@Override
public BlockState transform(BlockState state, StructureTransform transform) {
NodeRotation rotation = NodeRotation.get(transform.rotationAxis, transform.rotation);
// Handle default rotation & mirroring.
if (transform.mirror != null) state = mirror(state, transform.mirror);
state = state.setValue(FACING, rotation.rotate(state.getValue(FACING), false));
// Set the rotation state, which will be used to update the nodes.
return state.setValue(NodeRotation.ROTATION, rotation);
}
}

View File

@ -0,0 +1,428 @@
package com.mrh0.createaddition.blocks.connector.base;
import com.mrh0.createaddition.CreateAddition;
import com.mrh0.createaddition.config.Config;
import com.mrh0.createaddition.debug.IDebugDrawer;
import com.mrh0.createaddition.energy.IWireNode;
import com.mrh0.createaddition.energy.LocalNode;
import com.mrh0.createaddition.energy.NodeRotation;
import com.mrh0.createaddition.energy.WireType;
import com.mrh0.createaddition.energy.network.EnergyNetwork;
import com.mrh0.createaddition.network.EnergyNetworkPacket;
import com.mrh0.createaddition.network.IObserveTileEntity;
import com.mrh0.createaddition.network.ObservePacket;
import com.mrh0.createaddition.transfer.EnergyTransferable;
import com.mrh0.createaddition.util.Util;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import io.github.fabricators_of_create.porting_lib.transfer.TransferUtil;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import team.reborn.energy.api.EnergyStorage;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public abstract class AbstractConnectorBlockEntity extends SmartBlockEntity implements EnergyTransferable, IWireNode, IObserveTileEntity, IHaveGoggleInformation, IDebugDrawer {
private final Set<LocalNode> wireCache = new HashSet<>();
private final LocalNode[] localNodes;
private final IWireNode[] nodeCache;
private EnergyNetwork network;
private long demand = 0;
private boolean wasContraption = false;
private boolean firstTick = true;
@NotNull
protected EnergyStorage networkStorage = new NetworkEnergyStorage();
@NotNull
protected EnergyStorage externalStorage = EnergyStorage.EMPTY;
public AbstractConnectorBlockEntity(BlockEntityType<?> blockEntityTypeIn, BlockPos pos, BlockState state) {
super(blockEntityTypeIn, pos, state);
this.localNodes = new LocalNode[getNodeCount()];
this.nodeCache = new IWireNode[getNodeCount()];
}
public EnergyStorage getEnergyStorage(Direction side){
if(isEnergyInput(side)||isEnergyOutput(side)) {
return networkStorage;
}
return null;
}
public abstract long getMaxIn();
public abstract long getMaxOut();
//Renamed to prevent name conflict
public long getCapacityOutside() {
return Math.min(getMaxIn(), getMaxOut());
}
private class NetworkEnergyStorage implements EnergyStorage {
@Override
public long insert(long maxAmount, TransactionContext transaction) {
if(!Config.CONNECTOR_ALLOW_PASSIVE_IO.get()) return 0;
if(getMode() != ConnectorMode.Pull) return 0;
if (network == null) return 0;
maxAmount = Math.min(maxAmount, getMaxIn());
return network.push(maxAmount);
}
@Override
public long extract(long maxAmount, TransactionContext transaction) {
if(!Config.CONNECTOR_ALLOW_PASSIVE_IO.get()) return 0;
if(getMode() != ConnectorMode.Push) return 0;
if (network == null) return 0;
maxAmount = Math.min(maxAmount, getMaxOut());
return network.pull(maxAmount);
}
@Override
public long getAmount() {
if (network == null) return 0;
return Math.min(getCapacity(), network.getBuff());
}
@Override
public long getCapacity() {
return getCapacityOutside();
}
}
@Override
public @Nullable IWireNode getWireNode(int index) {
return IWireNode.getWireNodeFrom(index, this, this.localNodes, this.nodeCache, level);
}
@Override
public @Nullable LocalNode getLocalNode(int index) {
return this.localNodes[index];
}
@Override
public void setNode(int index, int other, BlockPos pos, WireType type) {
this.localNodes[index] = new LocalNode(this, index, other, type, pos);
notifyUpdate();
// Invalidate
if (network != null) network.invalidate();
}
@Override
public void removeNode(int index, boolean dropWire) {
LocalNode old = this.localNodes[index];
this.localNodes[index] = null;
this.nodeCache[index] = null;
invalidateNodeCache();
notifyUpdate();
// Invalidate
if (network != null) network.invalidate();
// Drop wire next tick.
if (dropWire && old != null) this.wireCache.add(old);
}
@Override
public BlockPos getPos() {
return getBlockPos();
}
@Override
public void setNetwork(int node, EnergyNetwork network) {
this.network = network;
}
@Override
public EnergyNetwork getNetwork(int node) {
return network;
}
public boolean isEnergyInput(Direction side) {
return getBlockState().getValue(AbstractConnectorBlock.FACING) == side;
}
public boolean isEnergyOutput(Direction side) {
return getBlockState().getValue(AbstractConnectorBlock.FACING) == side;
}
@Override
public void read(CompoundTag nbt, boolean clientPacket) {
super.read(nbt, clientPacket);
// Convert old nbt data. x0, y0, z0, node0 & type0 etc.
if (!clientPacket && nbt.contains("node0")) {
convertOldNbt(nbt);
setChanged();
}
// Read the nodes.
invalidateLocalNodes();
invalidateNodeCache();
ListTag nodes = nbt.getList(LocalNode.NODES, Tag.TAG_COMPOUND);
nodes.forEach(tag -> {
LocalNode localNode = new LocalNode(this, (CompoundTag) tag);
this.localNodes[localNode.getIndex()] = localNode;
});
// Check if this was a contraption.
if (nbt.contains("contraption") && !clientPacket) {
this.wasContraption = nbt.getBoolean("contraption");
NodeRotation rotation = getBlockState().getValue(NodeRotation.ROTATION);
if(level == null) return;
if (rotation != NodeRotation.NONE)
level.setBlock(getBlockPos(), getBlockState().setValue(NodeRotation.ROTATION, NodeRotation.NONE), 0);
// Loop over all nodes and update their relative positions.
for (LocalNode localNode : this.localNodes) {
if (localNode == null) continue;
localNode.updateRelative(rotation);
}
}
// Invalidate the network if we updated the nodes.
if (!nodes.isEmpty() && this.network != null) this.network.invalidate();
}
@Override
public void write(CompoundTag nbt, boolean clientPacket) {
super.write(nbt, clientPacket);
// Write nodes.
ListTag nodes = new ListTag();
for (int i = 0; i < getNodeCount(); i++) {
LocalNode localNode = this.localNodes[i];
if (localNode == null) continue;
CompoundTag tag = new CompoundTag();
localNode.write(tag);
nodes.add(tag);
}
nbt.put(LocalNode.NODES, nodes);
}
/**
* Called after the tile entity has been part of a contraption.
* Only runs on the server.
*/
private void validateNodes() {
boolean changed = validateLocalNodes(this.localNodes);
// Always set as changed if we were a contraption, as nodes might have been rotated.
notifyUpdate();
if (changed) {
invalidateNodeCache();
// Invalidate
if (this.network != null) this.network.invalidate();
}
}
public void firstTick() {
this.firstTick = false;
// Check if this blockentity was a part of a contraption.
// If it was, then make sure all the nodes are valid.
if(level == null) return;
if (this.wasContraption && !level.isClientSide()) {
this.wasContraption = false;
validateNodes();
}
updateExternalEnergyStorage();
}
protected void specialTick() {}
boolean externalStorageInvalid = false;
@Override
public void tick() {
if (this.firstTick) firstTick();
if (level == null) return;
if (!level.isLoaded(getBlockPos())) return;
// Check if we need to drop any wires due to contraption.
if (!this.wireCache.isEmpty() && !isRemoved()) handleWireCache(level, this.wireCache);
specialTick();
if (getMode() == ConnectorMode.None) return;
super.tick();
if(level == null) return;
if(level.isClientSide()) return;
if(awakeNetwork(level)) notifyUpdate();
networkTick(network);
if (externalStorageInvalid) updateExternalEnergyStorage();
}
private void networkTick(EnergyNetwork network) {
ConnectorMode mode = getMode();
if(level == null) return;
if(level.isClientSide()) return;
if (mode == ConnectorMode.Push) {
long pulled;
try (Transaction t = TransferUtil.getTransaction()){
pulled = network.pull(network.demand(externalStorage.insert(getMaxOut(), t)));
}
try (Transaction t = TransferUtil.getTransaction()) {
externalStorage.insert(pulled, t);
t.commit();
}
}
if (mode == ConnectorMode.Pull) {
long toPush;
try(Transaction t = TransferUtil.getTransaction()) {
toPush = externalStorage.extract(network.push(getMaxIn(), true), t);
t.commit();
}
network.push(toPush);
}
}
@Override
public void remove() {
if(level == null) return;
if (level.isClientSide()) return;
// Remove all nodes.
for (int i = 0; i < getNodeCount(); i++) {
LocalNode localNode = getLocalNode(i);
if (localNode == null) continue;
IWireNode otherNode = getWireNode(i);
if(otherNode == null) continue;
int ourNode = localNode.getOtherIndex();
if (localNode.isInvalid())
otherNode.removeNode(ourNode);
else
otherNode.removeNode(ourNode, true); // Make the other node drop the wires.
}
invalidateNodeCache();
invalidateCaps();
// Invalidate
if (network != null) network.invalidate();
}
public void invalidateLocalNodes() {
for(int i = 0; i < getNodeCount(); i++)
this.localNodes[i] = null;
}
@Override
public void invalidateNodeCache() {
for(int i = 0; i < getNodeCount(); i++)
this.nodeCache[i] = null;
}
public ConnectorMode getMode() {
return getBlockState().getValue(AbstractConnectorBlock.MODE);
}
@Override
public void onObserved(ServerPlayer player, ObservePacket pack) {
if(isNetworkValid(0)) {
EnergyNetworkPacket.send(worldPosition, getNetwork(0).getPulled(), getNetwork(0).getPushed(), player);
} else {
EnergyNetworkPacket.send(worldPosition, 0, 0, player);
}
}
@Override
public boolean addToGoggleTooltip(List<Component> tooltip, boolean isPlayerSneaking) {
ObservePacket.send(worldPosition, 0);
tooltip.add(Component.literal(spacing)
.append(Component.translatable(CreateAddition.MODID + ".tooltip.connector.info").withStyle(ChatFormatting.WHITE)));
tooltip.add(Component.literal(spacing)
.append(Component.translatable(CreateAddition.MODID + ".tooltip.energy.mode").withStyle(ChatFormatting.GRAY)));
tooltip.add(Component.literal(spacing).append(Component.literal(" "))
.append(getBlockState().getValue(AbstractConnectorBlock.MODE).getTooltip().withStyle(ChatFormatting.AQUA)));
tooltip.add(Component.literal(spacing)
.append(Component.translatable(CreateAddition.MODID + ".tooltip.energy.usage").withStyle(ChatFormatting.GRAY)));
tooltip.add(Component.literal(spacing).append(" ")
.append(Util.format((int)EnergyNetworkPacket.clientBuff)).append("fe/t").withStyle(ChatFormatting.AQUA));
return true;
}
public boolean ignoreCapSide() {
return this.getBlockState().getValue(AbstractConnectorBlock.MODE).isActive();
}
public void updateExternalEnergyStorage() {
if (level == null) return;
if (!level.isLoaded(getBlockPos())) return;
externalStorageInvalid = false;
var side = getBlockState().getValue(AbstractConnectorBlock.FACING);
BlockPos externalPos = worldPosition.relative(side);
if (!level.isLoaded(externalPos)) {
externalStorage = EnergyStorage.EMPTY;
return;
}
EnergyStorage es = EnergyStorage.SIDED.find(level, externalPos, side.getOpposite());
if(ignoreCapSide() && es == null) {
es = EnergyStorage.SIDED.find(level, externalPos, null);
}
if(es == null){
externalStorage = EnergyStorage.EMPTY;
} else {
externalStorage = es;
}
}
@Override
public void drawDebug() {
if (level == null) return;
// Outline all connected nodes.
for (int i = 0; i < getNodeCount(); i++) {
LocalNode localNode = this.localNodes[i];
if (localNode == null) continue;
BlockPos pos = localNode.getPos();
BlockState state = level.getBlockState(pos);
VoxelShape shape = state.getBlockSupportShape(level, pos);
int color;
if (i == 0) color = 0xFF0000;
else if (i == 1) color = 0x00FF00;
else if (i == 2) color = 0x0000FF;
else color = 0xFFFFFF;
// Make sure the node is a connector block.
if (!(level.getBlockEntity(pos) instanceof IWireNode)) {
shape = Shapes.block();
color = 0xFF00FF;
}
// ca_ = Create Addition
CreateClient.OUTLINER.chaseAABB("ca_nodes_" + i, shape.bounds().move(pos)).lineWidth(0.0625F).colored(color);
}
// Outline connected power
BlockPos pos = worldPosition.relative(getBlockState().getValue(AbstractConnectorBlock.FACING));
EnergyStorage cap = EnergyStorage.SIDED.find(level, pos, getBlockState().getValue(AbstractConnectorBlock.FACING).getOpposite());
if(cap == null) return;
// if(ignoreCapSide() && !cap.isPresent()) cap = te.getCapability(CapabilityEnergy.ENERGY);
VoxelShape shape = level.getBlockState(pos).getBlockSupportShape(level, pos);
CreateClient.OUTLINER.chaseAABB("ca_output", shape.bounds().move(pos)).lineWidth(0.0625F).colored(0x5B5BFF);
}
}

View File

@ -0,0 +1,69 @@
package com.mrh0.createaddition.blocks.connector.base;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.Level;
import team.reborn.energy.api.EnergyStorage;
public enum ConnectorMode implements StringRepresentable {
Push("push"),
Pull("pull"),
None("none"),
Passive("passive");
private String name;
ConnectorMode(String name) {
this.name = name;
}
@Override
public String getSerializedName() {
return this.name;
}
public ConnectorMode getNext() {
switch (this) {
//case Passive:
// return None;
case None:
return Pull;
case Pull:
return Push;
case Push:
return None;
}
return None;
}
public MutableComponent getTooltip() {
switch (this) {
case Passive:
return Component.translatable("createaddition.tooltip.energy.passive");
case None:
return Component.translatable("createaddition.tooltip.energy.none");
case Pull:
return Component.translatable("createaddition.tooltip.energy.pull");
case Push:
return Component.translatable("createaddition.tooltip.energy.push");
}
return Component.translatable("createaddition.tooltip.energy.none");
}
public boolean isActive() {
return this == Push || this == Pull;
}
public static ConnectorMode test(Level level, BlockPos pos, Direction face) {
EnergyStorage e = EnergyStorage.SIDED.find(level, pos, face);
if(e == null) return None;
if(e.supportsExtraction()) return Pull;
if(e.supportsInsertion()) return Push;
return None;
}
}

View File

@ -0,0 +1,14 @@
package com.mrh0.createaddition.blocks.connector.base;
import com.mrh0.createaddition.rendering.WireNodeRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
public class ConnectorRenderer extends WireNodeRenderer<AbstractConnectorBlockEntity> {
public ConnectorRenderer(BlockEntityRendererProvider.Context context) {
super(context);
}
}

View File

@ -0,0 +1,42 @@
package com.mrh0.createaddition.blocks.connector.base;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.decoration.girder.GirderBlock;
import com.simibubi.create.content.decoration.girder.GirderEncasedShaftBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
public enum ConnectorVariant implements StringRepresentable {
Default("default"),
Girder("girder");
private String name;
ConnectorVariant(String name) {
this.name = name;
}
@Override
public String getSerializedName() {
return this.name;
}
public static ConnectorVariant test(Level level, BlockPos pos, Direction face) {
BlockState state = level.getBlockState(pos);
if(state.is(AllBlocks.METAL_GIRDER.get())) {
if(state.getValue(GirderBlock.TOP) && face == Direction.UP) return Default;
if(state.getValue(GirderBlock.BOTTOM) && face == Direction.DOWN) return Default;
if(state.getValue(GirderBlock.X) && face.getAxis() == Direction.Axis.X) return Default;
if(state.getValue(GirderBlock.Z) && face.getAxis() == Direction.Axis.Z) return Default;
return Girder;
}
if(state.is(AllBlocks.METAL_GIRDER_ENCASED_SHAFT.get())){
if(!state.getValue(GirderEncasedShaftBlock.TOP) && face == Direction.UP) return Girder;
if(!state.getValue(GirderEncasedShaftBlock.BOTTOM) && face == Direction.DOWN) return Girder;
return Default;
}
return Default;
}
}

View File

@ -0,0 +1,54 @@
package com.mrh0.createaddition.blocks.creative_energy;
import com.mrh0.createaddition.index.CABlockEntities;
import com.mrh0.createaddition.shapes.CAShapes;
import com.simibubi.create.content.logistics.crate.CrateBlock;
import com.simibubi.create.foundation.block.IBE;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class CreativeEnergyBlock extends CrateBlock implements IBE<CreativeEnergyBlockEntity> {
public static final VoxelShape CREATIVE_ENERGY_SHAPE = CAShapes.shape(1,0,1,15,16,15).add(0,2,0,16,14,16).build();
public CreativeEnergyBlock(Properties props) {
super(props);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return CREATIVE_ENERGY_SHAPE;
}
@Override
public Class<CreativeEnergyBlockEntity> getBlockEntityClass() {
return CreativeEnergyBlockEntity.class;
}
@Override
public BlockEntityType<? extends CreativeEnergyBlockEntity> getBlockEntityType() {
return CABlockEntities.CREATIVE_ENERGY.get();
}
@Override
public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, boolean isMoving) {
BlockEntity tileentity = state.hasBlockEntity() ? worldIn.getBlockEntity(pos) : null;
if(tileentity != null) {
if(tileentity instanceof CreativeEnergyBlockEntity) {
((CreativeEnergyBlockEntity)tileentity).updateCache();
}
}
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return CABlockEntities.CREATIVE_ENERGY.create(pos, state);
}
}

View File

@ -0,0 +1,91 @@
package com.mrh0.createaddition.blocks.creative_energy;
import com.mrh0.createaddition.energy.CreativeEnergyStorage;
import com.mrh0.createaddition.transfer.EnergyTransferable;
import com.simibubi.create.content.logistics.crate.CrateBlockEntity;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
import team.reborn.energy.api.EnergyStorage;
@SuppressWarnings("UnstableApiUsage")
public class CreativeEnergyBlockEntity extends CrateBlockEntity implements EnergyTransferable{
protected final CreativeEnergyStorage energy;
public CreativeEnergyBlockEntity(BlockEntityType<?> tileEntityTypeIn, BlockPos pos, BlockState state) {
super(tileEntityTypeIn, pos, state);
energy = new CreativeEnergyStorage();
}
private boolean firstTickState = true;
@Override
public void tick() {
super.tick();
if(level.isClientSide())
return;
if(firstTickState)
firstTick();
firstTickState = false;
for(Direction d : Direction.values()) {
EnergyStorage ies = getCachedEnergy(d);
if(ies == null)
continue;
try(Transaction t = Transaction.openOuter()) {
long r = ies.insert(Integer.MAX_VALUE, t);
t.commit();
}
}
}
public void firstTick() {
updateCache();
}
public void updateCache() {
if(level.isClientSide())
return;
for(Direction side : Direction.values()) {
setCache(side, EnergyStorage.SIDED.find(level, worldPosition.relative(side), side.getOpposite()));
}
}
private EnergyStorage escacheUp = null;
private EnergyStorage escacheDown = null;
private EnergyStorage escacheNorth = null;
private EnergyStorage escacheEast = null;
private EnergyStorage escacheSouth = null;
private EnergyStorage escacheWest = null;
public void setCache(Direction side, EnergyStorage storage) {
switch (side) {
case DOWN -> escacheDown = storage;
case EAST -> escacheEast = storage;
case NORTH -> escacheNorth = storage;
case SOUTH -> escacheSouth = storage;
case UP -> escacheUp = storage;
case WEST -> escacheWest = storage;
}
}
@SuppressWarnings("DataFlowIssue")
public EnergyStorage getCachedEnergy(Direction side) {
return switch (side) {
case DOWN -> escacheDown;
case EAST -> escacheEast;
case NORTH -> escacheNorth;
case SOUTH -> escacheSouth;
case UP -> escacheUp;
case WEST -> escacheWest;
};
}
@Override
public EnergyStorage getEnergyStorage(@Nullable Direction direction) {
return energy;
}
}

View File

@ -0,0 +1,28 @@
package com.mrh0.createaddition.blocks.crops;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.CropBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class HarmfulPlantBlock extends CropBlock {
private static final VoxelShape[] SHAPE_BY_AGE = new VoxelShape[]{Block.box(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D), Block.box(0.0D, 0.0D, 0.0D, 16.0D, 3.0D, 16.0D), Block.box(0.0D, 0.0D, 0.0D, 16.0D, 4.0D, 16.0D), Block.box(0.0D, 0.0D, 0.0D, 16.0D, 5.0D, 16.0D), Block.box(0.0D, 0.0D, 0.0D, 16.0D, 6.0D, 16.0D), Block.box(0.0D, 0.0D, 0.0D, 16.0D, 7.0D, 16.0D), Block.box(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D), Block.box(0.0D, 0.0D, 0.0D, 16.0D, 9.0D, 16.0D)};
public HarmfulPlantBlock(BlockBehaviour.Properties pProperties) {
super(pProperties);
}
protected ItemLike getBaseSeedId() {
return Items.CARROT;
}
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
return SHAPE_BY_AGE[pState.getValue(this.getAgeProperty())];
}
}

View File

@ -0,0 +1,31 @@
package com.mrh0.createaddition.blocks.digital_adapter;
import com.mrh0.createaddition.index.CABlockEntities;
import com.simibubi.create.content.equipment.wrench.IWrenchable;
import com.simibubi.create.foundation.block.IBE;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
public class DigitalAdapterBlock extends Block implements IBE<DigitalAdapterBlockEntity>, IWrenchable {
public DigitalAdapterBlock(Properties props) {
super(props);
}
@Override
public Class<DigitalAdapterBlockEntity> getBlockEntityClass() {
return DigitalAdapterBlockEntity.class;
}
@Override
public BlockEntityType<? extends DigitalAdapterBlockEntity> getBlockEntityType() {
return CABlockEntities.DIGITAL_ADAPTER.get();
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return CABlockEntities.DIGITAL_ADAPTER.create(pos, state);
}
}

View File

@ -0,0 +1,139 @@
package com.mrh0.createaddition.blocks.digital_adapter;
import com.simibubi.create.content.contraptions.bearing.MechanicalBearingBlockEntity;
import com.simibubi.create.content.contraptions.elevator.ElevatorPulleyBlockEntity;
import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlockEntity;
import com.simibubi.create.content.contraptions.pulley.PulleyBlockEntity;
import com.simibubi.create.content.fluids.hosePulley.HosePulleyBlockEntity;
import com.simibubi.create.content.kinetics.gauge.SpeedGaugeBlockEntity;
import com.simibubi.create.content.kinetics.gauge.StressGaugeBlockEntity;
import com.simibubi.create.content.kinetics.speedController.SpeedControllerBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import java.util.ArrayList;
import java.util.List;
public class DigitalAdapterBlockEntity extends BlockEntity {
public final List<MutableComponent> textLines;
public static final int MAX_LINES = 16;
public static final MutableComponent EMPTY_LINE = Component.literal("");
public DigitalAdapterBlockEntity(BlockEntityType<?> tileEntityTypeIn, BlockPos pos, BlockState state) {
super(tileEntityTypeIn, pos, state);
textLines = new ArrayList<>();
for(int i = 0; i < MAX_LINES; i++) textLines.add(EMPTY_LINE);
}
private int line = 1;
public void incrementLine() {
line = Math.min(line + 1, DigitalAdapterBlockEntity.MAX_LINES);
}
public void setTextLine(int ln, MutableComponent text) {
if(ln < 1 || ln > MAX_LINES) return;
textLines.set(ln-1, text);
}
public MutableComponent getTextLine(int ln) {
if(ln < 1 || ln > MAX_LINES) return EMPTY_LINE;
return textLines.get(ln-1);
}
public void clearLine(int ln) {
setTextLine(ln, EMPTY_LINE);
}
public void clearAll() {
for(int i = 1; i < MAX_LINES+1; i++)
clearLine(i);
}
public void append(int ln, MutableComponent text) {
setTextLine(ln, getTextLine(ln).append(text));
}
public int getLine() {
return line;
}
public int setLine(int ln) {
return line = ln < 1 || ln > DigitalAdapterBlockEntity.MAX_LINES ? line : ln;
}
public SpeedControllerBlockEntity getSpeedController(Direction dir) {
BlockEntity be = this.level.getBlockEntity(getBlockPos().relative(dir));
if(be == null) return null;
if(be instanceof SpeedControllerBlockEntity scte) return scte;
return null;
}
public PulleyBlockEntity getRopePulley(Direction dir) {
BlockEntity be = this.level.getBlockEntity(getBlockPos().relative(dir));
if(be == null) return null;
if(be instanceof PulleyBlockEntity pte) return pte;
return null;
}
public HosePulleyBlockEntity getHosePulley(Direction dir) {
BlockEntity be = this.level.getBlockEntity(getBlockPos().relative(dir));
if(be == null) return null;
if(be instanceof HosePulleyBlockEntity pte) return pte;
return null;
}
public ElevatorPulleyBlockEntity getElevatorPulley(Direction dir) {
BlockEntity be = this.level.getBlockEntity(getBlockPos().relative(dir));
if(be == null) return null;
if(be instanceof ElevatorPulleyBlockEntity epbe) return epbe;
return null;
}
public MechanicalPistonBlockEntity getMechanicalPiston(Direction dir) {
BlockEntity be = this.level.getBlockEntity(getBlockPos().relative(dir));
if(be == null) return null;
if(be instanceof MechanicalPistonBlockEntity mpte) return mpte;
return null;
}
public MechanicalBearingBlockEntity getMechanicalBearing(Direction dir) {
BlockEntity be = this.level.getBlockEntity(getBlockPos().relative(dir));
if(be == null) return null;
if(be instanceof MechanicalBearingBlockEntity mpte) return mpte;
return null;
}
public StressGaugeBlockEntity getStressGauge(Direction dir) {
BlockEntity be = this.level.getBlockEntity(getBlockPos().relative(dir));
if(be == null) return null;
if(be instanceof StressGaugeBlockEntity sgte) return sgte;
return null;
}
public SpeedGaugeBlockEntity getSpeedGauge(Direction dir) {
BlockEntity be = this.level.getBlockEntity(getBlockPos().relative(dir));
if(be == null) return null;
if(be instanceof SpeedGaugeBlockEntity sgte) return sgte;
return null;
}
public void setTargetSpeed(Direction dir, int speed) {
SpeedControllerBlockEntity scte = getSpeedController(dir);
if(scte == null) return;
ISpeedControllerAdapter sts = (ISpeedControllerAdapter)((Object)scte);
sts.setTargetSpeed(speed);
}
public int getTargetSpeed(Direction dir) {
SpeedControllerBlockEntity scte = getSpeedController(dir);
if(scte == null) return 0;
ISpeedControllerAdapter sts = (ISpeedControllerAdapter)((Object)scte);
return sts.getTargetSpeed();
}
}

View File

@ -0,0 +1,19 @@
package com.mrh0.createaddition.blocks.digital_adapter;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.level.block.Block;
public class DigitalAdapterBlockItem extends BlockItem {
public DigitalAdapterBlockItem(Block block, Properties props) {
super(block, props);
}
/*public void fillItemCategory(CreativeModeTab tab, NonNullList<ItemStack> stacks) {
if (tab == CreativeModeTab.TAB_SEARCH) {
super.fillItemCategory(tab, stacks);
}
if(tab == ModGroup.MAIN && CreateAddition.CC_ACTIVE) {
super.fillItemCategory(tab, stacks);
}
}*/
}

View File

@ -0,0 +1,18 @@
package com.mrh0.createaddition.blocks.digital_adapter;
import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext;
import com.simibubi.create.content.redstone.displayLink.source.DisplaySource;
import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats;
import net.minecraft.network.chat.MutableComponent;
import java.util.List;
public class DigitalAdapterDisplaySource extends DisplaySource {
@Override
public List<MutableComponent> provideText(DisplayLinkContext context, DisplayTargetStats stats) {
if(context.getSourceBlockEntity() == null) return List.of();
if(context.getSourceBlockEntity() instanceof DigitalAdapterBlockEntity date)
return date.textLines;
return List.of();
}
}

View File

@ -0,0 +1,6 @@
package com.mrh0.createaddition.blocks.digital_adapter;
public interface ISpeedControllerAdapter {
void setTargetSpeed(int speed);
int getTargetSpeed();
}

View File

@ -0,0 +1,136 @@
package com.mrh0.createaddition.blocks.electric_motor;
import java.util.Random;
import com.mrh0.createaddition.index.CABlockEntities;
import com.mrh0.createaddition.shapes.CAShapes;
import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock;
import com.simibubi.create.content.kinetics.base.IRotate;
import com.simibubi.create.foundation.block.IBE;
import com.simibubi.create.foundation.utility.VoxelShaper;
import io.github.fabricators_of_create.porting_lib.block.ConnectableRedstoneBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class ElectricMotorBlock extends DirectionalKineticBlock implements IBE<ElectricMotorBlockEntity>, ConnectableRedstoneBlock {
public static final VoxelShaper ELECTRIC_MOTOR_SHAPE = CAShapes.shape(0, 5, 0, 16, 11, 16).add(3, 0, 3, 13, 14, 13)
.forDirectional();
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public ElectricMotorBlock(Properties properties) {
super(properties);
registerDefaultState(defaultBlockState().setValue(POWERED, false));
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(POWERED);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return ELECTRIC_MOTOR_SHAPE.get(state.getValue(FACING));
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
Direction preferred = getPreferredFacing(context);
if ((context.getPlayer() != null && context.getPlayer().isShiftKeyDown()) || preferred == null)
return super.getStateForPlacement(context);
return defaultBlockState().setValue(FACING, preferred);
}
@Override
public Class<ElectricMotorBlockEntity> getBlockEntityClass() {
return ElectricMotorBlockEntity.class;
}
@Override
public BlockEntityType<? extends ElectricMotorBlockEntity> getBlockEntityType() {
return CABlockEntities.ELECTRIC_MOTOR.get();
}
@Override
public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) {
return face == state.getValue(FACING);
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.getValue(FACING).getAxis();
}
@Override
public boolean hideStressImpact() {
return true;
}
public void setPowered(Level world, BlockPos pos, boolean powered) {
world.setBlock(pos, world.getBlockState(pos).setValue(POWERED, powered), 3);
}
@Override
public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) {
return true;
}
/*
@Override
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos from, boolean b) {
if (!world.isClientSide) {
boolean flag = state.getValue(POWERED);
if (flag != world.hasNeighborSignal(pos)) {
if (flag)
world.scheduleTick(pos, this, 4);
else
world.setBlock(pos, state.cycle(POWERED), 2);
}
}
}
*/
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos from, boolean b) {
if (!world.isClientSide) {
boolean flag = state.getValue(POWERED);
if (flag != world.hasNeighborSignal(pos)) {
if (flag){
setPowered(world, pos, false);
world.scheduleTick(pos, this, 4);
}
else{
setPowered(world, pos, true);
world.setBlock(pos, state.cycle(POWERED), 2);
}
}
}
}
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource pRandom) {
if (state.getValue(POWERED) && !world.hasNeighborSignal(pos))
world.setBlock(pos, state.cycle(POWERED), 2);
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return CABlockEntities.ELECTRIC_MOTOR.create(pos, state);
}
}

View File

@ -0,0 +1,255 @@
package com.mrh0.createaddition.blocks.electric_motor;
import java.util.List;
import com.mrh0.createaddition.CreateAddition;
import com.mrh0.createaddition.blocks.tesla_coil.TeslaCoilBlock;
import com.mrh0.createaddition.compat.computercraft.ElectricMotorPeripheral;
import com.mrh0.createaddition.compat.computercraft.Peripherals;
import com.mrh0.createaddition.config.Config;
import com.mrh0.createaddition.energy.InternalEnergyStorage;
import com.mrh0.createaddition.index.CABlocks;
import com.mrh0.createaddition.sound.CASoundScapes;
import com.mrh0.createaddition.transfer.EnergyTransferable;
import com.mrh0.createaddition.util.Util;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.kinetics.base.GeneratingKineticBlockEntity;
import com.simibubi.create.content.kinetics.motor.KineticScrollValueBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform;
import com.simibubi.create.foundation.blockEntity.behaviour.scrollValue.ScrollValueBehaviour;
import com.simibubi.create.foundation.utility.Lang;
import io.github.fabricators_of_create.porting_lib.util.LazyOptional;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
import team.reborn.energy.api.EnergyStorage;
public class ElectricMotorBlockEntity extends GeneratingKineticBlockEntity implements EnergyTransferable {
protected ScrollValueBehaviour generatedSpeed;
protected final InternalEnergyStorage energy;
private final LazyOptional<EnergyStorage> lazyEnergy;
private boolean cc_update_rpm = false;
private int cc_new_rpm = 32;
private boolean active = false;
public ElectricMotorBlockEntity(BlockEntityType<? extends ElectricMotorBlockEntity> type, BlockPos pos, BlockState state) {
super(type, pos, state);
energy = new InternalEnergyStorage(Config.ELECTRIC_MOTOR_CAPACITY.get(), Config.ELECTRIC_MOTOR_MAX_INPUT.get(), 0);
lazyEnergy = LazyOptional.of(() -> energy);
setLazyTickRate(20);
}
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
super.addBehaviours(behaviours);
CenteredSideValueBoxTransform slot =
new CenteredSideValueBoxTransform((motor, side) -> motor.getValue(ElectricMotorBlock.FACING) == side.getOpposite());
generatedSpeed = new KineticScrollValueBehaviour(Lang.translateDirect("generic.speed"), this, slot);
generatedSpeed.between(-Config.ELECTRIC_MOTOR_RPM_RANGE.get(), Config.ELECTRIC_MOTOR_RPM_RANGE.get());
generatedSpeed.value = 32;
//generatedSpeed.withUnit(i -> Lang.translateDirect("generic.unit.rpm"));
generatedSpeed.withCallback(i -> this.updateGeneratedRotation(i));
//generatedSpeed.withStepFunction(ElectricMotorTileEntity::step);
behaviours.add(generatedSpeed);
}
public static int step(ScrollValueBehaviour.StepContext context) {
int current = context.currentValue;
int step = 1;
if (!context.shift) {
int magnitude = Math.abs(current) - (context.forward == current > 0 ? 0 : 1);
if (magnitude >= 4) step *= 4;
if (magnitude >= 32) step *= 4;
if (magnitude >= 128) step *= 4;
}
return step;
}
public float calculateAddedStressCapacity() {
float capacity = Config.MAX_STRESS.get()/256f;
this.lastCapacityProvided = capacity;
return capacity;
}
@Override
public boolean addToGoggleTooltip(List<Component> tooltip, boolean isPlayerSneaking) {
super.addToGoggleTooltip(tooltip, isPlayerSneaking);
tooltip.add(Component.literal(spacing).append(Component.translatable(CreateAddition.MODID + ".tooltip.energy.consumption").withStyle(ChatFormatting.GRAY)));
tooltip.add(Component.literal(spacing).append(Component.literal(" " + Util.format(getEnergyConsumptionRate(generatedSpeed.getValue())) + "fe/t ")
.withStyle(ChatFormatting.AQUA)).append(Lang.translateDirect("gui.goggles.at_current_speed").withStyle(ChatFormatting.DARK_GRAY)));
return true;
}
public void updateGeneratedRotation(int i) {
super.updateGeneratedRotation();
cc_new_rpm = i;
}
@Override
public void initialize() {
super.initialize();
if (!hasSource() || getGeneratedSpeed() > getTheoreticalSpeed())
updateGeneratedRotation();
}
@Override
public float getGeneratedSpeed() {
if (!CABlocks.ELECTRIC_MOTOR.has(getBlockState())) return 0;
return convertToDirection(active ? generatedSpeed.getValue() : 0, getBlockState().getValue(ElectricMotorBlock.FACING));
}
@Override
protected Block getStressConfigKey() {
return AllBlocks.WATER_WHEEL.get();
}
@SuppressWarnings("unused")
public InternalEnergyStorage getEnergyStorage() {
return energy;
}
@Nullable
@Override
public EnergyStorage getEnergyStorage(@Nullable Direction side) {
return lazyEnergy.getValueUnsafer();
// if(CreateAddition.CC_ACTIVE)
// Peripherals.isPeripheral(getLevel(), getBlockPos(), side);
}
public boolean isEnergyInput(Direction side) {
return true;
}
public boolean isEnergyOutput(Direction side) {
return false;
}
@Override
public void read(CompoundTag compound, boolean clientPacket) {
super.read(compound, clientPacket);
energy.read(compound);
active = compound.getBoolean("active");
}
@Override
public void write(CompoundTag compound, boolean clientPacket) {
super.write(compound, clientPacket);
energy.write(compound);
compound.putBoolean("active", active);
}
@Override
public void lazyTick() {
super.lazyTick();
cc_antiSpam = 5;
}
public static int getEnergyConsumptionRate(int rpm) {
return Math.abs(rpm) > 0 ? (int)Math.max((double)Config.FE_RPM.get() * ((double)Math.abs(rpm) / 256d), (double)Config.ELECTRIC_MOTOR_MINIMUM_CONSUMPTION.get()) : 0;
}
@Override
public void remove() {
lazyEnergy.invalidate();
super.remove();
}
// CC
int cc_antiSpam = 0;
boolean first = true;
@Override
public void tick() {
super.tick();
if(first) {
updateGeneratedRotation();
first = false;
}
if(cc_update_rpm && cc_antiSpam > 0) {
generatedSpeed.setValue(cc_new_rpm);
cc_update_rpm = false;
cc_antiSpam--;
updateGeneratedRotation();
}
//Old Lazy
if(level.isClientSide()) return;
int con = getEnergyConsumptionRate(generatedSpeed.getValue());
if(!active) {
if(energy.getAmount() > con * 2L && !getBlockState().getValue(ElectricMotorBlock.POWERED)) {
active = true;
updateGeneratedRotation();
}
}
else {
long ext = energy.internalConsumeEnergy(con);
if (ext < con || getBlockState().getValue(ElectricMotorBlock.POWERED)) {
active = false;
updateGeneratedRotation();
}
}
}
@Override
public void tickAudio() {
super.tickAudio();
if (!active) return;
CASoundScapes.play(CASoundScapes.AmbienceGroup.DYNAMO, worldPosition, 1);
}
public static int getDurationAngle(int deg, float initialProgress, float speed) {
speed = Math.abs(speed);
deg = Math.abs(deg);
if(speed < 0.1f) return 0;
double degreesPerTick = (speed * 360) / 60 / 20;
return (int) ((1 - initialProgress) * deg / degreesPerTick + 1);
}
public static int getDurationDistance(int dis, float initialProgress, float speed) {
speed = Math.abs(speed);
dis = Math.abs(dis);
if(speed < 0.1f) return 0;
double metersPerTick = speed / 512;
return (int) ((1 - initialProgress) * dis / metersPerTick);
}
public boolean setRPM(int rpm) {
rpm = Math.max(Math.min(rpm, Config.ELECTRIC_MOTOR_RPM_RANGE.get()), -Config.ELECTRIC_MOTOR_RPM_RANGE.get());
cc_new_rpm = rpm;
cc_update_rpm = true;
return cc_antiSpam > 0;
}
public int getRPM() {
return cc_new_rpm;//generatedSpeed.getValue();
}
public int getGeneratedStress() {
return (int) calculateAddedStressCapacity();
}
public int getEnergyConsumption() {
return getEnergyConsumptionRate(generatedSpeed.getValue());
}
@SuppressWarnings("unused")
public boolean isPoweredState() {
return getBlockState().getValue(TeslaCoilBlock.POWERED);
}
}

View File

@ -0,0 +1,23 @@
package com.mrh0.createaddition.blocks.electric_motor;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityRenderer;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context;
import net.minecraft.world.level.block.state.BlockState;
public class ElectricMotorRenderer extends KineticBlockEntityRenderer {
public ElectricMotorRenderer(Context dispatcher) {
super(dispatcher);
}
@Override
protected SuperByteBuffer getRotatedModel(KineticBlockEntity te, BlockState state) {
return CachedBufferer.partialFacing(AllPartialModels.SHAFT_HALF, state);
}
}

View File

@ -0,0 +1,272 @@
/*package com.mrh0.createaddition.blocks.energy_meter;
import com.mrh0.createaddition.energy.IWireNode;
import com.mrh0.createaddition.energy.NodeRotation;
import com.mrh0.createaddition.index.CATileEntities;
import com.mrh0.createaddition.shapes.CAShapes;
import com.simibubi.create.content.contraptions.ITransformableBlock;
import com.simibubi.create.content.contraptions.StructureTransform;
import com.simibubi.create.content.equipment.wrench.IWrenchable;
import com.simibubi.create.foundation.block.IBE;
import com.simibubi.create.foundation.utility.VoxelShaper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.server.level.ServerLevel;
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.item.context.BlockPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.ticks.TickPriority;
import java.util.Random;
public class EnergyMeterBlock extends Block implements IBE<EnergyMeterTileEntity>, IWrenchable, ITransformableBlock {
public static final BooleanProperty VERTICAL = BooleanProperty.create("vertical");
public static final DirectionProperty HORIZONTAL_FACING = BlockStateProperties.HORIZONTAL_FACING;
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public static final VoxelShape HORIZONTAL_SHAPE_MAIN = Block.box(0, 0, 0, 16, 2, 16);
public static final VoxelShape HORIZONTAL_SHAPE_X = Shapes.or(HORIZONTAL_SHAPE_MAIN, Block.box(1, 0, 6, 5, 7, 10), Block.box(11, 0, 6, 15, 7, 10));
public static final VoxelShape HORIZONTAL_SHAPE_Z = Shapes.or(HORIZONTAL_SHAPE_MAIN, Block.box(6, 0, 1, 10, 7, 5), Block.box(6, 0, 11, 10, 7, 15));
//public static final VoxelShaper VERTICAL_SHAPE = CAShapes.shape(0, 0, 14, 16, 16, 16).add(1, 6, 9, 5, 10, 16).add(11, 6, 9, 15, 10, 16).forDirectional();
public static final VoxelShaper VERTICAL_SHAPE = CAShapes.shape(0, 0, 0, 16, 2, 16).add(1, 0, 6, 5, 7, 10).add(11, 0, 6, 15, 7, 10).forDirectional();
protected static final VoxelShape WEST_SHAPE = Block.box(0, 0, 0, 2, 16, 16);
protected static final VoxelShape EAST_SHAPE = Block.box(14, 0, 0, 16, 16, 16);
protected static final VoxelShape NORTH_SHAPE = Block.box(0, 0, 0, 16, 16, 2);
protected static final VoxelShape SOUTH_SHAPE = Block.box(0, 0, 14, 16, 16, 16);
public EnergyMeterBlock(Properties properties) {
super(properties);
this.registerDefaultState(this.defaultBlockState()
.setValue(VERTICAL, false)
.setValue(HORIZONTAL_FACING, Direction.NORTH)
.setValue(POWERED, false)
.setValue(NodeRotation.ROTATION, NodeRotation.NONE));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
Direction dir = state.getValue(HORIZONTAL_FACING);
if(state.getValue(VERTICAL))
return VERTICAL_SHAPE.get(dir.getOpposite());
Axis axis = dir.getAxis();
return axis == Axis.X ? HORIZONTAL_SHAPE_X : HORIZONTAL_SHAPE_Z;
}
@Override
public Class<EnergyMeterTileEntity> getBlockEntityClass() {
return EnergyMeterTileEntity.class;
}
@Override
public BlockEntityType<? extends EnergyMeterTileEntity> getBlockEntityType() {
return CATileEntities.REDSTONE_RELAY.get();
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> builder) {
builder.add(VERTICAL, HORIZONTAL_FACING, POWERED, NodeRotation.ROTATION);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext c) {
if(c.getClickedFace().getAxis() == Axis.Y)
return defaultBlockState().setValue(HORIZONTAL_FACING, c.getPlayer().isShiftKeyDown() ? c.getHorizontalDirection().getCounterClockWise() : c.getHorizontalDirection().getClockWise()).setValue(VERTICAL, false);
else
return defaultBlockState().setValue(HORIZONTAL_FACING, c.getClickedFace().getOpposite()).setValue(VERTICAL, true);
}
@Override
public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, Random rand) {
boolean flag = state.getValue(POWERED);
boolean flag1 = this.shouldBePowered(worldIn, pos, state);
if (flag && !flag1) {
worldIn.setBlock(pos, state.setValue(POWERED, Boolean.valueOf(false)), 2);
}
else if (!flag) {
worldIn.setBlock(pos, state.setValue(POWERED, Boolean.valueOf(true)), 2);
}
}
@Override
public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, boolean isMoving) {
if (state.canSurvive(worldIn, pos))
this.updateState(worldIn, pos, state);
else {
BlockEntity tileentity = state.hasBlockEntity() ? worldIn.getBlockEntity(pos) : null;
dropResources(state, worldIn, pos, tileentity);
worldIn.removeBlock(pos, false);
for (Direction direction : Direction.values())
worldIn.updateNeighborsAt(pos.relative(direction), this);
}
}
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
boolean vertical = state.getValue(VERTICAL);
Direction direction = state.getValue(HORIZONTAL_FACING);
return canSupportCenter(world, vertical ? pos.relative(direction) : pos.below(), vertical ? direction.getOpposite() : Direction.UP);
}
protected void updateState(Level worldIn, BlockPos pos, BlockState state) {
boolean flag = state.getValue(POWERED);
boolean flag1 = this.shouldBePowered(worldIn, pos, state);
if (flag != flag1 && !worldIn.getBlockTicks().willTickThisTick(pos, this)) {
TickPriority tickpriority = TickPriority.VERY_HIGH;
worldIn.scheduleTick(pos, this, this.getDelay(state), tickpriority);
}
}
private int getDelay(BlockState state) {
return 2;
}
protected boolean shouldBePowered(Level worldIn, BlockPos pos, BlockState state) {
return this.calculateInputStrength(worldIn, pos, state) > 0;
}
protected int calculateInputStrength(Level worldIn, BlockPos pos, BlockState state) {
boolean vertical = state.getValue(VERTICAL);
if(vertical) {
BlockPos blockpos1 = pos.relative(Direction.UP);
BlockPos blockpos2 = pos.relative(Direction.DOWN);
int i = Math.max(worldIn.getSignal(blockpos1, Direction.DOWN), worldIn.getSignal(blockpos2, Direction.UP));
BlockState blockstate1 = worldIn.getBlockState(blockpos1);
BlockState blockstate2 = worldIn.getBlockState(blockpos2);
return Math.max(i, Math.max(blockstate1.is(Blocks.REDSTONE_WIRE) ? blockstate1.getValue(RedStoneWireBlock.POWER) : 0, blockstate2.is(Blocks.REDSTONE_WIRE) ? blockstate2.getValue(RedStoneWireBlock.POWER) : 0));
}
else {
Direction direction = state.getValue(HORIZONTAL_FACING);
BlockPos blockpos1 = pos.relative(direction.getClockWise());
BlockPos blockpos2 = pos.relative(direction.getCounterClockWise());
int i = Math.max(worldIn.getSignal(blockpos1, direction.getClockWise()), worldIn.getSignal(blockpos2, direction.getCounterClockWise()));
int j = Math.max(worldIn.getDirectSignal(blockpos1, direction.getClockWise()), worldIn.getDirectSignal(blockpos2, direction.getCounterClockWise()));
BlockState blockstate1 = worldIn.getBlockState(blockpos1);
BlockState blockstate2 = worldIn.getBlockState(blockpos2);
return Math.max(Math.max(i, j), Math.max(blockstate1.is(Blocks.REDSTONE_WIRE) ? blockstate1.getValue(RedStoneWireBlock.POWER) : 0, blockstate2.is(Blocks.REDSTONE_WIRE) ? blockstate2.getValue(RedStoneWireBlock.POWER) : 0));
}
}
protected int getPowerOnSides(LevelReader worldIn, BlockPos pos, Direction direction) {
Direction direction1 = direction.getClockWise();
Direction direction2 = direction.getCounterClockWise();
return Math.max(this.getPowerOnSide(worldIn, pos.relative(direction1), direction2), this.getPowerOnSide(worldIn, pos.relative(direction2), direction1));
}
protected int getPowerOnSide(LevelReader worldIn, BlockPos pos, Direction side) {
BlockState blockstate = worldIn.getBlockState(pos);
if (this.isAlternateInput(blockstate)) {
if (blockstate.is(Blocks.REDSTONE_BLOCK))
return 15;
else
return blockstate.is(Blocks.REDSTONE_WIRE) ? blockstate.getValue(RedStoneWireBlock.POWER) : worldIn.getDirectSignal(pos, side);
} else
return 0;
}
protected boolean isAlternateInput(BlockState state) {
return state.isSignalSource();
}
@Override
public void setPlacedBy(Level worldIn, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
if (this.shouldBePowered(worldIn, pos, state)) {
worldIn.scheduleTick(pos, this, 1);
}
}
@Override
public void playerWillDestroy(Level worldIn, BlockPos pos, BlockState state, Player player) {
super.playerWillDestroy(worldIn, pos, state, player);
if (worldIn.isClientSide()) return;
BlockEntity te = worldIn.getBlockEntity(pos);
if (te == null) return;
if (!(te instanceof IWireNode cte)) return;
cte.dropWires(worldIn, !player.isCreative());
}
@Override
public InteractionResult onSneakWrenched(BlockState state, UseOnContext c) {
BlockEntity te = c.getLevel().getBlockEntity(c.getClickedPos());
if(te == null)
return IWrenchable.super.onSneakWrenched(state, c);
if(!(te instanceof IWireNode))
return IWrenchable.super.onSneakWrenched(state, c);
IWireNode cte = (IWireNode) te;
if (!c.getLevel().isClientSide())
cte.dropWires(c.getLevel(), c.getPlayer(), !c.getPlayer().isCreative());
return IWrenchable.super.onSneakWrenched(state, c);
}
@Override
public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) {
if(pos == null || side == null || state == null || world == null)
return false;
return !state.getValue(VERTICAL).booleanValue() && side.getAxis() != state.getValue(HORIZONTAL_FACING).getAxis();
}
private BlockState fromRotation(BlockState state, Direction dir) {
return state.setValue(HORIZONTAL_FACING, dir);
}
@Override
public BlockState rotate(BlockState state, Rotation direction) {
return fromRotation(state, direction.rotate(state.getValue(HORIZONTAL_FACING)));
}
@Override
public BlockState rotate(BlockState state, LevelAccessor world, BlockPos pos, Rotation direction) {
return rotate(state, direction);
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return fromRotation(state, mirror.mirror(state.getValue(HORIZONTAL_FACING)));
}
@Override
public BlockState transform(BlockState state, StructureTransform transform) {
NodeRotation rotation = NodeRotation.get(transform.rotationAxis, transform.rotation);
// Handle default rotation & mirroring.
if (transform.mirror != null) state = mirror(state, transform.mirror);
if (transform.rotationAxis == Axis.Y) state = rotate(state, transform.rotation);
// Set the rotation state, which will be used to update the nodes.
return state.setValue(NodeRotation.ROTATION, rotation);
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return CATileEntities.REDSTONE_RELAY.create(pos, state);
}
}
*/

Some files were not shown because too many files have changed in this diff Show More