Compare commits
20 Commits
a678f3dd02
...
szar-26.3.
| Author | SHA1 | Date | |
|---|---|---|---|
| 4bc0779967 | |||
| ab32bc230e | |||
| 034fac759c | |||
| aa07b71ed1 | |||
| 20027a974a | |||
| 539e4ad637 | |||
| 1313fd97db | |||
| b9393d179e | |||
| 5a42ec1e9e | |||
| 245f5ea035 | |||
| ae5783aa1d | |||
| 99a04d5b43 | |||
| 6fc34318bf | |||
| 0a120a8ee6 | |||
| 0501d8ee09 | |||
| 7c779124dc | |||
| 9c48313990 | |||
| 8869dc4087 | |||
| 7e5700d723 | |||
| d44fb3ca9a |
146
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,146 @@
|
||||
name: Build Minecraft Mod
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 21
|
||||
|
||||
- name: Ensure Gradle wrapper exists
|
||||
run: |
|
||||
if [ ! -f "./gradlew" ]; then
|
||||
echo "ERROR: gradlew not found in repository!"
|
||||
echo "Please run 'gradle wrapper' locally and push the files."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Make gradlew executable
|
||||
run: chmod +x ./gradlew
|
||||
|
||||
- name: Build mod
|
||||
run: ./gradlew build --no-daemon --max-workers=1 -Dorg.gradle.jvmargs="-Xmx1g -XX:MaxMetaspaceSize=256m"
|
||||
|
||||
- name: Read mod info
|
||||
id: mod_info
|
||||
run: |
|
||||
NAME=$(grep "^archives_base_name" gradle.properties | cut -d'=' -f2)
|
||||
VERSION=$(grep "^mod_version" gradle.properties | cut -d'=' -f2)
|
||||
|
||||
if [ -z "$NAME" ] || [ -z "$VERSION" ]; then
|
||||
echo "Failed to read mod info"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
JAR="build/libs/${NAME}-${VERSION}.jar"
|
||||
|
||||
if [ ! -f "$JAR" ]; then
|
||||
echo "Jar not found: $JAR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "NAME=$NAME" >> $GITEA_ENV
|
||||
echo "VERSION=$VERSION" >> $GITEA_ENV
|
||||
echo "JAR=$JAR" >> $GITEA_ENV
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: minecraft-mod
|
||||
path: ${{ env.JAR }}
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: minecraft-mod
|
||||
path: ./release-artifacts/
|
||||
|
||||
- name: Install jq
|
||||
run: apt-get update && apt-get install -y jq
|
||||
|
||||
- name: Read mod info from gradle.properties
|
||||
id: mod_info
|
||||
run: |
|
||||
NAME=$(grep "^archives_base_name" gradle.properties | cut -d'=' -f2)
|
||||
VERSION=$(grep "^mod_version" gradle.properties | cut -d'=' -f2)
|
||||
|
||||
if [ -z "$NAME" ] || [ -z "$VERSION" ]; then
|
||||
echo "Failed to read mod info"
|
||||
exit 1
|
||||
fi
|
||||
JAR="${NAME}-${VERSION}.jar"
|
||||
echo "NAME=$NAME" >> $GITEA_ENV
|
||||
echo "VERSION=$VERSION" >> $GITEA_ENV
|
||||
echo "JAR=$JAR" >> $GITEA_ENV
|
||||
- name: Determine tag
|
||||
run: |
|
||||
BASE="${NAME}-${VERSION}"
|
||||
TAG="$BASE"
|
||||
i=1
|
||||
|
||||
while true; do
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
|
||||
"${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases/tags/$TAG")
|
||||
|
||||
if [ "$STATUS" = "404" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
TAG="${BASE}($i)"
|
||||
i=$((i+1))
|
||||
done
|
||||
|
||||
echo "TAG=$TAG" >> $GITEA_ENV
|
||||
|
||||
- name: Create release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: build/libs/*.jar
|
||||
tag_name: ${{ env.TAG }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITEATOKEN }}
|
||||
|
||||
- name: Get release ID
|
||||
run: |
|
||||
RELEASE_ID=$(curl -s \
|
||||
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
|
||||
"${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases/tags/${TAG}" \
|
||||
| jq -r '.id')
|
||||
|
||||
echo "RELEASE_ID=$RELEASE_ID" >> $GITEA_ENV
|
||||
|
||||
- name: Upload the mod JAR
|
||||
run: |
|
||||
# Use the artifact downloaded in the previous step
|
||||
JAR_FILE=$(ls ./release-artifacts/*.jar | head -n 1)
|
||||
|
||||
if [ ! -f "$JAR_FILE" ]; then
|
||||
echo "Error: JAR not found in ./release-artifacts/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: token ${{ secrets.GITEATOKEN }}" \
|
||||
-H "Content-Type: application/java-archive" \
|
||||
--data-binary @"$JAR_FILE" \
|
||||
"${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases/${RELEASE_ID}/assets?name=$(basename $JAR_FILE)"
|
||||
55
README.md
@@ -1,34 +1,49 @@
|
||||

|
||||
|
||||
# Szar
|
||||
*Szar means <u>Shit</u> in Hungarian*
|
||||
|
||||
Ez egy privát, kísérleti fabric Minecraft 1.20.1 mod.
|
||||
Szar is a private, experimental Fabric Minecraft 1.20.1 mod created as a school programming project and as a joke between classmates and friends.
|
||||
|
||||
## FIGYELMEZTETÉS
|
||||
Ez a mod 18+ tartalmat tartalmaz, beleértve:
|
||||
- sértő, rasszista vagy provokatív elemeket
|
||||
- felnőtteknek szóló témákat
|
||||
- illegális vagy valós életben elfogadhatatlan dolgok fiktív megjelenítését
|
||||
The mod features a wide variety of over-the-top, humorous, and intentionally absurd ideas. Its content is entirely fictional and parody-style, designed for fun and creativity, and **not meant to be taken seriously**.
|
||||
|
||||
A mod **nem oktatási célú**, **nem támogatja**, és **nem népszerűsíti** ezeket a témákat.
|
||||
Kizárólag saját használatra készült.
|
||||
## Features
|
||||
|
||||
Ha ezek a tartalmak zavaróak számodra, **NE használd**.
|
||||
A mod használata **kizárólag saját felelősségre történik**.
|
||||
This mod includes (but is not limited to):
|
||||
|
||||
- Crazy functional blocks
|
||||
- Custom music discs
|
||||
- Weapons such as guns
|
||||
- Casinos with multiple gambling machines
|
||||
- Police systems
|
||||
- Drugs, memes, and historical figures
|
||||
- Nukes and backrooms
|
||||
- Board games
|
||||
- And basically anything that would be “crazy in Minecraft”
|
||||
|
||||
If you can imagine it being absurd or over-the-top in Minecraft, chances are this mod has it, if not, please contact me and it will!
|
||||
|
||||
# Hungarian / Magyar
|
||||
# Szar
|
||||
*buzi ai forditas mer lusta vagyok*
|
||||
|
||||
|
||||
# Shit
|
||||
A Szar egy privát, kísérleti Fabric Minecraft 1.20.1 mod, amelyet iskolai programozási projektként és viccnek készítettek osztálytársak és barátok között.
|
||||
|
||||
This is a private, experimental 1.20.1 fabric Minecraft mod.
|
||||
A mod számos túlzó, humoros és szándékosan abszurd ötletet tartalmaz. A tartalom teljesen fiktív és paródiaszerű, szórakoztatásra és kreativitásra készült, **nem szabad komolyan venni**.
|
||||
|
||||
## WARNING (EN)
|
||||
### Funkciók
|
||||
|
||||
This mod contains **18+ content**, including the following:
|
||||
- offensive, provocative, or otherwise inappropriate themes
|
||||
- adult themed content
|
||||
- fictional representations of content that would be unacceptable or illegal in real life
|
||||
A mod tartalmaz (de nem kizárólagosan):
|
||||
|
||||
This mod is **not intended for public use**, does **not endorse** any of the themes depicted, and was created **for personal use only**.
|
||||
- Őrült, funkcionális blokkok
|
||||
- Egyedi zenélőlemezek
|
||||
- Fegyverek, például pisztolyok
|
||||
- Kaszinók többféle szerencsejáték géppel
|
||||
- Rendőrségi rendszerek
|
||||
- Drogok, mémek és történelmi személyek
|
||||
- Nukleáris fegyverek és backroomból inspirált helyszínek
|
||||
- Társasjátékok
|
||||
- És gyakorlatilag bármi, ami “őrült” lenne a Minecraftban
|
||||
|
||||
If you find such content disturbing or offensive, **do not use this mod**.
|
||||
Use at your **own responsibility**.
|
||||
Ha el tudod képzelni, hogy valami túlzó vagy őrült lehet a Minecraftban, nagy valószínűséggel ez a mod tartalmazza, ha meg nem, akkor írj rám, és fogja!
|
||||
@@ -6,7 +6,7 @@ minecraft_version=1.20.1
|
||||
yarn_mappings=1.20.1+build.10
|
||||
loader_version=0.18.3
|
||||
# Mod Properties
|
||||
mod_version=26.3.25
|
||||
mod_version=26.3.30
|
||||
maven_group=dev.tggamesyt
|
||||
archives_base_name=szar
|
||||
# Dependencies
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
248
gradlew
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015 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.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# 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/platforms/jvm/plugins-application/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 -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || 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
|
||||
|
||||
|
||||
|
||||
# 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=SC2039,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=SC2039,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" )
|
||||
|
||||
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 optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# 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" "$@"
|
||||
@@ -4,13 +4,17 @@ import dev.tggamesyt.szar.BlueprintBlockEntity;
|
||||
import net.minecraft.block.BlockRenderType;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.LightmapTextureManager;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.WorldRenderer;
|
||||
import net.minecraft.client.render.block.BlockRenderManager;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
|
||||
public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<BlueprintBlockEntity> {
|
||||
@@ -20,6 +24,7 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<Bluepri
|
||||
@Override
|
||||
public void render(BlueprintBlockEntity entity, float tickDelta, MatrixStack matrices,
|
||||
VertexConsumerProvider vertexConsumers, int light, int overlay) {
|
||||
|
||||
if (!entity.hasStoredBlock()) return;
|
||||
|
||||
String storedId = entity.getStoredBlockId();
|
||||
@@ -31,72 +36,38 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<Bluepri
|
||||
BlockState storedState = block.getDefaultState();
|
||||
if (storedState.getRenderType() == BlockRenderType.INVISIBLE) return;
|
||||
|
||||
// Get the shape/state of the blueprint block itself
|
||||
BlockState blueprintState = entity.getCachedState();
|
||||
|
||||
// We want to render the stored block's TEXTURE but on the blueprint block's SHAPE.
|
||||
// The way to do this: find the model for the blueprint block shape,
|
||||
// but swap in the stored block's sprite via a custom render layer.
|
||||
// Simplest approach: render the blueprint block's model with the stored block's
|
||||
// textures by remapping the sprite.
|
||||
var renderer = MinecraftClient.getInstance().getBlockRenderManager();
|
||||
|
||||
BlockRenderManager renderer = MinecraftClient.getInstance().getBlockRenderManager();
|
||||
|
||||
matrices.push();
|
||||
|
||||
// Render the blueprint shape using the stored block's texture
|
||||
// by temporarily using the stored block's model sprites on our shape
|
||||
renderWithStoredTexture(entity, blueprintState, storedState, matrices, vertexConsumers, light, overlay, renderer);
|
||||
|
||||
matrices.pop();
|
||||
}
|
||||
|
||||
private void renderWithStoredTexture(BlueprintBlockEntity entity, BlockState blueprintState,
|
||||
BlockState storedState, MatrixStack matrices,
|
||||
VertexConsumerProvider vertexConsumers, int light, int overlay,
|
||||
BlockRenderManager renderer) {
|
||||
// Get the first (main) sprite from the stored block's model
|
||||
var storedModel = renderer.getModel(storedState);
|
||||
var blueprintModel = renderer.getModel(blueprintState);
|
||||
|
||||
var sprites = storedModel.getParticleSprite(); // main texture of stored block
|
||||
var wrappedModel = new BlueprintWrappedModel(
|
||||
blueprintModel,
|
||||
storedModel,
|
||||
blueprintState,
|
||||
storedState, entity
|
||||
);
|
||||
|
||||
// Render blueprint model quads, replacing its texture with stored block's sprite
|
||||
var random = Random.create();
|
||||
random.setSeed(42L);
|
||||
var layer = net.minecraft.client.render.RenderLayers.getBlockLayer(storedState);
|
||||
var consumer = vertexConsumers.getBuffer(layer);
|
||||
|
||||
var bufferSource = vertexConsumers;
|
||||
var layer = net.minecraft.client.render.RenderLayers.getBlockLayer(blueprintState);
|
||||
var consumer = bufferSource.getBuffer(layer);
|
||||
matrices.push();
|
||||
|
||||
for (var direction : new net.minecraft.util.math.Direction[]{
|
||||
null,
|
||||
net.minecraft.util.math.Direction.UP,
|
||||
net.minecraft.util.math.Direction.DOWN,
|
||||
net.minecraft.util.math.Direction.NORTH,
|
||||
net.minecraft.util.math.Direction.SOUTH,
|
||||
net.minecraft.util.math.Direction.EAST,
|
||||
net.minecraft.util.math.Direction.WEST
|
||||
}) {
|
||||
random.setSeed(42L);
|
||||
var quads = blueprintModel.getQuads(blueprintState, direction, random);
|
||||
for (var quad : quads) {
|
||||
// Emit the quad but with the stored block's sprite UV remapped
|
||||
emitQuadWithSprite(consumer, matrices, quad, sprites, light, overlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
renderer.getModelRenderer().render(
|
||||
entity.getWorld(),
|
||||
wrappedModel,
|
||||
storedState,
|
||||
entity.getPos(),
|
||||
matrices,
|
||||
consumer,
|
||||
false,
|
||||
net.minecraft.util.math.random.Random.create(),
|
||||
42L,
|
||||
overlay
|
||||
);
|
||||
|
||||
private void emitQuadWithSprite(net.minecraft.client.render.VertexConsumer consumer,
|
||||
MatrixStack matrices,
|
||||
net.minecraft.client.render.model.BakedQuad quad,
|
||||
net.minecraft.client.texture.Sprite sprite,
|
||||
int light, int overlay) {
|
||||
// Re-emit the quad geometry but remap UVs to the new sprite
|
||||
consumer.quad(matrices.peek(), quad, 1f, 1f, 1f, light, overlay);
|
||||
// Note: this uses the quad's original UVs which point to the blueprint texture.
|
||||
// For full texture remapping you'd need to manually rewrite vertex data.
|
||||
// This gives correct shape with blueprint texture as fallback —
|
||||
// see note below for full UV remapping.
|
||||
matrices.pop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package dev.tggamesyt.szar.client;
|
||||
|
||||
import dev.tggamesyt.szar.BlueprintBlockEntity;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.json.ModelOverrideList;
|
||||
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BlueprintWrappedModel implements BakedModel {
|
||||
|
||||
private final BakedModel blueprint;
|
||||
private final BakedModel stored;
|
||||
private final BlockState blueprintState;
|
||||
private final BlockState storedState;
|
||||
private final BlueprintBlockEntity entity;
|
||||
|
||||
public BlueprintWrappedModel(BakedModel blueprint, BakedModel stored,
|
||||
BlockState blueprintState, BlockState storedState, BlueprintBlockEntity entity) {
|
||||
this.blueprint = blueprint;
|
||||
this.stored = stored;
|
||||
this.blueprintState = blueprintState;
|
||||
this.storedState = storedState;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(BlockState state, Direction face, Random random) {
|
||||
List<BakedQuad> original = blueprint.getQuads(blueprintState, face, random);
|
||||
List<BakedQuad> result = new ArrayList<>(original.size());
|
||||
|
||||
for (BakedQuad quad : original) {
|
||||
int[] data = quad.getVertexData().clone();
|
||||
|
||||
Direction quadFace = quad.getFace();
|
||||
Sprite target = getSpriteForFace(stored, storedState, quadFace);
|
||||
|
||||
remapUVs(data, quad.getSprite(), target);
|
||||
|
||||
BlockPos pos = entity.getPos();
|
||||
Camera camera = MinecraftClient.getInstance().gameRenderer.getCamera();
|
||||
Vec3d camPos = camera.getPos();
|
||||
double dx = pos.getX() + 0.5 - camPos.x;
|
||||
double dy = pos.getY() + 0.5 - camPos.y;
|
||||
double dz = pos.getZ() + 0.5 - camPos.z;
|
||||
double distance = Math.sqrt(dx*dx + dy*dy + dz*dz);
|
||||
float offsetAmount = 0.0001f + (float)distance * 1e-5f;
|
||||
offsetAmount = Math.min(offsetAmount, 0.001f); // clamp max
|
||||
offsetVertsAlongNormal(data, quad.getFace(), offsetAmount);
|
||||
|
||||
result.add(new BakedQuad(
|
||||
data,
|
||||
quad.getColorIndex(),
|
||||
quadFace,
|
||||
target,
|
||||
quad.hasShade()
|
||||
));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- IMPORTANT: delegate everything else properly ---
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return stored.useAmbientOcclusion(); // important for lighting
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return stored.hasDepth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return stored.isSideLit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getParticleSprite() {
|
||||
return stored.getParticleSprite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTransformation getTransformation() {
|
||||
return stored.getTransformation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return stored.getOverrides();
|
||||
}
|
||||
|
||||
// --- helpers ---
|
||||
|
||||
private Sprite getSpriteForFace(BakedModel model, BlockState state, Direction face) {
|
||||
Random rand = Random.create(42L);
|
||||
|
||||
List<BakedQuad> quads = model.getQuads(state, face, rand);
|
||||
if (!quads.isEmpty()) return quads.get(0).getSprite();
|
||||
|
||||
quads = model.getQuads(state, null, rand);
|
||||
for (BakedQuad q : quads) {
|
||||
if (q.getFace() == face) return q.getSprite();
|
||||
}
|
||||
|
||||
return model.getParticleSprite();
|
||||
}
|
||||
|
||||
private void remapUVs(int[] vertexData, Sprite from, Sprite to) {
|
||||
int stride = 8;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int uvIndex = i * stride + 4;
|
||||
|
||||
float u = Float.intBitsToFloat(vertexData[uvIndex]);
|
||||
float v = Float.intBitsToFloat(vertexData[uvIndex + 1]);
|
||||
|
||||
float nu = (u - from.getMinU()) / (from.getMaxU() - from.getMinU());
|
||||
float nv = (v - from.getMinV()) / (from.getMaxV() - from.getMinV());
|
||||
|
||||
float newU = to.getMinU() + nu * (to.getMaxU() - to.getMinU());
|
||||
float newV = to.getMinV() + nv * (to.getMaxV() - to.getMinV());
|
||||
|
||||
vertexData[uvIndex] = Float.floatToRawIntBits(newU);
|
||||
vertexData[uvIndex + 1] = Float.floatToRawIntBits(newV);
|
||||
}
|
||||
}
|
||||
|
||||
private void offsetVertsAlongNormal(int[] vertexData, Direction face, float amount) {
|
||||
if (face == null) return; // skip general quads
|
||||
|
||||
float dx = face.getOffsetX() * amount;
|
||||
float dy = face.getOffsetY() * amount;
|
||||
float dz = face.getOffsetZ() * amount;
|
||||
|
||||
int vertexSize = 8; // X,Y,Z,COLOR,U,V,UV2,NORMAL
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int base = i * vertexSize;
|
||||
float x = Float.intBitsToFloat(vertexData[base]);
|
||||
float y = Float.intBitsToFloat(vertexData[base + 1]);
|
||||
float z = Float.intBitsToFloat(vertexData[base + 2]);
|
||||
|
||||
vertexData[base] = Float.floatToRawIntBits(x + dx);
|
||||
vertexData[base + 1] = Float.floatToRawIntBits(y + dy);
|
||||
vertexData[base + 2] = Float.floatToRawIntBits(z + dz);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,31 +38,35 @@ public class PlaneEntityRenderer extends EntityRenderer<PlaneEntity> {
|
||||
) {
|
||||
matrices.push();
|
||||
|
||||
// Smooth interpolation of rotation
|
||||
float interpolatedYaw = entity.prevYaw + (entity.getYaw() - entity.prevYaw) * tickDelta;
|
||||
float interpolatedYaw = entity.prevYaw + (entity.getYaw() - entity.prevYaw) * tickDelta;
|
||||
float interpolatedPitch = entity.prevPitch + (entity.getPitch() - entity.prevPitch) * tickDelta;
|
||||
|
||||
// Scale
|
||||
matrices.scale(4.0F, 4.0F, 4.0F);
|
||||
float pitchRad = (float) Math.toRadians(interpolatedPitch);
|
||||
float yawRad = (float) Math.toRadians(interpolatedYaw);
|
||||
|
||||
// Move model to correct pivot point
|
||||
final float PIVOT_OFFSET = 4F;
|
||||
final float ARC_RADIUS = 8F;
|
||||
|
||||
float dy = PIVOT_OFFSET * (1.0F - (float) Math.cos(pitchRad))
|
||||
- (ARC_RADIUS * (1.0F - (float) Math.cos(pitchRad)) - ARC_RADIUS * (1.0F - (float) Math.cos(pitchRad)));
|
||||
float dz = ARC_RADIUS * (float) Math.sin(pitchRad);
|
||||
|
||||
float worldX = -dz * (float) Math.sin(yawRad);
|
||||
float worldZ = dz * (float) Math.cos(yawRad);
|
||||
float worldY = PIVOT_OFFSET * (1.0F - (float) Math.cos(pitchRad));
|
||||
|
||||
matrices.translate(worldX, worldY, worldZ);
|
||||
|
||||
matrices.scale(4.0F, 4.0F, 4.0F);
|
||||
matrices.translate(0.0, 1.5, 0.0);
|
||||
|
||||
// Rotate to match hitbox exactly
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-interpolatedYaw));
|
||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(interpolatedPitch));
|
||||
|
||||
// Rotate 180° to fix backwards-facing
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180.0F));
|
||||
|
||||
// Flip model upright (Minecraft model fix)
|
||||
matrices.scale(-1.0F, -1.0F, 1.0F);
|
||||
|
||||
// Set model angles
|
||||
model.setAngles(
|
||||
entity,
|
||||
0,
|
||||
0,
|
||||
entity, 0, 0,
|
||||
entity.age + tickDelta,
|
||||
interpolatedYaw,
|
||||
interpolatedPitch
|
||||
@@ -72,10 +76,8 @@ public class PlaneEntityRenderer extends EntityRenderer<PlaneEntity> {
|
||||
vertices.getBuffer(RenderLayer.getEntityCutout(getTexture(entity)));
|
||||
|
||||
model.render(
|
||||
matrices,
|
||||
consumer,
|
||||
light,
|
||||
OverlayTexture.DEFAULT_UV,
|
||||
matrices, consumer,
|
||||
light, OverlayTexture.DEFAULT_UV,
|
||||
1.0F, 1.0F, 1.0F, 1.0F
|
||||
);
|
||||
|
||||
|
||||
@@ -565,6 +565,18 @@ public class SzarClient implements ClientModInitializer {
|
||||
Szar.CANNABIS_BLOCK,
|
||||
RenderLayer.getCutout()
|
||||
);
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(
|
||||
CONNECT_FOUR_BLOCK,
|
||||
RenderLayer.getCutout()
|
||||
);
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(
|
||||
SMALL_CHORUS,
|
||||
RenderLayer.getCutout()
|
||||
);
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(
|
||||
SMALL_CHORUS_FLOWER,
|
||||
RenderLayer.getCutout()
|
||||
);
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(
|
||||
ROULETTE_BLOCK,
|
||||
RenderLayer.getCutout()
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package dev.tggamesyt.szar.client.mixin;
|
||||
|
||||
import dev.tggamesyt.szar.*;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.particle.BlockDustParticle;
|
||||
import net.minecraft.client.particle.ParticleManager;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.World;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ParticleManager.class)
|
||||
public class ParticleManagerMixin {
|
||||
|
||||
@Shadow
|
||||
public ClientWorld world;
|
||||
|
||||
@Inject(method = "addBlockBreakParticles", at = @At("HEAD"), cancellable = true)
|
||||
private void redirectBreakParticles(BlockPos pos, BlockState state, CallbackInfo ci) {
|
||||
if (world == null) return;
|
||||
|
||||
if (!(state.getBlock() instanceof BlueprintStairsBlock ||
|
||||
state.getBlock() instanceof BlueprintSlabBlock ||
|
||||
state.getBlock() instanceof BlueprintDoorBlock ||
|
||||
state.getBlock() instanceof BlueprintTrapDoorBlock ||
|
||||
state.getBlock() instanceof BlueprintWallBlock ||
|
||||
state.getBlock() instanceof BlueprintFenceBlock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var be = world.getBlockEntity(pos);
|
||||
if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) return;
|
||||
|
||||
BlockState storedState = Registries.BLOCK
|
||||
.get(new Identifier(blueprint.getStoredBlockId()))
|
||||
.getDefaultState();
|
||||
|
||||
ci.cancel();
|
||||
|
||||
// ✅ USE BLUEPRINT SHAPE, NOT STORED
|
||||
var shape = state.getOutlineShape(world, pos);
|
||||
|
||||
shape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> {
|
||||
double dx = Math.min(1.0, maxX - minX);
|
||||
double dy = Math.min(1.0, maxY - minY);
|
||||
double dz = Math.min(1.0, maxZ - minZ);
|
||||
|
||||
int ix = Math.max(2, net.minecraft.util.math.MathHelper.ceil(dx / 0.25));
|
||||
int iy = Math.max(2, net.minecraft.util.math.MathHelper.ceil(dy / 0.25));
|
||||
int iz = Math.max(2, net.minecraft.util.math.MathHelper.ceil(dz / 0.25));
|
||||
|
||||
for (int x = 0; x < ix; x++) {
|
||||
for (int y = 0; y < iy; y++) {
|
||||
for (int z = 0; z < iz; z++) {
|
||||
|
||||
double fx = (x + 0.5) / ix;
|
||||
double fy = (y + 0.5) / iy;
|
||||
double fz = (z + 0.5) / iz;
|
||||
|
||||
double px = fx * dx + minX;
|
||||
double py = fy * dy + minY;
|
||||
double pz = fz * dz + minZ;
|
||||
|
||||
((ParticleManager)(Object)this).addParticle(
|
||||
new BlockDustParticle(
|
||||
world,
|
||||
pos.getX() + px,
|
||||
pos.getY() + py,
|
||||
pos.getZ() + pz,
|
||||
fx - 0.5,
|
||||
fy - 0.5,
|
||||
fz - 0.5,
|
||||
storedState, // ✅ texture comes from stored
|
||||
pos
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "addBlockBreakingParticles", at = @At("HEAD"), cancellable = true)
|
||||
private void redirectBreakingParticles(BlockPos pos, Direction direction, CallbackInfo ci) {
|
||||
if (world == null) return;
|
||||
|
||||
BlockState state = world.getBlockState(pos);
|
||||
if (!(state.getBlock() instanceof BlueprintStairsBlock ||
|
||||
state.getBlock() instanceof BlueprintSlabBlock ||
|
||||
state.getBlock() instanceof BlueprintDoorBlock ||
|
||||
state.getBlock() instanceof BlueprintTrapDoorBlock ||
|
||||
state.getBlock() instanceof BlueprintWallBlock ||
|
||||
state.getBlock() instanceof BlueprintFenceBlock)) {return;}
|
||||
|
||||
var be = world.getBlockEntity(pos);
|
||||
if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) return;
|
||||
|
||||
BlockState storedState = Registries.BLOCK
|
||||
.get(new Identifier(blueprint.getStoredBlockId()))
|
||||
.getDefaultState();
|
||||
ci.cancel();
|
||||
|
||||
Box box = storedState.getOutlineShape(world, pos).getBoundingBox();
|
||||
int i = pos.getX(), j = pos.getY(), k = pos.getZ();
|
||||
Random random = Random.create();
|
||||
double d = i + random.nextDouble() * (box.maxX - box.minX - 0.2) + 0.1 + box.minX;
|
||||
double e = j + random.nextDouble() * (box.maxY - box.minY - 0.2) + 0.1 + box.minY;
|
||||
double g = k + random.nextDouble() * (box.maxZ - box.minZ - 0.2) + 0.1 + box.minZ;
|
||||
if (direction == Direction.DOWN) e = j + box.minY - 0.1;
|
||||
if (direction == Direction.UP) e = j + box.maxY + 0.1;
|
||||
if (direction == Direction.NORTH) g = k + box.minZ - 0.1;
|
||||
if (direction == Direction.SOUTH) g = k + box.maxZ + 0.1;
|
||||
if (direction == Direction.WEST) d = i + box.minX - 0.1;
|
||||
if (direction == Direction.EAST) d = i + box.maxX + 0.1;
|
||||
|
||||
((ParticleManager)(Object)this).addParticle(
|
||||
new BlockDustParticle(world, d, e, g, 0, 0, 0, storedState, pos).move(0.2f).scale(0.6f)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
"MouseMixin",
|
||||
"PackMixin",
|
||||
"PackScreenCloseMixin",
|
||||
"ParticleManagerMixin",
|
||||
"PlayerEntityRendererMixin",
|
||||
"PlayerHeldItemFeatureRendererMixin",
|
||||
"PlayerModelMixin",
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.DoorBlock;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.enums.DoubleBlockHalf;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockView;
|
||||
@@ -29,13 +33,20 @@ public class BlueprintBehavior {
|
||||
|
||||
ItemStack held = player.getStackInHand(hand);
|
||||
|
||||
if (held.isEmpty()) {
|
||||
// Clear stored block
|
||||
if (held.isEmpty() && player.isSneaking()) {
|
||||
blueprint.clearStoredBlock();
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if (held.getItem() instanceof BlockItem blockItem) {
|
||||
if (!held.isEmpty() && held.getItem() instanceof BlockItem blockItem && !blueprint.hasStoredBlock()) {
|
||||
if (blockItem.getBlock() instanceof BlueprintStairsBlock ||
|
||||
blockItem.getBlock() instanceof BlueprintSlabBlock ||
|
||||
blockItem.getBlock() instanceof BlueprintDoorBlock ||
|
||||
blockItem.getBlock() instanceof BlueprintTrapDoorBlock ||
|
||||
blockItem.getBlock() instanceof BlueprintWallBlock ||
|
||||
blockItem.getBlock() instanceof BlueprintFenceBlock) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
String id = Registries.BLOCK.getId(blockItem.getBlock()).toString();
|
||||
blueprint.setStoredBlock(id);
|
||||
if (!player.isCreative()) held.decrement(1);
|
||||
@@ -51,12 +62,17 @@ public class BlueprintBehavior {
|
||||
public static float calcBreakingDelta(BlockState state, PlayerEntity player,
|
||||
BlockView world, BlockPos pos, float baseHardness) {
|
||||
BlockEntity be = world.getBlockEntity(pos);
|
||||
|
||||
if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) {
|
||||
return baseHardness;
|
||||
}
|
||||
float hardness = blueprint.getStoredHardness();
|
||||
if (hardness < 0) return 0f; // unbreakable
|
||||
return player.getBlockBreakingSpeed(state) / hardness / 30f;
|
||||
|
||||
BlockState storedState = Registries.BLOCK
|
||||
.get(new Identifier(blueprint.getStoredBlockId()))
|
||||
.getDefaultState();
|
||||
|
||||
// Fully delegate to vanilla logic
|
||||
return storedState.calcBlockBreakingDelta(player, world, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,11 +80,28 @@ public class BlueprintBehavior {
|
||||
*/
|
||||
public static void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
|
||||
BlockEntity be = world.getBlockEntity(pos);
|
||||
if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) return;
|
||||
if (!player.isCreative()) {
|
||||
ItemStack drop = blueprint.getStoredDrop();
|
||||
if (!drop.isEmpty()) {
|
||||
dropStack(world, pos, drop);
|
||||
|
||||
if (!(be instanceof BlueprintBlockEntity blueprint) || !blueprint.hasStoredBlock()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop stored block
|
||||
if (!world.isClient) {
|
||||
Block.dropStack(world, pos, blueprint.getStoredDrop());
|
||||
}
|
||||
|
||||
// Handle doors (break other half properly)
|
||||
if (state.getBlock() instanceof DoorBlock) {
|
||||
DoubleBlockHalf half = state.get(DoorBlock.HALF);
|
||||
BlockPos otherPos = (half == DoubleBlockHalf.LOWER) ? pos.up() : pos.down();
|
||||
|
||||
BlockState otherState = world.getBlockState(otherPos);
|
||||
BlockEntity otherBe = world.getBlockEntity(otherPos);
|
||||
|
||||
if (otherBe instanceof BlueprintBlockEntity otherBlueprint && otherBlueprint.hasStoredBlock()) {
|
||||
if (!world.isClient) {
|
||||
Block.dropStack(world, otherPos, otherBlueprint.getStoredDrop());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
@@ -16,8 +17,19 @@ public class BlueprintBlockEntity extends BlockEntity {
|
||||
@Nullable
|
||||
private String storedBlockId = null;
|
||||
|
||||
public BlueprintBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
public BlueprintBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(getBEType(state), pos, state);
|
||||
}
|
||||
|
||||
private static BlockEntityType<BlueprintBlockEntity> getBEType(BlockState state) {
|
||||
Block block = state.getBlock();
|
||||
if (block instanceof BlueprintStairsBlock) return BlueprintBlocks.BLUEPRINT_STAIRS_BE_TYPE;
|
||||
if (block instanceof BlueprintSlabBlock) return BlueprintBlocks.BLUEPRINT_SLAB_BE_TYPE;
|
||||
if (block instanceof BlueprintDoorBlock) return BlueprintBlocks.BLUEPRINT_DOOR_BE_TYPE;
|
||||
if (block instanceof BlueprintTrapDoorBlock) return BlueprintBlocks.BLUEPRINT_TRAPDOOR_BE_TYPE;
|
||||
if (block instanceof BlueprintWallBlock) return BlueprintBlocks.BLUEPRINT_WALL_BE_TYPE;
|
||||
if (block instanceof BlueprintFenceBlock) return BlueprintBlocks.BLUEPRINT_FENCE_BE_TYPE;
|
||||
throw new IllegalStateException("Unknown blueprint block: " + block);
|
||||
}
|
||||
|
||||
public boolean hasStoredBlock() {
|
||||
@@ -40,6 +52,9 @@ public class BlueprintBlockEntity extends BlockEntity {
|
||||
public void clearStoredBlock() {
|
||||
this.storedBlockId = null;
|
||||
markDirty();
|
||||
if (world != null && !world.isClient) {
|
||||
world.updateListeners(pos, getCachedState(), getCachedState(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the hardness of the stored block, or default if none. */
|
||||
|
||||
@@ -4,6 +4,7 @@ import dev.tggamesyt.szar.Szar;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.MapColor;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.item.BlockItem;
|
||||
@@ -12,6 +13,8 @@ import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import static dev.tggamesyt.szar.Szar.MOD_ID;
|
||||
|
||||
public class BlueprintBlocks {
|
||||
|
||||
private static AbstractBlock.Settings settings() {
|
||||
@@ -19,88 +22,89 @@ public class BlueprintBlocks {
|
||||
.mapColor(MapColor.TERRACOTTA_LIGHT_BLUE)
|
||||
.strength(1.0f);
|
||||
}
|
||||
|
||||
public static final Item BLUEPRINT = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(MOD_ID, "blueprint"),
|
||||
new Item(new Item.Settings())
|
||||
);
|
||||
public static final BlueprintStairsBlock BLUEPRINT_STAIRS =
|
||||
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_stairs"),
|
||||
Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_stairs"),
|
||||
new BlueprintStairsBlock(settings()));
|
||||
|
||||
public static final BlueprintSlabBlock BLUEPRINT_SLAB =
|
||||
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_slab"),
|
||||
Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_slab"),
|
||||
new BlueprintSlabBlock(settings()));
|
||||
|
||||
public static final BlueprintDoorBlock BLUEPRINT_DOOR =
|
||||
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_door"),
|
||||
Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_door"),
|
||||
new BlueprintDoorBlock(settings()));
|
||||
|
||||
public static final BlueprintTrapDoorBlock BLUEPRINT_TRAPDOOR =
|
||||
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_trapdoor"),
|
||||
Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_trapdoor"),
|
||||
new BlueprintTrapDoorBlock(settings()));
|
||||
|
||||
public static final BlueprintWallBlock BLUEPRINT_WALL =
|
||||
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_wall"),
|
||||
new BlueprintWallBlock(settings()));
|
||||
Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_wall"),
|
||||
new BlueprintWallBlock(AbstractBlock.Settings.copy(Blocks.STONE_BRICK_WALL)));
|
||||
|
||||
public static final BlueprintFenceBlock BLUEPRINT_FENCE =
|
||||
Registry.register(Registries.BLOCK, new Identifier(Szar.MOD_ID, "blueprint_fence"),
|
||||
new BlueprintFenceBlock(settings()));
|
||||
Registry.register(Registries.BLOCK, new Identifier(MOD_ID, "blueprint_fence"),
|
||||
new BlueprintFenceBlock(AbstractBlock.Settings.copy(Blocks.OAK_FENCE)));
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_STAIRS_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_stairs_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_STAIRS).build());
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_STAIRS_BE_TYPE;
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_SLAB_BE_TYPE;
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_DOOR_BE_TYPE;
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_TRAPDOOR_BE_TYPE;
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_WALL_BE_TYPE;
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_FENCE_BE_TYPE;
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_SLAB_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_slab_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_SLAB).build());
|
||||
static {
|
||||
BLUEPRINT_STAIRS_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(MOD_ID, "blueprint_stairs_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_STAIRS).build());
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_DOOR_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_door_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_DOOR).build());
|
||||
BLUEPRINT_SLAB_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(MOD_ID, "blueprint_slab_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_SLAB).build());
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_TRAPDOOR_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_trapdoor_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_TRAPDOOR).build());
|
||||
BLUEPRINT_DOOR_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(MOD_ID, "blueprint_door_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_DOOR).build());
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_WALL_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_wall_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_WALL).build());
|
||||
BLUEPRINT_TRAPDOOR_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(MOD_ID, "blueprint_trapdoor_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_TRAPDOOR).build());
|
||||
|
||||
public static final BlockEntityType<BlueprintBlockEntity> BLUEPRINT_FENCE_BE_TYPE =
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Szar.MOD_ID, "blueprint_fence_be"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
(pos, state) -> new BlueprintBlockEntity(null, pos, state),
|
||||
BLUEPRINT_FENCE).build());
|
||||
BLUEPRINT_WALL_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(MOD_ID, "blueprint_wall_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_WALL).build());
|
||||
|
||||
BLUEPRINT_FENCE_BE_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(MOD_ID, "blueprint_fence_be"),
|
||||
FabricBlockEntityTypeBuilder.create(BlueprintBlockEntity::new, BLUEPRINT_FENCE).build());
|
||||
}
|
||||
public static final BlockItem BLUEPRINT_STAIRS_ITEM = Registry.register(Registries.ITEM,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_stairs"),
|
||||
new Identifier(MOD_ID, "blueprint_stairs"),
|
||||
new BlockItem(BLUEPRINT_STAIRS, new Item.Settings()));
|
||||
|
||||
public static final BlockItem BLUEPRINT_SLAB_ITEM = Registry.register(Registries.ITEM,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_slab"),
|
||||
new Identifier(MOD_ID, "blueprint_slab"),
|
||||
new BlockItem(BLUEPRINT_SLAB, new Item.Settings()));
|
||||
|
||||
public static final BlockItem BLUEPRINT_DOOR_ITEM = Registry.register(Registries.ITEM,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_door"),
|
||||
new Identifier(MOD_ID, "blueprint_door"),
|
||||
new BlockItem(BLUEPRINT_DOOR, new Item.Settings()));
|
||||
|
||||
public static final BlockItem BLUEPRINT_TRAPDOOR_ITEM = Registry.register(Registries.ITEM,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_trapdoor"),
|
||||
new Identifier(MOD_ID, "blueprint_trapdoor"),
|
||||
new BlockItem(BLUEPRINT_TRAPDOOR, new Item.Settings()));
|
||||
|
||||
public static final BlockItem BLUEPRINT_WALL_ITEM = Registry.register(Registries.ITEM,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_wall"),
|
||||
new Identifier(MOD_ID, "blueprint_wall"),
|
||||
new BlockItem(BLUEPRINT_WALL, new Item.Settings()));
|
||||
|
||||
public static final BlockItem BLUEPRINT_FENCE_ITEM = Registry.register(Registries.ITEM,
|
||||
new Identifier(Szar.MOD_ID, "blueprint_fence"),
|
||||
new Identifier(MOD_ID, "blueprint_fence"),
|
||||
new BlockItem(BLUEPRINT_FENCE, new Item.Settings()));
|
||||
public static void init() {} // just call this to trigger class loading
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public class BlueprintDoorBlock extends DoorBlock implements BlockEntityProvider
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_DOOR_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class BlueprintFenceBlock extends FenceBlock implements BlockEntityProvid
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_FENCE_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class BlueprintSlabBlock extends SlabBlock implements BlockEntityProvider
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_SLAB_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class BlueprintStairsBlock extends StairsBlock implements BlockEntityProv
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_STAIRS_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class BlueprintTrapDoorBlock extends TrapdoorBlock implements BlockEntity
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_TRAPDOOR_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,6 +9,7 @@ import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.block.WallBlock;
|
||||
|
||||
public class BlueprintWallBlock extends WallBlock implements BlockEntityProvider {
|
||||
|
||||
@@ -18,7 +19,7 @@ public class BlueprintWallBlock extends WallBlock implements BlockEntityProvider
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BlueprintBlockEntity(BlueprintBlocks.BLUEPRINT_WALL_BE_TYPE, pos, state);
|
||||
return new BlueprintBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
62
src/main/java/dev/tggamesyt/szar/ChorusEndStone.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.Fertilizable;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldView;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.gen.feature.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ChorusEndStone extends EndSpreadableBlock implements Fertilizable {
|
||||
|
||||
public ChorusEndStone(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFertilizable(WorldView world, BlockPos pos, BlockState state, boolean isClient) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canGrow(World world, Random random, BlockPos pos, BlockState state) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grow(ServerWorld world, Random random, BlockPos pos, BlockState state) {
|
||||
BlockPos target = pos.up();
|
||||
|
||||
var registry = world.getRegistryManager().get(RegistryKeys.PLACED_FEATURE);
|
||||
var featureEntry = registry.getEntry(Szar.SMALL_CHORUS_PLACED);
|
||||
|
||||
// ❌ if blocked, do nothing
|
||||
if (!world.getBlockState(target).isAir()) return;
|
||||
|
||||
// 🌸 VERY RARE chorus flower (~5%)
|
||||
if (random.nextInt(20) == 0) {
|
||||
world.setBlockState(target, Blocks.CHORUS_FLOWER.getDefaultState());
|
||||
return;
|
||||
}
|
||||
|
||||
// 🌿 otherwise place ONE patch
|
||||
if (featureEntry.isPresent()) {
|
||||
featureEntry.get().value().generateUnregistered(
|
||||
world,
|
||||
world.getChunkManager().getChunkGenerator(),
|
||||
random,
|
||||
target
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
77
src/main/java/dev/tggamesyt/szar/EndSpreadableBlock.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.registry.tag.FluidTags;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.WorldView;
|
||||
import net.minecraft.world.chunk.light.ChunkLightProvider;
|
||||
|
||||
public abstract class EndSpreadableBlock extends SnowyBlock {
|
||||
|
||||
protected EndSpreadableBlock(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
private static boolean canSurvive(BlockState state, WorldView world, BlockPos pos) {
|
||||
BlockPos up = pos.up();
|
||||
BlockState upState = world.getBlockState(up);
|
||||
|
||||
if (upState.isOf(Blocks.SNOW) && upState.get(SnowBlock.LAYERS) == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (upState.getFluidState().getLevel() == 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int opacity = ChunkLightProvider.getRealisticOpacity(
|
||||
world, state, pos, upState, up, Direction.UP,
|
||||
upState.getOpacity(world, up)
|
||||
);
|
||||
|
||||
return opacity < world.getMaxLightLevel();
|
||||
}
|
||||
|
||||
private static boolean canSpread(BlockState state, WorldView world, BlockPos pos) {
|
||||
BlockPos up = pos.up();
|
||||
return canSurvive(state, world, pos)
|
||||
&& !world.getFluidState(up).isIn(FluidTags.WATER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
|
||||
|
||||
// ❌ Decay (like grass → dirt)
|
||||
if (!canSurvive(state, world, pos)) {
|
||||
world.setBlockState(pos, Blocks.END_STONE.getDefaultState());
|
||||
return;
|
||||
}
|
||||
|
||||
// 🌱 Spread
|
||||
if (world.getLightLevel(pos.up()) >= 9) {
|
||||
BlockState spreadState = this.getDefaultState();
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BlockPos target = pos.add(
|
||||
random.nextInt(3) - 1,
|
||||
random.nextInt(5) - 3,
|
||||
random.nextInt(3) - 1
|
||||
);
|
||||
|
||||
if (world.getBlockState(target).isOf(Blocks.END_STONE)
|
||||
&& canSpread(spreadState, world, target)) {
|
||||
|
||||
world.setBlockState(
|
||||
target,
|
||||
spreadState.with(SNOWY,
|
||||
world.getBlockState(target.up()).isOf(Blocks.SNOW)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/main/java/dev/tggamesyt/szar/EnderObsidian.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class EnderObsidian extends Block {
|
||||
|
||||
public EnderObsidian(AbstractBlock.Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, net.minecraft.block.entity.BlockEntity blockEntity, net.minecraft.item.ItemStack stack) {
|
||||
super.afterBreak(world, player, pos, state, blockEntity, stack);
|
||||
|
||||
if (!world.isClient) {
|
||||
world.setBlockState(pos, Szar.ENDER_ORE.getDefaultState());
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/main/java/dev/tggamesyt/szar/SmallChorusBlock.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.PlantBlock;
|
||||
import net.minecraft.block.ShapeContext;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
import net.minecraft.world.BlockView;
|
||||
|
||||
public class SmallChorusBlock extends PlantBlock {
|
||||
protected static final VoxelShape SHAPE = Block.createCuboidShape((double)2.0F, (double)0.0F, (double)2.0F, (double)14.0F, (double)13.0F, (double)14.0F);
|
||||
public SmallChorusBlock(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||
return SHAPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) {
|
||||
return floor.isOf(Szar.CHORUS_ENDSTONE);
|
||||
}
|
||||
}
|
||||
52
src/main/java/dev/tggamesyt/szar/SmallChorusFlowerBlock.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.PlantBlock;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class SmallChorusFlowerBlock extends PlantBlock {
|
||||
|
||||
protected static final VoxelShape SHAPE = Block.createCuboidShape(
|
||||
2.0, 0.0, 2.0,
|
||||
14.0, 13.0, 14.0
|
||||
);
|
||||
|
||||
public SmallChorusFlowerBlock(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, net.minecraft.block.ShapeContext context) {
|
||||
return SHAPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) {
|
||||
return floor.isOf(Szar.CHORUS_ENDSTONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
|
||||
|
||||
// small chance per random tick → averages ~5–10 minutes
|
||||
if (random.nextInt(6) == 0) { // tweak this number
|
||||
|
||||
// only grow if space above
|
||||
if (world.getBlockState(pos.up()).isAir()) {
|
||||
world.setBlockState(pos, Blocks.CHORUS_FLOWER.getDefaultState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRandomTicks(BlockState state) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
48
src/main/java/dev/tggamesyt/szar/SurfaceReplaceFeature.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.StructureWorldAccess;
|
||||
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
|
||||
import net.minecraft.world.gen.feature.Feature;
|
||||
import net.minecraft.world.gen.feature.util.FeatureContext;
|
||||
|
||||
public class SurfaceReplaceFeature extends Feature<DefaultFeatureConfig> {
|
||||
|
||||
public SurfaceReplaceFeature(Codec<DefaultFeatureConfig> codec) {
|
||||
super(codec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generate(FeatureContext<DefaultFeatureConfig> context) {
|
||||
StructureWorldAccess world = context.getWorld();
|
||||
BlockPos origin = context.getOrigin();
|
||||
|
||||
// snap to chunk corner
|
||||
int startX = (origin.getX() >> 4) << 4;
|
||||
int startZ = (origin.getZ() >> 4) << 4;
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
BlockPos column = new BlockPos(startX + x, origin.getY(), startZ + z);
|
||||
|
||||
for (int i = 10; i > -10; i--) {
|
||||
BlockPos pos = column.up(i);
|
||||
BlockState state = world.getBlockState(pos);
|
||||
|
||||
if (state.isOf(Blocks.END_STONE)) {
|
||||
world.setBlockState(pos, Szar.CHORUS_ENDSTONE.getDefaultState(), Block.NOTIFY_LISTENERS);
|
||||
break;
|
||||
} else if (!state.isAir()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.mojang.authlib.minecraft.client.MinecraftClient;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
|
||||
@@ -28,6 +27,7 @@ import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.trade.TradeOfferHelper;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.world.poi.PointOfInterestHelper;
|
||||
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry;
|
||||
import net.fabricmc.fabric.impl.biome.TheEndBiomeData;
|
||||
import net.minecraft.advancement.Advancement;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.dispenser.FallibleItemDispenserBehavior;
|
||||
@@ -75,6 +75,7 @@ import net.minecraft.village.TradeOffer;
|
||||
import net.minecraft.village.VillagerProfession;
|
||||
import net.minecraft.world.Heightmap;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeKeys;
|
||||
import net.minecraft.world.dimension.DimensionOptions;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
@@ -90,14 +91,12 @@ import net.minecraft.world.poi.PointOfInterestType;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static dev.tggamesyt.szar.ServerCosmetics.USERS;
|
||||
import static dev.tggamesyt.szar.ServerCosmetics.sync;
|
||||
|
||||
public class Szar implements ModInitializer {
|
||||
public static final String MOD_ID = "szar";
|
||||
@@ -164,6 +163,7 @@ public class Szar implements ModInitializer {
|
||||
new Identifier(Szar.MOD_ID, "won"),
|
||||
SoundEvent.of(new Identifier(Szar.MOD_ID, "won"))
|
||||
);
|
||||
private static final Set<Integer> chorusRolledEntities = new HashSet<>();
|
||||
public static final SoundEvent MERL_SOUND =
|
||||
SoundEvent.of(new Identifier(MOD_ID, "merl"));
|
||||
public static final Map<UUID, Long> recentPlaneCrashDeaths = new java.util.HashMap<>();
|
||||
@@ -366,7 +366,7 @@ public class Szar implements ModInitializer {
|
||||
boolean showRacist = !ServerConfig.get("racist");
|
||||
boolean showGambling = !ServerConfig.get("gambling");
|
||||
boolean showNsfw = !ServerConfig.get("nsfw");
|
||||
// random ahh silly stuff
|
||||
// memes
|
||||
entries.add(Szar.POPTART);
|
||||
entries.add(Szar.NYAN_SPAWNEGG);
|
||||
entries.add(Szar.BAITER_DISC);
|
||||
@@ -374,6 +374,8 @@ public class Szar implements ModInitializer {
|
||||
entries.add(Szar.EFN_DISK);
|
||||
entries.add(Szar.FIRTANA);
|
||||
entries.add(Szar.HELLO_DISC);
|
||||
entries.add(Szar.KEBAB);
|
||||
// backrooms
|
||||
entries.add(Szar.TRACKER_BLOCK_ITEM);
|
||||
entries.add(Szar.PORTAL_BLOCK_ITEM);
|
||||
entries.add(Szar.WALL_ITEM);
|
||||
@@ -384,15 +386,23 @@ public class Szar implements ModInitializer {
|
||||
entries.add(Szar.BEAN);
|
||||
entries.add(Szar.CAN_OF_BEANS);
|
||||
entries.add(Szar.ALMOND_WATER);
|
||||
entries.add(Szar.KEBAB);
|
||||
|
||||
// end update
|
||||
entries.add(Szar.CHORUS_ENDSTONE_ITEM);
|
||||
entries.add(Szar.SMALL_CHORUS_ITEM);
|
||||
entries.add(Szar.SMALL_CHORUS_FLOWER_ITEM);
|
||||
entries.add(Szar.ENDER_OBSIDIAN_ITEM);
|
||||
entries.add(Szar.ENDER_ORE_ITEM);
|
||||
entries.add(Szar.RAW_ENDER);
|
||||
entries.add(Szar.ENDER_INGOT);
|
||||
// blueprint stuff
|
||||
entries.add(BlueprintBlocks.BLUEPRINT);
|
||||
entries.add(BlueprintBlocks.BLUEPRINT_DOOR_ITEM);
|
||||
entries.add(BlueprintBlocks.BLUEPRINT_TRAPDOOR_ITEM);
|
||||
entries.add(BlueprintBlocks.BLUEPRINT_FENCE_ITEM);
|
||||
entries.add(BlueprintBlocks.BLUEPRINT_SLAB_ITEM);
|
||||
entries.add(BlueprintBlocks.BLUEPRINT_WALL_ITEM);
|
||||
entries.add(BlueprintBlocks.BLUEPRINT_STAIRS_ITEM);
|
||||
|
||||
// board games
|
||||
entries.add(Szar.TIC_TAC_TOE_ITEM);
|
||||
entries.add(Szar.CONNECT_FOUR_ITEM);
|
||||
entries.add(Szar.CHESS_ITEM);
|
||||
@@ -1024,7 +1034,7 @@ public class Szar implements ModInitializer {
|
||||
});
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
|
||||
dispatcher.register(
|
||||
LiteralArgumentBuilder.<ServerCommandSource>literal("szar")
|
||||
LiteralArgumentBuilder.<ServerCommandSource>literal(MOD_ID)
|
||||
.requires(context -> context.hasPermissionLevel(2))
|
||||
|
||||
// /szar ny
|
||||
@@ -1378,6 +1388,35 @@ public class Szar implements ModInitializer {
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(SzarGameRules::pushToGameRules);
|
||||
|
||||
BlueprintBlocks.init();
|
||||
|
||||
ServerTickEvents.END_SERVER_TICK.register(server -> {
|
||||
for (ServerWorld world : server.getWorlds()) {
|
||||
|
||||
|
||||
// Handle item transformation
|
||||
for (ItemEntity item : world.getEntitiesByType(EntityType.ITEM, e -> true)) {
|
||||
if (!item.getStack().isOf(Items.CHORUS_FRUIT)) continue;
|
||||
|
||||
BlockPos pos = item.getBlockPos();
|
||||
BlockPos down = pos.down();
|
||||
|
||||
if (!chorusRolledEntities.contains(item.getId()) && world.getBlockState(down).isOf(Szar.CHORUS_ENDSTONE)) {
|
||||
chorusRolledEntities.add(item.getId());
|
||||
|
||||
int roll = world.getRandom().nextInt(100); // 0-99
|
||||
if (roll < 5) { // 5% -> 1 in 20 chance
|
||||
world.setBlockState(pos, Szar.SMALL_CHORUS.getDefaultState());
|
||||
item.remove(Entity.RemovalReason.DISCARDED);
|
||||
} else if (roll == 5) { // 2% -> 1 in 50 chance
|
||||
world.setBlockState(pos, Szar.SMALL_CHORUS_FLOWER.getDefaultState());
|
||||
item.remove(Entity.RemovalReason.DISCARDED);
|
||||
}
|
||||
// otherwise do nothing, just mark it as rolled
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
TheEndBiomeData.addEndBiomeReplacement(BiomeKeys.END_HIGHLANDS, Szar.CHORUS_FOREST, 0.7);
|
||||
}
|
||||
|
||||
public static final Block TIC_TAC_TOE_BLOCK = Registry.register(
|
||||
@@ -1442,7 +1481,74 @@ public class Szar implements ModInitializer {
|
||||
public static final Identifier CHESS_CLOSE_SCREEN = new Identifier(MOD_ID, "chess_close");
|
||||
|
||||
public static final Map<UUID, BlockPos> chessActivePlayers = new java.util.HashMap<>();
|
||||
|
||||
public static final RegistryKey<ConfiguredFeature<?, ?>> SMALL_CHORUS_CONFIGURED =
|
||||
RegistryKey.of(RegistryKeys.CONFIGURED_FEATURE, new Identifier(MOD_ID, "small_chorus"));
|
||||
public static final RegistryKey<PlacedFeature> SMALL_CHORUS_PLACED =
|
||||
RegistryKey.of(RegistryKeys.PLACED_FEATURE, new Identifier(MOD_ID, "small_chorus_patch"));
|
||||
public static final Block CHORUS_ENDSTONE = Registry.register(
|
||||
Registries.BLOCK,
|
||||
new Identifier(MOD_ID, "chorus_endstone"),
|
||||
new ChorusEndStone(FabricBlockSettings.copyOf(Blocks.END_STONE).ticksRandomly())
|
||||
);
|
||||
public static final Item CHORUS_ENDSTONE_ITEM = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(MOD_ID, "chorus_endstone"),
|
||||
new BlockItem(CHORUS_ENDSTONE, new FabricItemSettings())
|
||||
);
|
||||
public static final Block SMALL_CHORUS = Registry.register(
|
||||
Registries.BLOCK,
|
||||
new Identifier(MOD_ID, "small_chorus"),
|
||||
new SmallChorusBlock(FabricBlockSettings.copyOf(Blocks.GRASS))
|
||||
);
|
||||
public static final Item SMALL_CHORUS_ITEM = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(MOD_ID, "small_chorus"),
|
||||
new BlockItem(SMALL_CHORUS, new FabricItemSettings())
|
||||
);
|
||||
public static final Block SMALL_CHORUS_FLOWER = Registry.register(
|
||||
Registries.BLOCK,
|
||||
new Identifier(MOD_ID, "small_chorus_flower"),
|
||||
new SmallChorusFlowerBlock(FabricBlockSettings.copyOf(Blocks.POPPY).ticksRandomly())
|
||||
);
|
||||
public static final Item SMALL_CHORUS_FLOWER_ITEM = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(MOD_ID, "small_chorus_flower"),
|
||||
new BlockItem(SMALL_CHORUS_FLOWER, new FabricItemSettings())
|
||||
);
|
||||
public static final RegistryKey<Biome> CHORUS_FOREST = RegistryKey.of(
|
||||
RegistryKeys.BIOME,
|
||||
new Identifier(MOD_ID, "chorus_forest")
|
||||
);
|
||||
public static final Block ENDER_OBSIDIAN = Registry.register(
|
||||
Registries.BLOCK,
|
||||
new Identifier(MOD_ID, "ender_obsidian"),
|
||||
new EnderObsidian(FabricBlockSettings.copyOf(Blocks.OBSIDIAN))
|
||||
);
|
||||
public static final Item ENDER_OBSIDIAN_ITEM = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(MOD_ID, "ender_obsidian"),
|
||||
new BlockItem(ENDER_OBSIDIAN, new FabricItemSettings())
|
||||
);
|
||||
public static final Block ENDER_ORE = Registry.register(
|
||||
Registries.BLOCK,
|
||||
new Identifier(MOD_ID, "ender_ore"),
|
||||
new Block(FabricBlockSettings.copyOf(Blocks.OBSIDIAN))
|
||||
);
|
||||
public static final Item ENDER_ORE_ITEM = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(MOD_ID, "ender_ore"),
|
||||
new BlockItem(ENDER_ORE, new FabricItemSettings())
|
||||
);
|
||||
public static final Item RAW_ENDER = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(MOD_ID, "raw_ender"),
|
||||
new Item(new FabricItemSettings())
|
||||
);
|
||||
public static final Item ENDER_INGOT = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(MOD_ID, "ender_ingot"),
|
||||
new Item(new FabricItemSettings())
|
||||
);
|
||||
// Blocks
|
||||
public static final TrackerBlock TRACKER_BLOCK = Registry.register(
|
||||
Registries.BLOCK, new Identifier(MOD_ID, "tracker"),
|
||||
@@ -2530,7 +2636,7 @@ public class Szar implements ModInitializer {
|
||||
MinecraftServer server = serverPlayer.getServer();
|
||||
if (server == null) return;
|
||||
|
||||
if (!advancement.equals("szar")) {
|
||||
if (!advancement.equals(MOD_ID)) {
|
||||
grantAdvancement(player, "szar");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package dev.tggamesyt.szar.mixin;
|
||||
|
||||
import dev.tggamesyt.szar.Szar;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.ChorusFlowerBlock;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.tag.TagKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.WorldView;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(ChorusFlowerBlock.class)
|
||||
public abstract class ChorusFlowerBlockMixin {
|
||||
|
||||
@Unique
|
||||
private static final TagKey<Block> ENDSTONES =
|
||||
TagKey.of(RegistryKeys.BLOCK, new Identifier(Szar.MOD_ID, "endstones"));
|
||||
|
||||
/**
|
||||
* 🔥 Redirect EVERY BlockState.isOf call inside ChorusFlowerBlock
|
||||
* and replace END_STONE checks with tag checks
|
||||
*/
|
||||
@Redirect(
|
||||
method = {
|
||||
"canPlaceAt",
|
||||
"randomTick",
|
||||
"generate*",
|
||||
"scheduledTick"
|
||||
},
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/block/BlockState;isOf(Lnet/minecraft/block/Block;)Z"
|
||||
)
|
||||
)
|
||||
private boolean replaceEndStoneChecks(BlockState state, Block block) {
|
||||
|
||||
// Replace ONLY END_STONE checks
|
||||
if (block == Blocks.END_STONE) {
|
||||
return state.isIn(ENDSTONES);
|
||||
}
|
||||
|
||||
// Everything else stays vanilla
|
||||
return state.isOf(block);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package dev.tggamesyt.szar.mixin;
|
||||
|
||||
import dev.tggamesyt.szar.Szar;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.ChorusPlantBlock;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.tag.TagKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(ChorusPlantBlock.class)
|
||||
public abstract class ChorusPlantBlockMixin {
|
||||
|
||||
@Unique
|
||||
private static final TagKey<Block> ENDSTONES =
|
||||
TagKey.of(RegistryKeys.BLOCK, new Identifier(Szar.MOD_ID, "endstones"));
|
||||
|
||||
/**
|
||||
* 🔥 Replace ALL END_STONE checks in ChorusPlantBlock
|
||||
*/
|
||||
@Redirect(
|
||||
method = {
|
||||
"withConnectionProperties",
|
||||
"getStateForNeighborUpdate",
|
||||
"canPlaceAt"
|
||||
},
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/block/BlockState;isOf(Lnet/minecraft/block/Block;)Z"
|
||||
)
|
||||
)
|
||||
private boolean replaceEndStoneChecks(BlockState state, Block block) {
|
||||
|
||||
// Replace END_STONE with your tag
|
||||
if (block == Blocks.END_STONE) {
|
||||
return state.isIn(ENDSTONES);
|
||||
}
|
||||
|
||||
return state.isOf(block);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package dev.tggamesyt.szar.mixin;
|
||||
|
||||
import dev.tggamesyt.szar.Szar;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.tag.TagKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.world.gen.feature.ChorusPlantFeature;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(ChorusPlantFeature.class)
|
||||
public class ChorusPlantFeatureMixin {
|
||||
|
||||
@Unique
|
||||
private static final TagKey<Block> ENDSTONES =
|
||||
TagKey.of(RegistryKeys.BLOCK, new Identifier(Szar.MOD_ID, "endstones"));
|
||||
|
||||
@Redirect(
|
||||
method = "generate",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/block/BlockState;isOf(Lnet/minecraft/block/Block;)Z"
|
||||
)
|
||||
)
|
||||
private boolean replaceEndStoneCheck(BlockState state, Block block) {
|
||||
if (block == Blocks.END_STONE) {
|
||||
return state.isIn(ENDSTONES);
|
||||
}
|
||||
return state.isOf(block);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package dev.tggamesyt.szar.mixin;
|
||||
|
||||
import dev.tggamesyt.szar.Szar;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.gen.chunk.Blender;
|
||||
import net.minecraft.world.gen.chunk.NoiseChunkGenerator;
|
||||
import net.minecraft.world.ChunkRegion;
|
||||
import net.minecraft.world.gen.StructureAccessor;
|
||||
import net.minecraft.world.gen.noise.NoiseConfig;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(NoiseChunkGenerator.class)
|
||||
public class NoiseChunkGeneratorMixin {
|
||||
|
||||
@Inject(method = "buildSurface*", at = @At("TAIL"))
|
||||
private void replaceSurface(ChunkRegion region, StructureAccessor structures, NoiseConfig noiseConfig, Chunk chunk, CallbackInfo ci) {
|
||||
BlockPos.Mutable mutable = new BlockPos.Mutable();
|
||||
int startX = chunk.getPos().getStartX();
|
||||
int startZ = chunk.getPos().getStartZ();
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int worldX = startX + x;
|
||||
int worldZ = startZ + z;
|
||||
int topY = chunk.getHeightmap(net.minecraft.world.Heightmap.Type.WORLD_SURFACE_WG).get(x, z);
|
||||
|
||||
mutable.set(worldX, topY, worldZ);
|
||||
RegistryEntry<Biome> biome = region.getBiome(mutable);
|
||||
|
||||
if (biome.matchesKey(Szar.CHORUS_FOREST)) {
|
||||
mutable.set(worldX, topY - 1, worldZ);
|
||||
if (chunk.getBlockState(mutable).isOf(Blocks.END_STONE)) {
|
||||
chunk.setBlockState(mutable, Szar.CHORUS_ENDSTONE.getDefaultState(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package dev.tggamesyt.szar.mixin;
|
||||
|
||||
import dev.tggamesyt.szar.Szar;
|
||||
import net.minecraft.registry.RegistryEntryLookup;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.util.math.ChunkSectionPos;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeKeys;
|
||||
import net.minecraft.world.biome.source.BiomeCoords;
|
||||
import net.minecraft.world.biome.source.TheEndBiomeSource;
|
||||
import net.minecraft.world.biome.source.util.MultiNoiseUtil;
|
||||
import org.spongepowered.asm.mixin.*;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
@Mixin(TheEndBiomeSource.class)
|
||||
public class TheEndBiomeSourceMixin {
|
||||
|
||||
@Unique
|
||||
private RegistryEntry<Biome> szar$chorusEntry;
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void onInit(RegistryEntry<Biome> centerBiome, RegistryEntry<Biome> highlandsBiome, RegistryEntry<Biome> midlandsBiome, RegistryEntry<Biome> smallIslandsBiome, RegistryEntry<Biome> barrensBiome, CallbackInfo ci) {
|
||||
RegistryEntryLookup<Biome> lookup = net.fabricmc.fabric.impl.biome.TheEndBiomeData.biomeRegistry.get();
|
||||
if (lookup != null) {
|
||||
this.szar$chorusEntry = lookup.getOrThrow(Szar.CHORUS_FOREST);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "getBiome", at = @At("RETURN"), cancellable = true)
|
||||
private void overrideBiome(int x, int y, int z, MultiNoiseUtil.MultiNoiseSampler noise, CallbackInfoReturnable<RegistryEntry<Biome>> cir) {
|
||||
if (szar$chorusEntry == null) return;
|
||||
|
||||
RegistryEntry<Biome> result = cir.getReturnValue();
|
||||
if (!result.matchesKey(BiomeKeys.END_HIGHLANDS)
|
||||
&& !result.matchesKey(BiomeKeys.END_MIDLANDS)
|
||||
&& !result.matchesKey(BiomeKeys.END_BARRENS)) return;
|
||||
|
||||
int islandX = ChunkSectionPos.getSectionCoord(BiomeCoords.toBlock(x)) >> 3;
|
||||
int islandZ = ChunkSectionPos.getSectionCoord(BiomeCoords.toBlock(z)) >> 3;
|
||||
long islandSeed = (long) islandX * 341873128712L + (long) islandZ * 132897987541L;
|
||||
|
||||
if (new java.util.Random(islandSeed).nextFloat() < 0.4f) {
|
||||
cir.setReturnValue(szar$chorusEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "szar:block/chorus_endstone"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "szar:block/ender_obsidian"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "szar:block/ender_ore"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "szar:block/small_chorus"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "szar:block/small_chorus_flower"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,5 +197,14 @@
|
||||
"block.szar.blueprint_door": "Blueprint Door",
|
||||
"block.szar.blueprint_trapdoor": "Blueprint Trapdoor",
|
||||
"block.szar.blueprint_wall": "Blueprint Wall",
|
||||
"block.szar.blueprint_fence": "Blueprint Fence"
|
||||
"block.szar.blueprint_fence": "Blueprint Fence",
|
||||
"item.szar.blueprint": "Blueprint",
|
||||
|
||||
"block.szar.chorus_endstone": "Chorus EndStone",
|
||||
"block.szar.small_chorus": "Small Chorus",
|
||||
"block.szar.small_chorus_flower": "Small Chorus Flower",
|
||||
"block.szar.ender_obsidian": "Ender Obsidian",
|
||||
"block.szar.ender_ore": "Ender Ore",
|
||||
"item.szar.raw_ender": "Raw Ender",
|
||||
"item.szar.ender_ingot": "Ender Ingot"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:block/fence_inventory",
|
||||
"textures": {
|
||||
"texture": "szar:block/blueprint"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:block/wall_inventory",
|
||||
"textures": {
|
||||
"wall": "szar:block/blueprint"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"parent": "minecraft:block/cube_bottom_top",
|
||||
"textures": {
|
||||
"side": "szar:block/end_stone_grass",
|
||||
"bottom": "szar:block/end_stone",
|
||||
"top": "szar:block/chorus_top"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:block/cube_all",
|
||||
"textures": {
|
||||
"all": "szar:block/ender_obsidian"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:block/cube_all",
|
||||
"textures": {
|
||||
"all": "szar:block/ender_ore"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "block/cross",
|
||||
"textures": {
|
||||
"cross": "szar:block/small_chorus"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "block/cross",
|
||||
"textures": {
|
||||
"cross": "szar:block/small_chorus_flower"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "szar:item/blueprint"
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{ "parent": "minecraft:item/generated", "textures": { "layer0": "szar:block/blueprint" } }
|
||||
{ "parent": "minecraft:item/generated", "textures": { "layer0": "szar:block/blueprint_door" } }
|
||||
@@ -1 +1 @@
|
||||
{ "parent": "szar:block/blueprint_fence_post" }
|
||||
{ "parent": "szar:block/blueprint_fence_inventory" }
|
||||
@@ -1 +1 @@
|
||||
{ "parent": "szar:block/blueprint_wall_post" }
|
||||
{ "parent": "szar:block/blueprint_wall_inventory" }
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "szar:block/chorus_endstone"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "szar:item/ender_ingot"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "szar:block/ender_obsidian"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "szar:block/ender_ore"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "szar:item/raw_ender"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "szar:block/small_chorus"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "szar:block/small_chorus_flower"
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/assets/szar/textures/block/blueprint.png
Normal file
|
After Width: | Height: | Size: 880 B |
BIN
src/main/resources/assets/szar/textures/block/blueprint_door.png
Normal file
|
After Width: | Height: | Size: 984 B |
BIN
src/main/resources/assets/szar/textures/block/chorus_flower.png
Normal file
|
After Width: | Height: | Size: 325 B |
|
After Width: | Height: | Size: 328 B |
BIN
src/main/resources/assets/szar/textures/block/chorus_plant.png
Normal file
|
After Width: | Height: | Size: 300 B |
BIN
src/main/resources/assets/szar/textures/block/chorus_shuffle.png
Normal file
|
After Width: | Height: | Size: 604 B |
|
After Width: | Height: | Size: 664 B |
BIN
src/main/resources/assets/szar/textures/block/chorus_top.png
Normal file
|
After Width: | Height: | Size: 645 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 823 B |
BIN
src/main/resources/assets/szar/textures/block/choruscolor.png
Normal file
|
After Width: | Height: | Size: 904 B |
|
After Width: | Height: | Size: 315 B |
BIN
src/main/resources/assets/szar/textures/block/end_stone.png
Normal file
|
After Width: | Height: | Size: 270 B |
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src/main/resources/assets/szar/textures/block/ender_obsidian.png
Normal file
|
After Width: | Height: | Size: 581 B |
BIN
src/main/resources/assets/szar/textures/block/ender_ore.png
Normal file
|
After Width: | Height: | Size: 489 B |
|
After Width: | Height: | Size: 177 B |
|
After Width: | Height: | Size: 560 B |
|
After Width: | Height: | Size: 795 B |
BIN
src/main/resources/assets/szar/textures/block/small_chorus.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
BIN
src/main/resources/assets/szar/textures/item/blueprint.png
Normal file
|
After Width: | Height: | Size: 854 B |
BIN
src/main/resources/assets/szar/textures/item/ender_ingot.png
Normal file
|
After Width: | Height: | Size: 367 B |
BIN
src/main/resources/assets/szar/textures/item/raw_ender.png
Normal file
|
After Width: | Height: | Size: 441 B |
BIN
src/main/resources/assets/szar/textures/item/raw_ender_1.png
Normal file
|
After Width: | Height: | Size: 359 B |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"szar:blueprint_fence"
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"values": [
|
||||
"szar:chemical_workbench",
|
||||
"szar:roulette",
|
||||
"szar:slot_machine",
|
||||
"szar:tictactoe",
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
"replace": false,
|
||||
"values": [
|
||||
"szar:uranium_ore",
|
||||
"szar:niggerite_block"
|
||||
"szar:niggerite_block",
|
||||
"szar:chorus_endstone",
|
||||
"szar:ender_ore",
|
||||
"szar:ender_obsidian"
|
||||
]
|
||||
}
|
||||
|
||||
6
src/main/resources/data/minecraft/tags/blocks/walls.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"szar:blueprint_wall"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"szar:blueprint_fence"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "szar:blueprint_door"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "szar:blueprint_fence"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"bonus_rolls": 0.0,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"functions": [
|
||||
{
|
||||
"add": false,
|
||||
"conditions": [
|
||||
{
|
||||
"block": "szar:blueprint_slab",
|
||||
"condition": "minecraft:block_state_property",
|
||||
"properties": {
|
||||
"type": "double"
|
||||
}
|
||||
}
|
||||
],
|
||||
"count": 2.0,
|
||||
"function": "minecraft:set_count"
|
||||
},
|
||||
{
|
||||
"function": "minecraft:explosion_decay"
|
||||
}
|
||||
],
|
||||
"name": "szar:blueprint_slab"
|
||||
}
|
||||
],
|
||||
"rolls": 1.0
|
||||
}
|
||||
],
|
||||
"random_sequence": "minecraft:blocks/stone_slab"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "szar:blueprint_stairs"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "szar:blueprint_trapdoor"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "szar:blueprint_wall"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "szar:chemical_workbench"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"bonus_rolls": 0.0,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:alternatives",
|
||||
"children": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:match_tool",
|
||||
"predicate": {
|
||||
"enchantments": [
|
||||
{
|
||||
"enchantment": "minecraft:silk_touch",
|
||||
"levels": {
|
||||
"min": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "szar:chorus_endstone"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
],
|
||||
"name": "minecraft:end_stone"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"rolls": 1.0
|
||||
}
|
||||
],
|
||||
"random_sequence": "minecraft:blocks/grass_block"
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:alternatives",
|
||||
"children": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "szar:ender_ore",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:match_tool",
|
||||
"predicate": {
|
||||
"enchantments": [
|
||||
{
|
||||
"enchantment": "minecraft:silk_touch",
|
||||
"levels": {
|
||||
"min": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"items": [
|
||||
"minecraft:diamond_pickaxe",
|
||||
"minecraft:netherite_pickaxe"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "szar:raw_ender",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:match_tool",
|
||||
"predicate": {
|
||||
"items": [
|
||||
"minecraft:netherite_pickaxe"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"bonus_rolls": 0.0,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:alternatives",
|
||||
"children": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:match_tool",
|
||||
"predicate": {
|
||||
"items": [
|
||||
"minecraft:shears"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "szar:small_chorus"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"conditions": [
|
||||
{
|
||||
"chance": 0.125,
|
||||
"condition": "minecraft:random_chance"
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"enchantment": "minecraft:fortune",
|
||||
"formula": "minecraft:uniform_bonus_count",
|
||||
"function": "minecraft:apply_bonus",
|
||||
"parameters": {
|
||||
"bonusMultiplier": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"function": "minecraft:explosion_decay"
|
||||
}
|
||||
],
|
||||
"name": "minecraft:chorus_fruit"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"rolls": 1.0
|
||||
}
|
||||
],
|
||||
"random_sequence": "minecraft:blocks/grass"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"bonus_rolls": 0.0,
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "szar:small_chorus_flower"
|
||||
}
|
||||
],
|
||||
"rolls": 1.0
|
||||
}
|
||||
],
|
||||
"random_sequence": "minecraft:blocks/poppy"
|
||||
}
|
||||
20
src/main/resources/data/szar/recipes/blueprint.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [
|
||||
" B ",
|
||||
"BPB",
|
||||
" B "
|
||||
],
|
||||
"key": {
|
||||
"B": {
|
||||
"tag": "szar:blue"
|
||||
},
|
||||
"P": {
|
||||
"item": "minecraft:paper"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "szar:blueprint",
|
||||
"count": 1
|
||||
}
|
||||
}
|
||||
17
src/main/resources/data/szar/recipes/blueprint_door.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [
|
||||
"BB",
|
||||
"BB",
|
||||
"BB"
|
||||
],
|
||||
"key": {
|
||||
"B": {
|
||||
"item": "szar:blueprint"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "szar:blueprint_door",
|
||||
"count": 1
|
||||
}
|
||||
}
|
||||