Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1427eb9e9a | |||
| 0ad489f82f | |||
| 43ad0cca5a | |||
| 72274c08f8 | |||
| 6b95a3891f | |||
| 36e2b9a886 | |||
| 932254b1d9 | |||
| 1b9f7d85c0 | |||
| 77d7e7412e | |||
| fd94a17dbe | |||
| 758cce1623 | |||
| 629ab9fba3 | |||
| 6c530c2651 | |||
| 0d5bc6a5bf | |||
| 6b7dd9f96a | |||
| 3475b19df5 | |||
| e30e42ff51 | |||
| 0d8a24c7dc | |||
| 613965f989 | |||
| 64fc1eea2d | |||
| e6319f88e0 |
2
.gitignore
vendored
@ -36,3 +36,5 @@ loom-cache/
|
||||
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
run-*/
|
||||
270
CONTRIBUTING.md
Normal file
@ -0,0 +1,270 @@
|
||||
# Contributing Guide (Java Style)
|
||||
|
||||
This project follows a strict, C/C++-style Java formatting rule set. The goal is to preserve intent, control flow clarity, and fast mental parsing. Please follow these rules for any Java changes.
|
||||
|
||||
If a tool or formatter fights these rules, the tool is wrong.
|
||||
|
||||
## Core Philosophy
|
||||
|
||||
- Java is written as if it were C/C++.
|
||||
- Formatting must never change perceived control flow.
|
||||
- Readability means fast, correct parsing in your head.
|
||||
- Tools adapt to the codebase, not the other way around.
|
||||
|
||||
## Indentation & Whitespace
|
||||
|
||||
- Indentation: 4 spaces.
|
||||
- No tabs.
|
||||
- Avoid excessive vertical whitespace.
|
||||
- Blank lines only when they add logical separation.
|
||||
|
||||
✅ Good:
|
||||
```java
|
||||
int sum(int a, int b) {
|
||||
int r = a + b;
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
❌ Bad:
|
||||
```java
|
||||
int sum(int a, int b)
|
||||
|
||||
{
|
||||
|
||||
int r = a + b;
|
||||
|
||||
return r;
|
||||
}
|
||||
```
|
||||
|
||||
## Braces
|
||||
|
||||
- Braces are always required.
|
||||
- Opening brace stays on the same line.
|
||||
- Never rely on implicit scopes.
|
||||
|
||||
✅ Good:
|
||||
```java
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
❌ Bad:
|
||||
```java
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
## Imports (Strict Rules)
|
||||
|
||||
### Never use fully-qualified class names inline
|
||||
|
||||
❌ Forbidden:
|
||||
```java
|
||||
net.minecraft.util.math.BlockPos pos = new net.minecraft.util.math.BlockPos(0, 0, 0);
|
||||
```
|
||||
|
||||
✅ Required:
|
||||
```java
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
BlockPos pos = new BlockPos(0, 0, 0);
|
||||
```
|
||||
|
||||
### Import grouping and ordering
|
||||
|
||||
1) Imports from external/other packages first.
|
||||
2) Blank line.
|
||||
3) Imports from this project (net.Chipperfluff.*) next.
|
||||
|
||||
Inside each block, order by:
|
||||
1) Classes
|
||||
2) Functions (static method imports)
|
||||
3) Variables/constants (static field imports)
|
||||
4) Enums
|
||||
|
||||
If there are no project imports, do not add a blank line.
|
||||
|
||||
## Method Signatures
|
||||
|
||||
- Method signatures must stay on one line.
|
||||
- Do not break parameters across multiple lines.
|
||||
- Long lines are acceptable; ambiguity is not.
|
||||
|
||||
✅ Good:
|
||||
```java
|
||||
void processUser(User user, int flags, boolean force, long timeout) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
❌ Bad:
|
||||
```java
|
||||
void processUser(
|
||||
User user,
|
||||
int flags,
|
||||
boolean force,
|
||||
long timeout
|
||||
) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Function Calls & Argument Layout
|
||||
|
||||
### Default rule
|
||||
- Single-line calls are preferred.
|
||||
- Flat calls stay flat.
|
||||
- Length alone is not a reason to wrap.
|
||||
|
||||
✅ Good:
|
||||
```java
|
||||
Color color = user.getProfile().getSettings().getTheme().getPrimaryColor();
|
||||
```
|
||||
|
||||
### Multiline calls are allowed only when:
|
||||
- The call is structural or declarative.
|
||||
- Each argument is conceptually distinct.
|
||||
- Nesting would otherwise hide meaning.
|
||||
|
||||
✅ Good (structural/declarative):
|
||||
```java
|
||||
BiomeModifications.addFeature(
|
||||
BiomeSelectors.foundInOverworld(),
|
||||
GenerationStep.Feature.UNDERGROUND_ORES,
|
||||
RegistryKey.of(
|
||||
RegistryKeys.PLACED_FEATURE,
|
||||
new Identifier("chipi", "chipper_ore")
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
❌ Bad (no semantic gain):
|
||||
```java
|
||||
doThing(
|
||||
a,
|
||||
b,
|
||||
c
|
||||
);
|
||||
```
|
||||
|
||||
## Chained Calls
|
||||
|
||||
- Flat chains stay on one line.
|
||||
- Long or builder-style chains may be split vertically.
|
||||
- Each chained step gets its own line.
|
||||
|
||||
✅ Good:
|
||||
```java
|
||||
builder
|
||||
.withColor(theme.getPrimaryColor())
|
||||
.withSize(32)
|
||||
.enableShadow()
|
||||
.build();
|
||||
```
|
||||
|
||||
❌ Bad:
|
||||
```java
|
||||
builder.withColor(
|
||||
theme.getPrimaryColor()
|
||||
).withSize(
|
||||
32
|
||||
).enableShadow().build();
|
||||
```
|
||||
|
||||
## Control Flow & Returns
|
||||
|
||||
- Early returns are encouraged.
|
||||
- Avoid artificial nesting.
|
||||
- Single-exit functions are not required.
|
||||
|
||||
✅ Good:
|
||||
```java
|
||||
void handle(User user) {
|
||||
if (user == null) return;
|
||||
if (!user.isActive()) return;
|
||||
|
||||
process(user);
|
||||
}
|
||||
```
|
||||
|
||||
❌ Bad:
|
||||
```java
|
||||
void handle(User user) {
|
||||
if (user != null) {
|
||||
if (user.isActive()) {
|
||||
process(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## One-Liners
|
||||
|
||||
- One-liners allowed for simple guard clauses.
|
||||
- No complex logic on one line.
|
||||
|
||||
✅ Allowed:
|
||||
```java
|
||||
if (value == null) return;
|
||||
```
|
||||
|
||||
❌ Not allowed:
|
||||
```java
|
||||
if (a == b && c != d && flag && check()) doThing();
|
||||
```
|
||||
|
||||
## Null Handling
|
||||
|
||||
- null is a valid, intentional state.
|
||||
- Do not over-engineer around it.
|
||||
- Prefer clarity over defensive clutter.
|
||||
|
||||
✅ Good:
|
||||
```java
|
||||
User user = findUser(id);
|
||||
if (user == null) return;
|
||||
```
|
||||
|
||||
## Logging & Debug Output
|
||||
|
||||
- Logging must be short and readable.
|
||||
- Prefer System.out.println for quick diagnostics.
|
||||
- Verbose logging only when justified.
|
||||
|
||||
✅ Good:
|
||||
```java
|
||||
System.out.println("Loaded structure: " + id);
|
||||
```
|
||||
|
||||
## Autoformatters & Linters
|
||||
|
||||
Autoformatters must not:
|
||||
|
||||
- Break method signatures.
|
||||
- Move braces to new lines.
|
||||
- Introduce unwanted trailing newlines.
|
||||
- Rewrap stable code repeatedly.
|
||||
|
||||
If a formatter fights these rules: disable or reconfigure it.
|
||||
|
||||
## Empty Methods
|
||||
|
||||
Empty methods or constructors must be written on one line:
|
||||
|
||||
```java
|
||||
public static void register() {}
|
||||
```
|
||||
|
||||
## Summary (Non-Negotiable)
|
||||
|
||||
- Java written with C/C++ structure.
|
||||
- Compact signatures, explicit layout.
|
||||
- Imports always used (no fully-qualified inline types).
|
||||
- Multiline formatting only when it adds meaning.
|
||||
- Formatting reflects logic, not fashion.
|
||||
|
||||
121
IDEAS.md
Normal file
@ -0,0 +1,121 @@
|
||||
# Chipi Mod Ideas
|
||||
|
||||
## Progression Loop
|
||||
### Idea
|
||||
Add a portal activator + key system that unlocks deeper rooms in the Chipi dimension.
|
||||
### What It Does
|
||||
Creates a clear loop: build portal → explore → collect keys → access new room tiers.
|
||||
|
||||
## Dungeon Variety
|
||||
### Idea
|
||||
Add multiple room archetypes: loot rooms, trap rooms, dead ends, vertical shafts.
|
||||
### What It Does
|
||||
Breaks up repetition and makes each run feel less predictable.
|
||||
|
||||
## Chipi Loot Tables
|
||||
### Idea
|
||||
Create loot tables for rooms/corridors with unique tools, curios, and lore items.
|
||||
### What It Does
|
||||
Rewards exploration beyond ore grinding.
|
||||
|
||||
## Miniboss or Boss
|
||||
### Idea
|
||||
Add a rare boss like "Mep Alpha" or "Void Warden" that guards a core material.
|
||||
### What It Does
|
||||
Gives a big milestone and a reason to return to the dimension.
|
||||
|
||||
## Player Jr Modes
|
||||
### Idea
|
||||
Add follow/guard/wander + sit/teleport behaviors, plus simple leveling perks.
|
||||
### What It Does
|
||||
Turns Player Jr into a companion system instead of a single behavior.
|
||||
|
||||
## Jr Recall Item
|
||||
### Idea
|
||||
Add a "Jr Whistle" to recall Player Jr to you or to the portal spawn.
|
||||
### What It Does
|
||||
Fixes pathing loss and makes Jr easier to manage.
|
||||
|
||||
## Aura-Driven Tool Skills
|
||||
### Idea
|
||||
Add a short dash, shield, or blink that consumes the aura bar.
|
||||
### What It Does
|
||||
Lets the aura system do more than passive energy display.
|
||||
|
||||
## Chipi Shrine
|
||||
### Idea
|
||||
Add a recharge block or ritual that refills aura energy for materials.
|
||||
### What It Does
|
||||
Creates a resource sink and a strategic rest point.
|
||||
|
||||
## Expanded Milk Uses
|
||||
### Idea
|
||||
Use Mep Milk and Player Milk in brewing or special recipes.
|
||||
### What It Does
|
||||
Gives the items more long-term value.
|
||||
|
||||
## Mep Variants
|
||||
### Idea
|
||||
Add a rare friendly Mep variant with unique drops or interactions.
|
||||
### What It Does
|
||||
Adds discovery moments and variety to the mob.
|
||||
|
||||
## Chipper Upgrades
|
||||
### Idea
|
||||
Add reinforced or blessed chipper armor/tools with small set bonuses.
|
||||
### What It Does
|
||||
Extends gear progression past base chipper items.
|
||||
|
||||
## Portal Effects
|
||||
### Idea
|
||||
Add particles, ambient hum, and a short screen tint on teleport.
|
||||
### What It Does
|
||||
Makes portal travel feel more special.
|
||||
|
||||
## Void Hazard Zones
|
||||
### Idea
|
||||
Add a "void fog" or patches that drain aura instead of insta-kill.
|
||||
### What It Does
|
||||
Creates tension without instant death.
|
||||
|
||||
## Dimension Ambience
|
||||
### Idea
|
||||
Custom sky color, fog distance, and looping ambient sound in Chipi.
|
||||
### What It Does
|
||||
Strengthens the dimension's atmosphere.
|
||||
|
||||
## Chipi Compass
|
||||
### Idea
|
||||
Add a compass item that points to the nearest room or portal.
|
||||
### What It Does
|
||||
Helps navigation in the dungeon grid.
|
||||
|
||||
## Block Family
|
||||
### Idea
|
||||
Add stairs/slabs/walls for Chipi blocks.
|
||||
### What It Does
|
||||
Improves building options in the dimension.
|
||||
|
||||
## Rare Ore Nodes
|
||||
### Idea
|
||||
Add rare geodes or ore nodes unique to Chipi for discs or relics.
|
||||
### What It Does
|
||||
Creates a high-value hunt target.
|
||||
|
||||
## Trader NPC
|
||||
### Idea
|
||||
Add a small trader that spawns in certain rooms.
|
||||
### What It Does
|
||||
Introduces a non-hostile encounter with unique trades.
|
||||
|
||||
## New Advancements
|
||||
### Idea
|
||||
Add a few fun advancements for Mep interactions and Player Jr milestones.
|
||||
### What It Does
|
||||
Highlights quirky features and gives players goals.
|
||||
|
||||
## Structure Test Tools
|
||||
### Idea
|
||||
Add a command for random room placement to quickly test layouts.
|
||||
### What It Does
|
||||
Speeds up iteration on dungeon design.
|
||||
20
build.gradle
@ -3,7 +3,7 @@ plugins {
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
version = "1.0.0"
|
||||
version = "0.0.3"
|
||||
group = "net.Chipperfluff"
|
||||
|
||||
repositories {
|
||||
@ -25,3 +25,21 @@ java {
|
||||
languageVersion = JavaLanguageVersion.of(17)
|
||||
}
|
||||
}
|
||||
|
||||
loom {
|
||||
runs {
|
||||
server {
|
||||
server()
|
||||
runDir "run-server"
|
||||
}
|
||||
client1 {
|
||||
client()
|
||||
runDir "run-1"
|
||||
}
|
||||
client2 {
|
||||
client()
|
||||
runDir "run-2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
build.sh
@ -1 +0,0 @@
|
||||
clear;rm -rf run;./gradlew runClient --stacktrace --info;echo '';tree --gitignore
|
||||
236
chipper
Executable file
@ -0,0 +1,236 @@
|
||||
#!/usr/bin/env bash
|
||||
set -u
|
||||
|
||||
GRADLE="./gradlew"
|
||||
GRADLE_BASE_FLAGS=(
|
||||
"--console=plain"
|
||||
"--no-daemon"
|
||||
"-Dfabric.development=true"
|
||||
"-Dminecraft.api.env=dev"
|
||||
"-Dminecraft.session.disable=true"
|
||||
)
|
||||
|
||||
OPTIONS_SRC="./config/options.txt"
|
||||
|
||||
ROLE=""
|
||||
ROLE_INDEX=""
|
||||
PASSTHROUGH=()
|
||||
|
||||
# ---------- utils ----------
|
||||
|
||||
rand() { shuf -i 0-$(($1 - 1)) -n 1; }
|
||||
|
||||
parse_args() {
|
||||
local cleaned=()
|
||||
for ((i=0; i<${#ARGS[@]}; i++)); do
|
||||
case "${ARGS[$i]}" in
|
||||
-s|--server)
|
||||
ROLE="server"
|
||||
;;
|
||||
-p1|--player1)
|
||||
ROLE="client"
|
||||
ROLE_INDEX=1
|
||||
;;
|
||||
-p2|--player2)
|
||||
ROLE="client"
|
||||
ROLE_INDEX=2
|
||||
;;
|
||||
--)
|
||||
PASSTHROUGH=( "${ARGS[@]:$((i+1))}" )
|
||||
break
|
||||
;;
|
||||
*)
|
||||
cleaned+=( "${ARGS[$i]}" )
|
||||
;;
|
||||
esac
|
||||
done
|
||||
ARGS=( "${cleaned[@]}" )
|
||||
}
|
||||
|
||||
# ---------- run-dir helpers ----------
|
||||
|
||||
prepare_run_dir() {
|
||||
local dir="$1"
|
||||
rm -rf "$dir"
|
||||
mkdir -p "$dir"
|
||||
}
|
||||
|
||||
inject_options() {
|
||||
local dir="$1"
|
||||
|
||||
# options.txt
|
||||
if [[ -f "$OPTIONS_SRC" ]]; then
|
||||
cp "$OPTIONS_SRC" "$dir/options.txt"
|
||||
fi
|
||||
|
||||
# servers.dat (client server list)
|
||||
if [[ -f "./config/servers.dat" ]]; then
|
||||
cp "./config/servers.dat" "$dir/servers.dat"
|
||||
fi
|
||||
|
||||
# server.properties
|
||||
if [[ -f "./config/server.properties" ]]; then
|
||||
cp "./config/server.properties" "$dir/server.properties"
|
||||
fi
|
||||
|
||||
# server icon
|
||||
if [[ -f "./config/server-icon.png" ]]; then
|
||||
cp "./config/server-icon.png" "$dir/server-icon.png"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_server_files() {
|
||||
local dir="$1"
|
||||
|
||||
[[ -f "$dir/eula.txt" ]] || echo "eula=true" > "$dir/eula.txt"
|
||||
|
||||
if [[ ! -f "$dir/server.properties" ]]; then
|
||||
cat > "$dir/server.properties" <<EOF
|
||||
online-mode=false
|
||||
server-port=25565
|
||||
level-name=world
|
||||
enable-command-block=true
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------- squirrel ----------
|
||||
|
||||
header() {
|
||||
local action="$1"
|
||||
|
||||
local squirrels=(
|
||||
' /\_/\
|
||||
( o.o )
|
||||
> ^ <'
|
||||
|
||||
' /\_/\
|
||||
( -.- )
|
||||
o_(")(")'
|
||||
|
||||
' /\_/\
|
||||
( @.@ )
|
||||
> ~ <'
|
||||
)
|
||||
|
||||
clear
|
||||
echo "${squirrels[$(rand ${#squirrels[@]})]}"
|
||||
echo
|
||||
case "$action" in
|
||||
run) echo "🐿️ running chipper" ;;
|
||||
clean) echo "🐿️ cleaning workspace" ;;
|
||||
build) echo "🐿️ building project" ;;
|
||||
tree) echo "🐿️ observing project tree" ;;
|
||||
*) echo "🐿️ thinking..." ;;
|
||||
esac
|
||||
echo
|
||||
}
|
||||
|
||||
# ---------- commands ----------
|
||||
|
||||
cmd_run() {
|
||||
header run
|
||||
|
||||
case "$ROLE" in
|
||||
server)
|
||||
run_dir="run-server"
|
||||
prepare_run_dir "$run_dir"
|
||||
inject_options "$run_dir"
|
||||
ensure_server_files "$run_dir"
|
||||
|
||||
echo "🖥️🐿️ starting dedicated server"
|
||||
exec "$GRADLE" runServer "${GRADLE_BASE_FLAGS[@]}" "${PASSTHROUGH[@]}"
|
||||
;;
|
||||
|
||||
client)
|
||||
run_dir="run-$ROLE_INDEX"
|
||||
task="runClient$ROLE_INDEX"
|
||||
prepare_run_dir "$run_dir"
|
||||
inject_options "$run_dir"
|
||||
|
||||
echo "🎮🐿️ starting client $ROLE_INDEX"
|
||||
exec "$GRADLE" "$task" "${GRADLE_BASE_FLAGS[@]}" "${PASSTHROUGH[@]}"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "❌🐿️ no role selected"
|
||||
echo "👉🐿️ use one of:"
|
||||
echo " --server"
|
||||
echo " --player1"
|
||||
echo " --player2"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
cmd_clean() {
|
||||
header clean
|
||||
"$GRADLE" clean "${GRADLE_BASE_FLAGS[@]}" "${PASSTHROUGH[@]}"
|
||||
}
|
||||
|
||||
cmd_build() {
|
||||
header build
|
||||
"$GRADLE" build "${GRADLE_BASE_FLAGS[@]}" "${PASSTHROUGH[@]}"
|
||||
}
|
||||
|
||||
cmd_tree() {
|
||||
header tree
|
||||
tree --gitignore
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
cat <<'EOF'
|
||||
/\_/\
|
||||
( o.o )
|
||||
> ^ <
|
||||
|
||||
🐿️ C H I P P E R
|
||||
|
||||
Usage:
|
||||
./chipper run [role] [-- passthrough]
|
||||
|
||||
Roles:
|
||||
-s, --server Start ONLY server
|
||||
-p1, --player1 Start ONLY client 1
|
||||
-p2, --player2 Start ONLY client 2
|
||||
|
||||
Other commands:
|
||||
clean Gradle clean
|
||||
build Gradle build
|
||||
tree Show project tree
|
||||
help Show this menu
|
||||
|
||||
Examples:
|
||||
./chipper run --server
|
||||
./chipper run --player1
|
||||
./chipper run --player2
|
||||
./chipper run --player1 -- --debug
|
||||
./chipper build
|
||||
./chipper tree
|
||||
|
||||
Notes:
|
||||
- No legacy player spawning
|
||||
- Each role has its own run directory
|
||||
- options.txt injected per run dir
|
||||
- Everything after `--` is forwarded
|
||||
- The squirrel is mandatory
|
||||
EOF
|
||||
}
|
||||
|
||||
# ---------- entry ----------
|
||||
|
||||
ARGS=( "$@" )
|
||||
parse_args
|
||||
|
||||
case "${ARGS[0]:-help}" in
|
||||
run) cmd_run ;;
|
||||
clean) cmd_clean ;;
|
||||
build) cmd_build ;;
|
||||
tree) cmd_tree ;;
|
||||
help|-h) cmd_help ;;
|
||||
*)
|
||||
echo "[!] Unknown command: ${ARGS[0]}"
|
||||
cmd_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
137
config/options.txt
Normal file
@ -0,0 +1,137 @@
|
||||
version:3465
|
||||
autoJump:false
|
||||
operatorItemsTab:false
|
||||
autoSuggestions:true
|
||||
chatColors:true
|
||||
chatLinks:true
|
||||
chatLinksPrompt:true
|
||||
enableVsync:true
|
||||
entityShadows:true
|
||||
forceUnicodeFont:false
|
||||
discrete_mouse_scroll:false
|
||||
invertYMouse:false
|
||||
realmsNotifications:true
|
||||
reducedDebugInfo:false
|
||||
showSubtitles:false
|
||||
directionalAudio:false
|
||||
touchscreen:false
|
||||
fullscreen:false
|
||||
bobView:true
|
||||
toggleCrouch:false
|
||||
toggleSprint:false
|
||||
darkMojangStudiosBackground:false
|
||||
hideLightningFlashes:false
|
||||
mouseSensitivity:0.5
|
||||
fov:0.0
|
||||
screenEffectScale:1.0
|
||||
fovEffectScale:1.0
|
||||
darknessEffectScale:1.0
|
||||
glintSpeed:0.5
|
||||
glintStrength:0.75
|
||||
damageTiltStrength:1.0
|
||||
highContrast:false
|
||||
gamma:0.5
|
||||
renderDistance:12
|
||||
simulationDistance:12
|
||||
entityDistanceScaling:1.0
|
||||
guiScale:0
|
||||
particles:0
|
||||
maxFps:120
|
||||
graphicsMode:1
|
||||
ao:true
|
||||
prioritizeChunkUpdates:0
|
||||
biomeBlendRadius:2
|
||||
renderClouds:"true"
|
||||
resourcePacks:["fabric"]
|
||||
incompatibleResourcePacks:[]
|
||||
lastServer:
|
||||
lang:en_us
|
||||
soundDevice:""
|
||||
chatVisibility:0
|
||||
chatOpacity:1.0
|
||||
chatLineSpacing:0.0
|
||||
textBackgroundOpacity:0.5
|
||||
backgroundForChatOnly:true
|
||||
hideServerAddress:false
|
||||
advancedItemTooltips:false
|
||||
pauseOnLostFocus:true
|
||||
overrideWidth:0
|
||||
overrideHeight:0
|
||||
chatHeightFocused:1.0
|
||||
chatDelay:0.0
|
||||
chatHeightUnfocused:0.4375
|
||||
chatScale:1.0
|
||||
chatWidth:1.0
|
||||
notificationDisplayTime:1.0
|
||||
mipmapLevels:4
|
||||
useNativeTransport:true
|
||||
mainHand:"right"
|
||||
attackIndicator:1
|
||||
narrator:0
|
||||
tutorialStep:movement
|
||||
mouseWheelSensitivity:1.0
|
||||
rawMouseInput:true
|
||||
glDebugVerbosity:1
|
||||
skipMultiplayerWarning:true
|
||||
skipRealms32bitWarning:true
|
||||
hideMatchedNames:true
|
||||
joinedFirstServer:false
|
||||
hideBundleTutorial:false
|
||||
syncChunkWrites:false
|
||||
showAutosaveIndicator:true
|
||||
allowServerListing:true
|
||||
onlyShowSecureChat:false
|
||||
panoramaScrollSpeed:1.0
|
||||
telemetryOptInExtra:false
|
||||
onboardAccessibility:false
|
||||
key_key.attack:key.mouse.left
|
||||
key_key.use:key.mouse.right
|
||||
key_key.forward:key.keyboard.w
|
||||
key_key.left:key.keyboard.a
|
||||
key_key.back:key.keyboard.s
|
||||
key_key.right:key.keyboard.d
|
||||
key_key.jump:key.keyboard.space
|
||||
key_key.sneak:key.keyboard.left.shift
|
||||
key_key.sprint:key.keyboard.left.control
|
||||
key_key.drop:key.keyboard.q
|
||||
key_key.inventory:key.keyboard.e
|
||||
key_key.chat:key.keyboard.t
|
||||
key_key.playerlist:key.keyboard.tab
|
||||
key_key.pickItem:key.mouse.middle
|
||||
key_key.command:key.keyboard.slash
|
||||
key_key.socialInteractions:key.keyboard.p
|
||||
key_key.screenshot:key.keyboard.f2
|
||||
key_key.togglePerspective:key.keyboard.f5
|
||||
key_key.smoothCamera:key.keyboard.unknown
|
||||
key_key.fullscreen:key.keyboard.f11
|
||||
key_key.spectatorOutlines:key.keyboard.unknown
|
||||
key_key.swapOffhand:key.keyboard.f
|
||||
key_key.saveToolbarActivator:key.keyboard.c
|
||||
key_key.loadToolbarActivator:key.keyboard.x
|
||||
key_key.advancements:key.keyboard.l
|
||||
key_key.hotbar.1:key.keyboard.1
|
||||
key_key.hotbar.2:key.keyboard.2
|
||||
key_key.hotbar.3:key.keyboard.3
|
||||
key_key.hotbar.4:key.keyboard.4
|
||||
key_key.hotbar.5:key.keyboard.5
|
||||
key_key.hotbar.6:key.keyboard.6
|
||||
key_key.hotbar.7:key.keyboard.7
|
||||
key_key.hotbar.8:key.keyboard.8
|
||||
key_key.hotbar.9:key.keyboard.9
|
||||
soundCategory_master:1.0
|
||||
soundCategory_music:0.0
|
||||
soundCategory_record:1.0
|
||||
soundCategory_weather:1.0
|
||||
soundCategory_block:1.0
|
||||
soundCategory_hostile:1.0
|
||||
soundCategory_neutral:1.0
|
||||
soundCategory_player:1.0
|
||||
soundCategory_ambient:1.0
|
||||
soundCategory_voice:1.0
|
||||
modelPart_cape:true
|
||||
modelPart_jacket:true
|
||||
modelPart_left_sleeve:true
|
||||
modelPart_right_sleeve:true
|
||||
modelPart_left_pants_leg:true
|
||||
modelPart_right_pants_leg:true
|
||||
modelPart_hat:true
|
||||
BIN
config/server-icon.png
Normal file
|
After Width: | Height: | Size: 417 B |
58
config/server.properties
Normal file
@ -0,0 +1,58 @@
|
||||
#Minecraft server properties
|
||||
#Mon Dec 22 17:38:51 CET 2025
|
||||
allow-flight=false
|
||||
allow-nether=true
|
||||
broadcast-console-to-ops=true
|
||||
broadcast-rcon-to-ops=true
|
||||
difficulty=easy
|
||||
enable-command-block=true
|
||||
enable-jmx-monitoring=false
|
||||
enable-query=false
|
||||
enable-rcon=false
|
||||
enable-status=true
|
||||
enforce-secure-profile=true
|
||||
enforce-whitelist=false
|
||||
entity-broadcast-range-percentage=100
|
||||
force-gamemode=false
|
||||
function-permission-level=2
|
||||
gamemode=survival
|
||||
generate-structures=true
|
||||
generator-settings={}
|
||||
hardcore=false
|
||||
hide-online-players=false
|
||||
initial-disabled-packs=
|
||||
initial-enabled-packs=vanilla,fabric
|
||||
level-name=world
|
||||
level-seed=
|
||||
level-type=minecraft\:normal
|
||||
max-chained-neighbor-updates=1000000
|
||||
max-players=20
|
||||
max-tick-time=60000
|
||||
max-world-size=29999984
|
||||
motd=§6chipi §edev §7server\n§8local test instance
|
||||
network-compression-threshold=256
|
||||
online-mode=false
|
||||
op-permission-level=4
|
||||
player-idle-timeout=0
|
||||
prevent-proxy-connections=false
|
||||
pvp=true
|
||||
query.port=25565
|
||||
rate-limit=0
|
||||
rcon.password=
|
||||
rcon.port=25575
|
||||
require-resource-pack=false
|
||||
resource-pack=
|
||||
resource-pack-prompt=
|
||||
resource-pack-sha1=
|
||||
server-ip=
|
||||
server-port=25565
|
||||
simulation-distance=10
|
||||
spawn-animals=true
|
||||
spawn-monsters=true
|
||||
spawn-npcs=true
|
||||
spawn-protection=16
|
||||
sync-chunk-writes=true
|
||||
text-filtering-config=
|
||||
use-native-transport=true
|
||||
view-distance=10
|
||||
white-list=false
|
||||
BIN
config/servers.dat
Normal file
1
gradle.properties
Normal file
@ -0,0 +1 @@
|
||||
org.gradle.configuration-cache=false
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
networkTimeout=10000
|
||||
networkTimeout=600000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@ -1,20 +1,23 @@
|
||||
package net.Chipperfluff.chipi;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
|
||||
|
||||
import net.Chipperfluff.chipi.advancement.ModCriteria;
|
||||
import net.Chipperfluff.chipi.block.ModBlocks;
|
||||
import net.Chipperfluff.chipi.command.CommandHandler;
|
||||
import net.Chipperfluff.chipi.effect.ChipiBlessingEvents;
|
||||
import net.Chipperfluff.chipi.effect.ChipiHungerHandler;
|
||||
import net.Chipperfluff.chipi.effect.ModEffects;
|
||||
import net.Chipperfluff.chipi.entity.ModEntities;
|
||||
import net.Chipperfluff.chipi.entity.SpawnLogic;
|
||||
import net.Chipperfluff.chipi.entity.MepEntity;
|
||||
import net.Chipperfluff.chipi.entity.ModEntities;
|
||||
import net.Chipperfluff.chipi.entity.PlayerJrEntity;
|
||||
import net.Chipperfluff.chipi.entity.SpawnLogic;
|
||||
import net.Chipperfluff.chipi.item.ModItemGroups;
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
import net.Chipperfluff.chipi.item.music.ModMusicDiscs;
|
||||
import net.Chipperfluff.chipi.server.ChipiServerEvents;
|
||||
import net.Chipperfluff.chipi.sound.ModSounds;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
|
||||
import net.Chipperfluff.chipi.util.TickScheduler;
|
||||
|
||||
public class ChipiMod implements ModInitializer {
|
||||
@ -35,12 +38,15 @@ public class ChipiMod implements ModInitializer {
|
||||
SpawnLogic.register();
|
||||
|
||||
ModSounds.register();
|
||||
ModMusicDiscs.registerAll();
|
||||
|
||||
TickScheduler.init();
|
||||
CommandHandler.register();
|
||||
|
||||
FabricDefaultAttributeRegistry.register(ModEntities.MEP, MepEntity.createMepAttributes());
|
||||
|
||||
FabricDefaultAttributeRegistry.register(ModEntities.PLAYER_JR, PlayerJrEntity.createAttributes());
|
||||
|
||||
ChipiServerEvents.register();
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,14 +5,9 @@ import net.minecraft.advancement.criterion.Criteria;
|
||||
public class ModCriteria {
|
||||
|
||||
public static final PortalActivatedTrigger PORTAL_ACTIVATED = Criteria.register(new PortalActivatedTrigger());
|
||||
|
||||
public static final PortalDestroyedTrigger PORTAL_DESTROYED = Criteria.register(new PortalDestroyedTrigger());
|
||||
|
||||
public static final VoidConsumedTrigger VOID_CONSUMED_TRIGGER = Criteria.register(new VoidConsumedTrigger());
|
||||
|
||||
public static final VoidConsumedFireTrigger VOID_CONSUMED_FIRE_TRIGGER = Criteria.register(new VoidConsumedFireTrigger());
|
||||
|
||||
public static void register() {
|
||||
// classload trigger
|
||||
}
|
||||
public static void register() {}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package net.Chipperfluff.chipi.block;
|
||||
|
||||
import net.Chipperfluff.chipi.advancement.ModCriteria;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.PillarBlock;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
@ -9,6 +8,8 @@ import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.Chipperfluff.chipi.advancement.ModCriteria;
|
||||
|
||||
public class ChipperFrameBlock extends PillarBlock {
|
||||
|
||||
public ChipperFrameBlock(Settings settings) {
|
||||
|
||||
@ -15,7 +15,6 @@ import net.minecraft.util.shape.VoxelShape;
|
||||
import net.minecraft.util.shape.VoxelShapes;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class ChipperPortalBlock extends Block {
|
||||
@ -71,7 +70,6 @@ public class ChipperPortalBlock extends Block {
|
||||
player.setOnGround(true);
|
||||
}
|
||||
|
||||
|
||||
public static BlockPos resolveSafeSpawn(ServerWorld targetWorld) {
|
||||
BlockPos spawn = DEFAULT_SPAWN;
|
||||
BlockPos under = spawn.down();
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package net.Chipperfluff.chipi.block;
|
||||
|
||||
import net.Chipperfluff.chipi.advancement.ModCriteria;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
@ -8,6 +7,8 @@ import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.Chipperfluff.chipi.advancement.ModCriteria;
|
||||
|
||||
public class ChipperPortalShape {
|
||||
|
||||
private final World world;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package net.Chipperfluff.chipi.block;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
@ -11,6 +10,8 @@ import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
|
||||
public class ModBlocks {
|
||||
|
||||
public static final Block VOID_BLOCK = Registry.register(
|
||||
@ -52,5 +53,16 @@ public class ModBlocks {
|
||||
new Block(AbstractBlock.Settings.copy(Blocks.IRON_BLOCK).requiresTool())
|
||||
);
|
||||
|
||||
public static final Block JINGLE_BLOCK = Registry.register(
|
||||
Registries.BLOCK,
|
||||
new Identifier(ChipiMod.MOD_ID, "jingle_block"),
|
||||
new Block(
|
||||
AbstractBlock.Settings.create()
|
||||
.strength(2.0f)
|
||||
.mapColor(MapColor.RED)
|
||||
.requiresTool()
|
||||
)
|
||||
);
|
||||
|
||||
public static void register() {}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package net.Chipperfluff.chipi.block;
|
||||
|
||||
import net.Chipperfluff.chipi.advancement.ModCriteria;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
@ -17,6 +16,8 @@ import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.Chipperfluff.chipi.advancement.ModCriteria;
|
||||
|
||||
public class VoidBlock extends Block {
|
||||
|
||||
public VoidBlock(Settings settings) {
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
package net.Chipperfluff.chipi.client;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
|
||||
import net.Chipperfluff.chipi.block.ModBlocks;
|
||||
import net.Chipperfluff.chipi.client.entity.ModEntityRenderers;
|
||||
import net.Chipperfluff.chipi.client.hud.ChipiStatusBar;
|
||||
import net.Chipperfluff.chipi.util.ClientTickScheduler;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
|
||||
public class ChipiClient implements ClientModInitializer {
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
package net.Chipperfluff.chipi.client;
|
||||
|
||||
import net.Chipperfluff.chipi.block.ModBlocks;
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.Chipperfluff.chipi.block.ModBlocks;
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
|
||||
public final class ModTooltips {
|
||||
|
||||
private ModTooltips() {
|
||||
}
|
||||
private ModTooltips() {}
|
||||
|
||||
public static void register() {
|
||||
|
||||
@ -30,10 +30,10 @@ public final class ModTooltips {
|
||||
if (stack.isOf(ModBlocks.CHIPPER_ALLOY_BLOCK.asItem()))
|
||||
lines.add(Text.translatable("tooltip.chipi.chipper_alloy_block"));
|
||||
|
||||
// ===== ITEMS =====
|
||||
if (stack.isOf(ModItems.NUT))
|
||||
lines.add(Text.translatable("tooltip.chipi.nut"));
|
||||
if (stack.isOf(ModBlocks.JINGLE_BLOCK.asItem()))
|
||||
lines.add(Text.translatable("tooltip.chipi.jingle_block"));
|
||||
|
||||
// ===== ITEMS =====
|
||||
if (stack.isOf(ModItems.RAW_CHIPPER_ORE))
|
||||
lines.add(Text.translatable("tooltip.chipi.raw_chipper_ore"));
|
||||
|
||||
@ -46,6 +46,16 @@ public final class ModTooltips {
|
||||
if (stack.isOf(ModItems.MEP_SPAWN_EGG))
|
||||
lines.add(Text.translatable("tooltip.chipi.mep_spawn_egg"));
|
||||
|
||||
// ===== FOOD =====
|
||||
if (stack.isOf(ModItems.NUT))
|
||||
lines.add(Text.translatable("tooltip.chipi.nut"));
|
||||
|
||||
if (stack.isOf(ModItems.MEP_MILK))
|
||||
lines.add(Text.translatable("tooltip.chipi.mep_milk"));
|
||||
|
||||
if (stack.isOf(ModItems.PLAYER_MILK))
|
||||
lines.add(Text.translatable("tooltip.chipi.player_milk"));
|
||||
|
||||
// ===== ARMOR =====
|
||||
if (stack.isOf(ModItems.CHIPPER_HELMET))
|
||||
lines.add(Text.translatable("tooltip.chipi.chipper_helmet"));
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
package net.Chipperfluff.chipi.client.entity;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
import net.Chipperfluff.chipi.entity.MepEntity;
|
||||
import net.minecraft.client.render.entity.BipedEntityRenderer;
|
||||
import net.minecraft.client.render.entity.EntityRendererFactory;
|
||||
import net.minecraft.client.render.entity.model.BipedEntityModel;
|
||||
import net.minecraft.client.render.entity.model.EntityModelLayers;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
import net.Chipperfluff.chipi.entity.MepEntity;
|
||||
|
||||
public class MepRenderer extends BipedEntityRenderer<MepEntity, BipedEntityModel<MepEntity>> {
|
||||
|
||||
private static final Identifier TEXTURE = new Identifier(ChipiMod.MOD_ID, "textures/entity/mep.png");
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
package net.Chipperfluff.chipi.client.entity;
|
||||
|
||||
import net.Chipperfluff.chipi.entity.ModEntities;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
|
||||
|
||||
import net.Chipperfluff.chipi.entity.ModEntities;
|
||||
|
||||
public class ModEntityRenderers {
|
||||
|
||||
public static void register() {
|
||||
EntityRendererRegistry.register(ModEntities.MEP, MepRenderer::new);
|
||||
EntityRendererRegistry.register(ModEntities.PLAYER_JR, PlayerJrRenderer::new);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
package net.Chipperfluff.chipi.client.entity;
|
||||
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.entity.BipedEntityRenderer;
|
||||
import net.minecraft.client.render.entity.EntityRendererFactory;
|
||||
import net.minecraft.client.render.entity.model.BipedEntityModel;
|
||||
import net.minecraft.client.render.entity.model.EntityModelLayers;
|
||||
import net.minecraft.client.util.DefaultSkinHelper;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.Chipperfluff.chipi.entity.PlayerJrEntity;
|
||||
|
||||
public class PlayerJrRenderer
|
||||
extends BipedEntityRenderer<PlayerJrEntity, BipedEntityModel<PlayerJrEntity>> {
|
||||
|
||||
public PlayerJrRenderer(EntityRendererFactory.Context ctx) {
|
||||
super(ctx, new BipedEntityModel<>(ctx.getPart(EntityModelLayers.PLAYER)), 0.3f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
PlayerJrEntity entity,
|
||||
float yaw,
|
||||
float tickDelta,
|
||||
MatrixStack matrices,
|
||||
VertexConsumerProvider vertices,
|
||||
int light
|
||||
) {
|
||||
matrices.scale(0.5f, 0.5f, 0.5f);
|
||||
super.render(entity, yaw, tickDelta, matrices, vertices, light);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getTexture(PlayerJrEntity entity) {
|
||||
String dadName = entity.getDadName();
|
||||
|
||||
if (dadName == null || dadName.isBlank()) {
|
||||
return DefaultSkinHelper.getTexture();
|
||||
}
|
||||
|
||||
/*
|
||||
* THIS is how vanilla + mods do it:
|
||||
* - stable Identifier
|
||||
* - async skin download
|
||||
* - cached by SkinProvider
|
||||
*/
|
||||
Identifier skin = AbstractClientPlayerEntity.getSkinId(dadName);
|
||||
AbstractClientPlayerEntity.loadSkin(skin, dadName);
|
||||
|
||||
return skin;
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,13 @@
|
||||
package net.Chipperfluff.chipi.client.hud;
|
||||
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
|
||||
import static net.Chipperfluff.chipi.util.ChipiTrackedData.CHIPI_ENERGY;
|
||||
|
||||
public class ChipiStatusBar {
|
||||
|
||||
@ -4,8 +4,6 @@ import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.struct.ChipiStructures;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.argument.BlockPosArgumentType;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
@ -14,6 +12,8 @@ import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.struct.ChipiStructures;
|
||||
|
||||
public class ChpCommand {
|
||||
|
||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
|
||||
|
||||
@ -12,6 +12,7 @@ public final class CommandHandler {
|
||||
(dispatcher, registryAccess, environment) -> {
|
||||
ChpCommand.register(dispatcher);
|
||||
CspCommand.register(dispatcher);
|
||||
SpawnJrCommand.register(dispatcher);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -3,8 +3,6 @@ package net.Chipperfluff.chipi.command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.struct.ChipiStructures;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.command.argument.BlockPosArgumentType;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
@ -13,6 +11,8 @@ import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.struct.ChipiStructures;
|
||||
|
||||
public class CspCommand {
|
||||
|
||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
package net.Chipperfluff.chipi.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.command.argument.EntityArgumentType;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import net.Chipperfluff.chipi.entity.ModEntities;
|
||||
import net.Chipperfluff.chipi.entity.PlayerJrEntity;
|
||||
|
||||
public final class SpawnJrCommand {
|
||||
|
||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
CommandManager.literal("spawnjr")
|
||||
.requires(src -> src.hasPermissionLevel(2))
|
||||
.then(
|
||||
CommandManager.argument("dad", EntityArgumentType.player())
|
||||
.executes(SpawnJrCommand::execute)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static int execute(CommandContext<ServerCommandSource> ctx) {
|
||||
ServerCommandSource source = ctx.getSource();
|
||||
|
||||
System.out.println("[spawnjr] ================================");
|
||||
System.out.println("[spawnjr] Command invoked");
|
||||
|
||||
try {
|
||||
ServerWorld world = source.getWorld();
|
||||
ServerPlayerEntity dad = EntityArgumentType.getPlayer(ctx, "dad");
|
||||
ServerPlayerEntity spawner = source.getPlayerOrThrow();
|
||||
|
||||
BlockPos pos = spawner.getBlockPos();
|
||||
|
||||
System.out.println("[spawnjr] Dad = " + dad.getName().getString());
|
||||
System.out.println("[spawnjr] Dad UUID = " + dad.getUuidAsString());
|
||||
System.out.println("[spawnjr] World = " + world.getRegistryKey().getValue());
|
||||
System.out.println("[spawnjr] Spawn pos = " + pos);
|
||||
|
||||
PlayerJrEntity jr = new PlayerJrEntity(ModEntities.PLAYER_JR, world);
|
||||
System.out.println("[spawnjr] Entity constructed");
|
||||
|
||||
jr.refreshPositionAndAngles(
|
||||
pos.getX() + 0.5,
|
||||
pos.getY(),
|
||||
pos.getZ() + 0.5,
|
||||
world.random.nextFloat() * 360f,
|
||||
0f
|
||||
);
|
||||
|
||||
// single source of truth
|
||||
jr.setDad(dad);
|
||||
System.out.println("[spawnjr] Dad relationship set");
|
||||
|
||||
boolean spawned = world.spawnEntity(jr);
|
||||
System.out.println("[spawnjr] spawnEntity() returned = " + spawned);
|
||||
|
||||
if (!spawned) {
|
||||
source.sendError(Text.literal("[spawnjr] Spawn failed (entity rejected by world)"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
System.out.println("[spawnjr] SUCCESS");
|
||||
System.out.println("[spawnjr] ================================");
|
||||
return 1;
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("[spawnjr] ================================");
|
||||
System.out.println("[spawnjr] CRASH");
|
||||
System.out.println("[spawnjr] hey message Chipperfluff");
|
||||
System.out.println("[spawnjr] Exception: " + e.getClass().getName());
|
||||
System.out.println("[spawnjr] Message: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
|
||||
source.sendError(Text.literal(
|
||||
"[spawnjr] Internal error. Check logs. (hey message Chipperfluff)"
|
||||
));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,16 +1,28 @@
|
||||
package net.Chipperfluff.chipi.effect;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
import net.minecraft.entity.effect.StatusEffect;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
|
||||
public class ModEffects {
|
||||
|
||||
public static final StatusEffect CHIPI_BLESSING = new ChipiBlessingEffect();
|
||||
public static final StatusEffect PREGNANT = new PregnantEffect();
|
||||
|
||||
public static void register() {
|
||||
Registry.register(Registries.STATUS_EFFECT, new Identifier(ChipiMod.MOD_ID, "chipi_blessing"), CHIPI_BLESSING);
|
||||
Registry.register(
|
||||
Registries.STATUS_EFFECT,
|
||||
new Identifier(ChipiMod.MOD_ID, "chipi_blessing"),
|
||||
CHIPI_BLESSING
|
||||
);
|
||||
|
||||
Registry.register(
|
||||
Registries.STATUS_EFFECT,
|
||||
new Identifier(ChipiMod.MOD_ID, "pregnant"),
|
||||
PREGNANT
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
127
src/main/java/net/Chipperfluff/chipi/effect/PregnantEffect.java
Normal file
@ -0,0 +1,127 @@
|
||||
package net.Chipperfluff.chipi.effect;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.attribute.EntityAttributeInstance;
|
||||
import net.minecraft.entity.attribute.EntityAttributes;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
import net.minecraft.entity.effect.StatusEffect;
|
||||
import net.minecraft.entity.effect.StatusEffectCategory;
|
||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import java.util.UUID;
|
||||
|
||||
import net.Chipperfluff.chipi.entity.ModEntities;
|
||||
import net.Chipperfluff.chipi.entity.PlayerJrEntity;
|
||||
|
||||
public class PregnantEffect extends StatusEffect {
|
||||
|
||||
public static final int TOTAL_DURATION = 20 * 60 * 10; // 10 min
|
||||
private static final double MAX_SLOW = 0.90;
|
||||
|
||||
private static final UUID SPEED_UUID =
|
||||
UUID.fromString("7c8b6b8f-4b6c-4f6f-9b7b-01c8e9f8a111");
|
||||
|
||||
public PregnantEffect() {
|
||||
super(StatusEffectCategory.HARMFUL, 0xFFB6C1);
|
||||
}
|
||||
|
||||
/* ---------- helpers used by mixin ---------- */
|
||||
|
||||
/** 0.0 → normal jump, 1.0 → no jump */
|
||||
public static double getJumpClamp(ServerPlayerEntity player) {
|
||||
StatusEffectInstance inst = player.getStatusEffect(ModEffects.PREGNANT);
|
||||
if (inst == null) return 0.0;
|
||||
|
||||
double progress =
|
||||
1.0 - (inst.getDuration() / (double) TOTAL_DURATION);
|
||||
|
||||
return Math.min(Math.max(progress, 0.0), 1.0);
|
||||
}
|
||||
|
||||
/* ---------- ticking ---------- */
|
||||
|
||||
@Override
|
||||
public boolean canApplyUpdateEffect(int duration, int amplifier) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyUpdateEffect(LivingEntity entity, int amplifier) {
|
||||
if (!(entity instanceof ServerPlayerEntity player)) return;
|
||||
|
||||
StatusEffectInstance inst = player.getStatusEffect(this);
|
||||
if (inst == null) return;
|
||||
|
||||
int remaining = inst.getDuration();
|
||||
|
||||
double progress =
|
||||
1.0 - (remaining / (double) TOTAL_DURATION);
|
||||
|
||||
progress = Math.min(Math.max(progress, 0.0), 1.0);
|
||||
|
||||
applySpeedModifier(player, progress * MAX_SLOW);
|
||||
|
||||
if (remaining % 400 == 0 && remaining > 20) {
|
||||
player.sendMessage(
|
||||
Text.literal("Your knees file a formal complaint…"),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
if (remaining == 1) {
|
||||
finishBirth(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void applySpeedModifier(ServerPlayerEntity player, double slowAmount) {
|
||||
EntityAttributeInstance attr =
|
||||
player.getAttributeInstance(EntityAttributes.GENERIC_MOVEMENT_SPEED);
|
||||
|
||||
if (attr == null) return;
|
||||
|
||||
EntityAttributeModifier old = attr.getModifier(SPEED_UUID);
|
||||
if (old != null) attr.removeModifier(old);
|
||||
|
||||
if (slowAmount > 0.01) {
|
||||
attr.addTemporaryModifier(new EntityAttributeModifier(
|
||||
SPEED_UUID,
|
||||
"Pregnancy slowdown",
|
||||
-slowAmount,
|
||||
EntityAttributeModifier.Operation.MULTIPLY_TOTAL
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private void finishBirth(ServerPlayerEntity dad) {
|
||||
// cleanup
|
||||
EntityAttributeInstance attr =
|
||||
dad.getAttributeInstance(EntityAttributes.GENERIC_MOVEMENT_SPEED);
|
||||
if (attr != null) {
|
||||
EntityAttributeModifier old = attr.getModifier(SPEED_UUID);
|
||||
if (old != null) attr.removeModifier(old);
|
||||
}
|
||||
|
||||
dad.removeStatusEffect(this);
|
||||
|
||||
PlayerJrEntity jr = ModEntities.PLAYER_JR.create(dad.getWorld());
|
||||
if (jr == null) return;
|
||||
|
||||
jr.refreshPositionAndAngles(
|
||||
dad.getX(), dad.getY(), dad.getZ(),
|
||||
dad.getYaw(), dad.getPitch()
|
||||
);
|
||||
|
||||
jr.setDad(dad);
|
||||
dad.getWorld().spawnEntity(jr);
|
||||
|
||||
dad.sendMessage(
|
||||
Text.literal(
|
||||
"You're a dad now. The name’s " +
|
||||
jr.getName().getString() +
|
||||
". Warning: it might cheat."
|
||||
),
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@ package net.Chipperfluff.chipi.entity;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.SlabBlock;
|
||||
import net.minecraft.block.StairsBlock;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.goal.*;
|
||||
@ -81,7 +82,7 @@ public class MepEntity extends PathAwareEntity {
|
||||
// === ATTACK OVERRIDE (AURA IMMUNITY) ===
|
||||
|
||||
@Override
|
||||
public boolean tryAttack(net.minecraft.entity.Entity target) {
|
||||
public boolean tryAttack(Entity target) {
|
||||
if (target instanceof PlayerEntity player) {
|
||||
if (ProtectionAuraHandler.hasAura(player)) {
|
||||
return false; // chase but never hit
|
||||
|
||||
@ -1,12 +1,9 @@
|
||||
package net.Chipperfluff.chipi.entity;
|
||||
|
||||
import net.Chipperfluff.chipi.entity.MepEntity;
|
||||
|
||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
|
||||
|
||||
import net.minecraft.entity.EntityDimensions;
|
||||
import net.minecraft.entity.SpawnGroup;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.SpawnGroup;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.util.Identifier;
|
||||
@ -23,6 +20,15 @@ public final class ModEntities {
|
||||
.build()
|
||||
);
|
||||
|
||||
private ModEntities() {
|
||||
}
|
||||
public static final EntityType<PlayerJrEntity> PLAYER_JR =
|
||||
Registry.register(
|
||||
Registries.ENTITY_TYPE,
|
||||
new Identifier("chipi", "player_jr"),
|
||||
FabricEntityTypeBuilder
|
||||
.create(SpawnGroup.CREATURE, PlayerJrEntity::new)
|
||||
.dimensions(EntityDimensions.fixed(0.45f, 0.9f)) // small
|
||||
.build()
|
||||
);
|
||||
|
||||
private ModEntities() {}
|
||||
}
|
||||
|
||||
388
src/main/java/net/Chipperfluff/chipi/entity/PlayerJrEntity.java
Normal file
@ -0,0 +1,388 @@
|
||||
package net.Chipperfluff.chipi.entity;
|
||||
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
import net.minecraft.entity.ai.goal.LookAroundGoal;
|
||||
import net.minecraft.entity.ai.goal.LookAtEntityGoal;
|
||||
import net.minecraft.entity.ai.goal.SwimGoal;
|
||||
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
||||
import net.minecraft.entity.attribute.EntityAttributes;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.entity.mob.PathAwareEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerJrEntity extends PathAwareEntity {
|
||||
|
||||
/* ================= RULES (CHEATING FRIEND) ================= */
|
||||
|
||||
private static final double FORCE_FLY_DISTANCE = 50.0; // fly if farther than this (horizontal)
|
||||
private static final int STUCK_TICKS_TO_FLY = 40; // 2 seconds of no horizontal progress
|
||||
private static final double STUCK_MIN_CLOSING = 0.10; // horizontal progress threshold
|
||||
private static final double STUCK_MIN_DISTANCE = 6.0; // don't care if already close
|
||||
private static final double DAD_MOVING_EPS_SQ = 0.02; // if dad is moving, don't call it stuck
|
||||
|
||||
private static final int LAND_RADIUS = 6; // search dry landing within this radius
|
||||
private static final double LAND_HORIZONTAL_DISTANCE = 2.0; // must be this close (horiz) to land
|
||||
private static final double HOVER_HEIGHT = 1.25; // hover above landing block
|
||||
private static final int MIN_FLY_TICKS = 20; // must fly at least this long
|
||||
|
||||
private static final double FLY_SPEED = 0.55;
|
||||
private static final double FLY_ACCEL = 0.25;
|
||||
private static final int MAX_VERTICAL_GAP = 6; // if dad is this high above -> fly
|
||||
|
||||
/* ================= STATE ================= */
|
||||
|
||||
private UUID dadUuid;
|
||||
private String dadName = "";
|
||||
|
||||
private enum Mode { GROUND, FLYING }
|
||||
private Mode mode = Mode.GROUND;
|
||||
|
||||
private int flyTicks = 0;
|
||||
|
||||
// Stuck tracking (ground)
|
||||
private int stuckTicks = 0;
|
||||
private double lastDadHorizDist = -1;
|
||||
|
||||
// Landing / hover state
|
||||
private BlockPos landingSpot = null;
|
||||
private BlockPos forcedLandingSpot = null;
|
||||
|
||||
/* ================= CONSTRUCTOR ================= */
|
||||
|
||||
public PlayerJrEntity(EntityType<? extends PathAwareEntity> type, World world) {
|
||||
super(type, world);
|
||||
}
|
||||
|
||||
public static DefaultAttributeContainer.Builder createAttributes() {
|
||||
return MobEntity.createMobAttributes()
|
||||
.add(EntityAttributes.GENERIC_MAX_HEALTH, 10.0)
|
||||
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25)
|
||||
.add(EntityAttributes.GENERIC_FOLLOW_RANGE, 64.0);
|
||||
}
|
||||
|
||||
/* ================= DAD ================= */
|
||||
|
||||
public void setDad(ServerPlayerEntity dad) {
|
||||
dadUuid = dad.getUuid();
|
||||
dadName = dad.getGameProfile().getName();
|
||||
setCustomName(Text.literal(dadName + " jr."));
|
||||
setCustomNameVisible(true);
|
||||
}
|
||||
|
||||
private ServerPlayerEntity getDad() {
|
||||
if (dadUuid == null || getWorld().isClient) return null;
|
||||
return getWorld().getServer().getPlayerManager().getPlayer(dadUuid);
|
||||
}
|
||||
|
||||
public String getDadName() { return dadName; }
|
||||
|
||||
/* ================= AI ================= */
|
||||
|
||||
@Override
|
||||
protected void initGoals() {
|
||||
goalSelector.add(1, new SwimGoal(this));
|
||||
goalSelector.add(2, new FollowDadGoal(this));
|
||||
goalSelector.add(3, new LookAtEntityGoal(this, PlayerEntity.class, 6f));
|
||||
goalSelector.add(4, new LookAroundGoal(this));
|
||||
}
|
||||
|
||||
/* ================= TICK ================= */
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if (getWorld().isClient) return;
|
||||
|
||||
// Never fall damage ever (you asked this specifically)
|
||||
this.fallDistance = 0.0f;
|
||||
|
||||
ServerPlayerEntity dad = getDad();
|
||||
if (dad == null) return;
|
||||
|
||||
switch (mode) {
|
||||
case GROUND -> doGroundBrain(dad);
|
||||
case FLYING -> doFlyingBrain(dad);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================= CORE BRAIN: GROUND ================= */
|
||||
|
||||
private void doGroundBrain(ServerPlayerEntity dad) {
|
||||
// Water cheat: if land is nearby, prefer walking out; if no path, fly briefly to land.
|
||||
if (this.isTouchingWater()) {
|
||||
BlockPos escape = findLandingSpotNear(this.getBlockPos(), LAND_RADIUS);
|
||||
if (escape != null) {
|
||||
boolean canWalk = getNavigation().startMovingTo(
|
||||
escape.getX() + 0.5,
|
||||
escape.getY(),
|
||||
escape.getZ() + 0.5,
|
||||
1.1
|
||||
);
|
||||
if (canWalk) {
|
||||
resetStuckTracking(dad);
|
||||
return;
|
||||
}
|
||||
forcedLandingSpot = escape;
|
||||
startFlying(dad);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update stuck tracking (only on ground mode)
|
||||
updateStuckTracking(dad);
|
||||
if (stuckTicks >= STUCK_TICKS_TO_FLY) {
|
||||
startFlying(dad);
|
||||
return;
|
||||
}
|
||||
|
||||
// Too far behind (impatient cheat)
|
||||
if (horizontalDistanceTo(dad) > FORCE_FLY_DISTANCE) {
|
||||
startFlying(dad);
|
||||
return;
|
||||
}
|
||||
|
||||
// Dad is way above us (can't reach)
|
||||
double dy = dad.getY() - getY();
|
||||
if (dy > MAX_VERTICAL_GAP && horizontalDistanceTo(dad) > 2.0) {
|
||||
startFlying(dad);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStuckTracking(ServerPlayerEntity dad) {
|
||||
boolean tryingToWalk = !getNavigation().isIdle();
|
||||
double dadDist = horizontalDistanceTo(dad);
|
||||
double dadSpeedSq = dad.getVelocity().horizontalLengthSquared();
|
||||
|
||||
if (!tryingToWalk || dadDist <= STUCK_MIN_DISTANCE || dadSpeedSq > DAD_MOVING_EPS_SQ) {
|
||||
stuckTicks = 0;
|
||||
lastDadHorizDist = dadDist;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastDadHorizDist < 0) {
|
||||
lastDadHorizDist = dadDist;
|
||||
stuckTicks = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
double closing = lastDadHorizDist - dadDist; // positive means getting closer
|
||||
if (closing < STUCK_MIN_CLOSING) stuckTicks++;
|
||||
else stuckTicks = 0;
|
||||
|
||||
lastDadHorizDist = dadDist;
|
||||
}
|
||||
|
||||
private void resetStuckTracking(ServerPlayerEntity dad) {
|
||||
stuckTicks = 0;
|
||||
lastDadHorizDist = horizontalDistanceTo(dad);
|
||||
}
|
||||
|
||||
/* ================= CORE BRAIN: FLYING ================= */
|
||||
|
||||
private void startFlying(ServerPlayerEntity dad) {
|
||||
mode = Mode.FLYING;
|
||||
flyTicks = 0;
|
||||
|
||||
landingSpot = null;
|
||||
|
||||
setNoGravity(true);
|
||||
getNavigation().stop();
|
||||
setVelocity(Vec3d.ZERO);
|
||||
velocityDirty = true;
|
||||
|
||||
dad.sendMessage(Text.literal(getName().getString() + " switched to Game Mode Creative"), false);
|
||||
}
|
||||
|
||||
private void doFlyingBrain(ServerPlayerEntity dad) {
|
||||
flyTicks++;
|
||||
|
||||
double horiz = horizontalDistanceTo(dad);
|
||||
|
||||
if (flyTicks >= MIN_FLY_TICKS) {
|
||||
BlockPos candidate = forcedLandingSpot;
|
||||
if (candidate == null) {
|
||||
candidate = findLandingSpotNear(dad.getBlockPos(), LAND_RADIUS);
|
||||
}
|
||||
if (candidate != null && !wouldImmediatelyRefly(dad, candidate)) {
|
||||
landingSpot = candidate;
|
||||
if (horizontalDistanceTo(landingSpot) <= LAND_HORIZONTAL_DISTANCE) {
|
||||
stopFlying(dad);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BlockPos targetSpot = forcedLandingSpot != null ? forcedLandingSpot : landingSpot;
|
||||
Vec3d target = targetSpot != null
|
||||
? Vec3d.ofCenter(targetSpot).add(0, HOVER_HEIGHT, 0)
|
||||
: dad.getPos().add(0, 2.2, 0);
|
||||
|
||||
flyTowardSmooth(target);
|
||||
lookAtEntity(dad, 30f, 30f);
|
||||
}
|
||||
private void stopFlying(ServerPlayerEntity dad) {
|
||||
setNoGravity(false);
|
||||
mode = Mode.GROUND;
|
||||
|
||||
landingSpot = null;
|
||||
forcedLandingSpot = null;
|
||||
|
||||
dad.sendMessage(Text.literal(getName().getString() + " switched to Game Mode Survival"), false);
|
||||
}
|
||||
|
||||
/* ================= MOVEMENT HELPERS ================= */
|
||||
|
||||
private void flyTowardSmooth(Vec3d target) {
|
||||
Vec3d delta = target.subtract(getPos());
|
||||
double distSq = delta.lengthSquared();
|
||||
if (distSq < 0.0006) {
|
||||
setVelocity(getVelocity().multiply(0.6));
|
||||
velocityDirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3d desired = delta.normalize().multiply(FLY_SPEED);
|
||||
|
||||
// stronger steer when far (prevents drifting)
|
||||
double accel = (distSq > 64.0) ? Math.min(0.55, FLY_ACCEL * 2.0) : FLY_ACCEL;
|
||||
|
||||
Vec3d blended = getVelocity().multiply(1.0 - accel).add(desired.multiply(accel));
|
||||
setVelocity(blended);
|
||||
velocityDirty = true;
|
||||
}
|
||||
|
||||
private double horizontalDistanceTo(ServerPlayerEntity dad) {
|
||||
double dx = dad.getX() - getX();
|
||||
double dz = dad.getZ() - getZ();
|
||||
return Math.sqrt(dx * dx + dz * dz);
|
||||
}
|
||||
|
||||
private double horizontalDistanceTo(BlockPos pos) {
|
||||
double dx = pos.getX() + 0.5 - getX();
|
||||
double dz = pos.getZ() + 0.5 - getZ();
|
||||
return Math.sqrt(dx * dx + dz * dz);
|
||||
}
|
||||
|
||||
/* ================= LAND SEARCH (DRY + SAFE) ================= */
|
||||
|
||||
private BlockPos findLandingSpotNear(BlockPos center, int radius) {
|
||||
BlockPos best = null;
|
||||
double bestScore = Double.MAX_VALUE;
|
||||
|
||||
int minY = center.getY() - 3;
|
||||
int maxY = center.getY() + 3;
|
||||
|
||||
for (int dx = -radius; dx <= radius; dx++) {
|
||||
for (int dz = -radius; dz <= radius; dz++) {
|
||||
if ((dx * dx + dz * dz) > radius * radius) continue;
|
||||
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
BlockPos p = new BlockPos(center.getX() + dx, y, center.getZ() + dz);
|
||||
if (!canStandAt(p)) continue;
|
||||
|
||||
// prefer closer to dad AND closer to us a bit
|
||||
double toCenter = p.getSquaredDistance(center);
|
||||
double toMe = this.getPos().squaredDistanceTo(Vec3d.ofCenter(p));
|
||||
double score = toCenter * 1.0 + toMe * 0.10;
|
||||
|
||||
if (score < bestScore) {
|
||||
bestScore = score;
|
||||
best = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
private boolean canStandAt(BlockPos pos) {
|
||||
World w = getWorld();
|
||||
|
||||
// feet + head air
|
||||
if (!w.getBlockState(pos).isAir()) return false;
|
||||
if (!w.getBlockState(pos.up()).isAir()) return false;
|
||||
|
||||
// solid below
|
||||
BlockPos below = pos.down();
|
||||
if (!w.getBlockState(below).isSolidBlock(w, below)) return false;
|
||||
|
||||
// not in fluid, not standing on fluid
|
||||
if (!w.getFluidState(pos).isEmpty()) return false;
|
||||
if (!w.getFluidState(below).isEmpty()) return false;
|
||||
|
||||
// also avoid lava blocks around feet area (simple “don’t be stupid”)
|
||||
// (fluid check already catches lava fluid; this catches blocks like magma? optional)
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean wouldImmediatelyRefly(ServerPlayerEntity dad, BlockPos landPos) {
|
||||
if (horizontalDistanceTo(dad) > FORCE_FLY_DISTANCE) return true;
|
||||
if (dad.getY() - landPos.getY() > MAX_VERTICAL_GAP) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ================= FALL DAMAGE ================= */
|
||||
|
||||
@Override
|
||||
public boolean handleFallDamage(float fallDistance, float damageMultiplier, DamageSource source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ================= SAVE / LOAD ================= */
|
||||
|
||||
@Override
|
||||
public void writeCustomDataToNbt(NbtCompound nbt) {
|
||||
if (dadUuid != null) nbt.putUuid("Dad", dadUuid);
|
||||
nbt.putString("DadName", dadName);
|
||||
nbt.putString("Mode", mode.name());
|
||||
nbt.putInt("FlyTicks", flyTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readCustomDataFromNbt(NbtCompound nbt) {
|
||||
if (nbt.containsUuid("Dad")) dadUuid = nbt.getUuid("Dad");
|
||||
if (nbt.contains("DadName")) dadName = nbt.getString("DadName");
|
||||
if (nbt.contains("Mode")) {
|
||||
mode = Mode.valueOf(nbt.getString("Mode"));
|
||||
setNoGravity(mode != Mode.GROUND);
|
||||
}
|
||||
if (nbt.contains("FlyTicks")) flyTicks = nbt.getInt("FlyTicks");
|
||||
|
||||
// volatile reset
|
||||
landingSpot = null;
|
||||
forcedLandingSpot = null;
|
||||
lastDadHorizDist = -1;
|
||||
stuckTicks = 0;
|
||||
}
|
||||
|
||||
/* ================= FOLLOW GOAL ================= */
|
||||
|
||||
static class FollowDadGoal extends Goal {
|
||||
private final PlayerJrEntity jr;
|
||||
FollowDadGoal(PlayerJrEntity jr) { this.jr = jr; }
|
||||
|
||||
@Override
|
||||
public boolean canStart() {
|
||||
return jr.mode == Mode.GROUND && jr.getDad() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
ServerPlayerEntity dad = jr.getDad();
|
||||
if (dad == null) return;
|
||||
|
||||
if (jr.squaredDistanceTo(dad) > 4) {
|
||||
jr.getNavigation().startMovingTo(dad, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,10 +2,10 @@ package net.Chipperfluff.chipi.entity;
|
||||
|
||||
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
|
||||
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.SpawnGroup;
|
||||
import net.minecraft.entity.SpawnReason;
|
||||
import net.minecraft.entity.SpawnRestriction;
|
||||
@ -13,14 +13,12 @@ import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.Heightmap;
|
||||
import net.minecraft.world.ServerWorldAccess;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.math.Box;
|
||||
|
||||
|
||||
public final class SpawnLogic {
|
||||
|
||||
@ -30,8 +28,7 @@ public final class SpawnLogic {
|
||||
private static final RegistryKey<Biome> VOID_BIOME =
|
||||
RegistryKey.of(RegistryKeys.BIOME, new Identifier("chipi", "void"));
|
||||
|
||||
private SpawnLogic() {
|
||||
}
|
||||
private SpawnLogic() {}
|
||||
|
||||
public static void register() {
|
||||
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
package net.Chipperfluff.chipi.item;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.UseAction;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
|
||||
import net.Chipperfluff.chipi.effect.ModEffects;
|
||||
|
||||
public class MepMilkItem extends Item {
|
||||
|
||||
@ -15,4 +15,9 @@ public class ModFoodComponents {
|
||||
new FoodComponent.Builder()
|
||||
.alwaysEdible()
|
||||
.build();
|
||||
|
||||
public static final FoodComponent PLAYER_MILK =
|
||||
new FoodComponent.Builder()
|
||||
.alwaysEdible()
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
package net.Chipperfluff.chipi.item;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
import net.Chipperfluff.chipi.block.ModBlocks;
|
||||
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@ -10,6 +8,10 @@ import net.minecraft.registry.Registry;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
import net.Chipperfluff.chipi.block.ModBlocks;
|
||||
import net.Chipperfluff.chipi.item.music.ModMusicDiscs;
|
||||
|
||||
public class ModItemGroups {
|
||||
|
||||
public static final ItemGroup CHIPI_GROUP = Registry.register(
|
||||
@ -25,6 +27,7 @@ public class ModItemGroups {
|
||||
entries.add(ModBlocks.CHIPPER_PORTAL);
|
||||
entries.add(ModBlocks.CHIPPER_ORE);
|
||||
entries.add(ModBlocks.CHIPPER_ALLOY_BLOCK);
|
||||
entries.add(ModBlocks.JINGLE_BLOCK);
|
||||
|
||||
// Items
|
||||
entries.add(ModItems.RAW_CHIPPER_ORE);
|
||||
@ -35,6 +38,7 @@ public class ModItemGroups {
|
||||
// Food
|
||||
entries.add(ModItems.MEP_MILK);
|
||||
entries.add(ModItems.NUT);
|
||||
entries.add(ModItems.PLAYER_MILK);
|
||||
|
||||
// Armor
|
||||
entries.add(ModItems.CHIPPER_HELMET);
|
||||
@ -49,11 +53,13 @@ public class ModItemGroups {
|
||||
entries.add(ModItems.CHIPPER_SHOVEL);
|
||||
entries.add(ModItems.CHIPPER_HOE);
|
||||
|
||||
// Music discs
|
||||
for (var disc : ModMusicDiscs.getAll().values()) {
|
||||
entries.add(disc);
|
||||
}
|
||||
})
|
||||
.build()
|
||||
);
|
||||
|
||||
public static void register() {
|
||||
// force class load
|
||||
}
|
||||
public static void register() {}
|
||||
}
|
||||
|
||||
@ -1,17 +1,16 @@
|
||||
package net.Chipperfluff.chipi.item;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
import net.Chipperfluff.chipi.block.ModBlocks;
|
||||
import net.Chipperfluff.chipi.entity.ModEntities;
|
||||
import net.Chipperfluff.chipi.item.armor.ChipperArmorMaterial;
|
||||
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
|
||||
import net.minecraft.item.*;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.Chipperfluff.chipi.item.tool.ChipperToolMaterial;
|
||||
import net.Chipperfluff.chipi.item.MepMilkItem;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
import net.Chipperfluff.chipi.block.ModBlocks;
|
||||
import net.Chipperfluff.chipi.entity.ModEntities;
|
||||
import net.Chipperfluff.chipi.item.armor.ChipperArmorMaterial;
|
||||
import net.Chipperfluff.chipi.item.tool.ChipperToolMaterial;
|
||||
|
||||
public class ModItems {
|
||||
|
||||
@ -47,6 +46,12 @@ public class ModItems {
|
||||
new BlockItem(ModBlocks.CHIPPER_ALLOY_BLOCK, new FabricItemSettings())
|
||||
);
|
||||
|
||||
public static final Item JINGLE_BLOCK = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(ChipiMod.MOD_ID, "jingle_block"),
|
||||
new BlockItem(ModBlocks.JINGLE_BLOCK, new FabricItemSettings())
|
||||
);
|
||||
|
||||
// ===== ENTITY ITEMS =====
|
||||
|
||||
public static final Item MEP_SPAWN_EGG = Registry.register(
|
||||
@ -89,6 +94,17 @@ public class ModItems {
|
||||
new MepMilkItem(new Item.Settings().maxCount(1).recipeRemainder(Items.BUCKET).food(ModFoodComponents.MEP_MILK))
|
||||
);
|
||||
|
||||
public static final Item PLAYER_MILK = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(ChipiMod.MOD_ID, "player_milk"),
|
||||
new PlayerMilkItem(
|
||||
new Item.Settings()
|
||||
.maxCount(1)
|
||||
.recipeRemainder(Items.BUCKET)
|
||||
.food(ModFoodComponents.PLAYER_MILK)
|
||||
)
|
||||
);
|
||||
|
||||
// ===== ARMOR =====
|
||||
|
||||
public static final Item CHIPPER_HELMET = Registry.register(
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
package net.Chipperfluff.chipi.item;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUsage;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.UseAction;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.Chipperfluff.chipi.effect.ModEffects;
|
||||
import net.Chipperfluff.chipi.sound.ModSounds;
|
||||
|
||||
public class PlayerMilkItem extends Item {
|
||||
|
||||
public PlayerMilkItem(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
/* ================= DENY DRINKING ================= */
|
||||
|
||||
@Override
|
||||
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
|
||||
ItemStack stack = user.getStackInHand(hand);
|
||||
|
||||
// Already pregnant → deny drinking
|
||||
if (user.hasStatusEffect(ModEffects.PREGNANT)) {
|
||||
if (!world.isClient) {
|
||||
user.sendMessage(
|
||||
Text.literal("You already feel something growing..."),
|
||||
true
|
||||
);
|
||||
}
|
||||
return TypedActionResult.fail(stack);
|
||||
}
|
||||
|
||||
// Start drinking normally
|
||||
user.setCurrentHand(hand);
|
||||
return TypedActionResult.consume(stack);
|
||||
}
|
||||
|
||||
/* ================= DRINK ANIMATION ================= */
|
||||
|
||||
@Override
|
||||
public UseAction getUseAction(ItemStack stack) {
|
||||
return UseAction.DRINK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxUseTime(ItemStack stack) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
/* ================= FINISH DRINK ================= */
|
||||
|
||||
@Override
|
||||
public ItemStack finishUsing(ItemStack stack, World world, LivingEntity user) {
|
||||
|
||||
if (!world.isClient && user instanceof PlayerEntity player) {
|
||||
|
||||
// Apply pregnancy effect
|
||||
player.addStatusEffect(new StatusEffectInstance(
|
||||
ModEffects.PREGNANT,
|
||||
20 * 60 * 10, // 10 minutes
|
||||
0,
|
||||
false,
|
||||
true
|
||||
));
|
||||
|
||||
// Play sound
|
||||
world.playSound(
|
||||
null,
|
||||
player.getBlockPos(),
|
||||
ModSounds.PLAYER_MILK_SONG,
|
||||
SoundCategory.PLAYERS,
|
||||
1.0f,
|
||||
1.0f
|
||||
);
|
||||
}
|
||||
|
||||
// ✅ CORRECT vanilla behavior:
|
||||
// consumes milk and gives bucket
|
||||
if (user instanceof PlayerEntity player) {
|
||||
return ItemUsage.exchangeStack(stack, player, new ItemStack(Items.BUCKET));
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
@ -1,16 +1,16 @@
|
||||
package net.Chipperfluff.chipi.item.armor;
|
||||
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
import net.minecraft.item.ArmorItem;
|
||||
import net.minecraft.item.ArmorMaterial;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.util.Util;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
|
||||
public class ChipperArmorMaterial implements ArmorMaterial {
|
||||
|
||||
public static final ChipperArmorMaterial INSTANCE = new ChipperArmorMaterial();
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package net.Chipperfluff.chipi.armor;
|
||||
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.SlabBlock;
|
||||
import net.minecraft.block.StairsBlock;
|
||||
@ -12,8 +11,10 @@ import net.minecraft.text.Text;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import static net.Chipperfluff.chipi.util.ChipiTrackedData.CHIPI_ENERGY;
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
|
||||
import static net.Chipperfluff.chipi.server.ChipiServerEvents.CHIPI_DIMENSION_KEY;
|
||||
import static net.Chipperfluff.chipi.util.ChipiTrackedData.CHIPI_ENERGY;
|
||||
|
||||
public final class ProtectionAuraHandler {
|
||||
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
package net.Chipperfluff.chipi.item.music;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.MusicDiscItem;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.util.Identifier;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
|
||||
public class ModMusicDiscs {
|
||||
|
||||
private static final Map<String, Item> DISCS = new LinkedHashMap<>();
|
||||
|
||||
private static final MusicDiscDef[] DEFINITIONS = {
|
||||
new MusicDiscDef("aa9", 7, 5, 0),
|
||||
new MusicDiscDef("abc", 7, 2, 11),
|
||||
new MusicDiscDef("fs", 7, 2, 0),
|
||||
new MusicDiscDef("phone", 7, 2, 11),
|
||||
new MusicDiscDef("wha", 7, 1, 48),
|
||||
new MusicDiscDef("who", 7, 2, 27),
|
||||
new MusicDiscDef("working_as_intented", 7, 3, 45)
|
||||
};
|
||||
|
||||
private static Item registerDisc(MusicDiscDef def) {
|
||||
String id = "chipi_record_" + def.name();
|
||||
Identifier identifier = new Identifier(ChipiMod.MOD_ID, id);
|
||||
|
||||
SoundEvent sound = Registry.register(
|
||||
Registries.SOUND_EVENT,
|
||||
identifier,
|
||||
SoundEvent.of(identifier)
|
||||
);
|
||||
|
||||
Item item = Registry.register(
|
||||
Registries.ITEM,
|
||||
identifier,
|
||||
new MusicDiscItem(
|
||||
def.comparatorOutput(),
|
||||
sound,
|
||||
new Item.Settings().maxCount(1),
|
||||
toTicks(def.minutes(), def.seconds())
|
||||
)
|
||||
);
|
||||
|
||||
DISCS.put(def.name(), item);
|
||||
return item;
|
||||
}
|
||||
|
||||
public static Map<String, Item> getAll() {
|
||||
return DISCS;
|
||||
}
|
||||
|
||||
public static void registerAll() {
|
||||
for (MusicDiscDef def : DEFINITIONS) {
|
||||
registerDisc(def);
|
||||
}
|
||||
}
|
||||
|
||||
private static int toTicks(int minutes, int seconds) {
|
||||
int totalSeconds = Math.max(0, minutes) * 60 + Math.max(0, seconds);
|
||||
return totalSeconds * 20;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
package net.Chipperfluff.chipi.item.music;
|
||||
|
||||
public record MusicDiscDef(String name, int comparatorOutput, int minutes, int seconds) {}
|
||||
@ -2,8 +2,8 @@ package net.Chipperfluff.chipi.item.tool;
|
||||
|
||||
import net.minecraft.item.ToolMaterial;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
|
||||
public enum ChipperToolMaterial implements ToolMaterial {
|
||||
INSTANCE;
|
||||
|
||||
@ -2,7 +2,6 @@ package net.Chipperfluff.chipi.mixin;
|
||||
|
||||
import net.minecraft.entity.data.DataTracker;
|
||||
import net.minecraft.entity.data.TrackedData;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@ -16,10 +15,7 @@ public abstract class DataTrackerMixin {
|
||||
protected abstract <T> DataTracker.Entry<T> getEntry(TrackedData<T> data);
|
||||
|
||||
@Inject(method = "get", at = @At("HEAD"), cancellable = true)
|
||||
private <T> void chipi$nullSafeGet(
|
||||
TrackedData<T> data,
|
||||
CallbackInfoReturnable<T> cir
|
||||
) {
|
||||
private <T> void chipi$nullSafeGet(TrackedData<T> data, CallbackInfoReturnable<T> cir) {
|
||||
DataTracker.Entry<T> entry = this.getEntry(data);
|
||||
|
||||
if (entry == null) {
|
||||
|
||||
@ -1,30 +1,82 @@
|
||||
package net.Chipperfluff.chipi.mixin;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.Chipperfluff.chipi.util.ChipiTrackedData;
|
||||
import net.minecraft.entity.data.DataTracker;
|
||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
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;
|
||||
|
||||
import net.Chipperfluff.chipi.effect.ModEffects;
|
||||
import net.Chipperfluff.chipi.effect.PregnantEffect;
|
||||
import net.Chipperfluff.chipi.util.ChipiTrackedData;
|
||||
|
||||
@Mixin(PlayerEntity.class)
|
||||
public abstract class PlayerEntityMixin {
|
||||
|
||||
/* ============================================================
|
||||
INIT: tracked data
|
||||
============================================================ */
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void chipi$initTrackedData(
|
||||
World world,
|
||||
BlockPos pos,
|
||||
float yaw,
|
||||
GameProfile profile,
|
||||
CallbackInfo ci
|
||||
World world,
|
||||
BlockPos pos,
|
||||
float yaw,
|
||||
GameProfile profile,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
PlayerEntity self = (PlayerEntity)(Object)this;
|
||||
DataTracker tracker = self.getDataTracker();
|
||||
|
||||
tracker.startTracking(ChipiTrackedData.CHIPI_ENERGY, 1.0f);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
JUMP CLAMP: pregnancy logic
|
||||
============================================================ */
|
||||
|
||||
@Inject(
|
||||
method = "jump",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void chipi$pregnancyJumpClamp(CallbackInfo ci) {
|
||||
if (!((Object)this instanceof ServerPlayerEntity player)) return;
|
||||
|
||||
StatusEffectInstance inst =
|
||||
player.getStatusEffect(ModEffects.PREGNANT);
|
||||
|
||||
if (inst == null) return; // normal jump
|
||||
|
||||
int total = PregnantEffect.TOTAL_DURATION;
|
||||
int remaining = inst.getDuration();
|
||||
|
||||
// progress 0.0 → 1.0
|
||||
double progress =
|
||||
1.0 - ((double)remaining / total);
|
||||
progress = Math.min(Math.max(progress, 0.0), 1.0);
|
||||
|
||||
// vanilla jump velocity ≈ 0.42
|
||||
double maxJump = 0.42 * (1.0 - progress);
|
||||
|
||||
// End stage: NO jumping at all
|
||||
if (maxJump < 0.05) {
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3d vel = player.getVelocity();
|
||||
player.setVelocity(vel.x, maxJump, vel.z);
|
||||
player.velocityDirty = true;
|
||||
|
||||
// stop vanilla jump
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,36 @@
|
||||
package net.Chipperfluff.chipi.server;
|
||||
|
||||
import net.Chipperfluff.chipi.SpawnPlacedState;
|
||||
import net.Chipperfluff.chipi.armor.ProtectionAuraHandler;
|
||||
import net.Chipperfluff.chipi.block.ChipperPortalBlock;
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiDungeonGenerator;
|
||||
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
|
||||
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
|
||||
import net.fabricmc.fabric.api.event.player.UseEntityCallback;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.structure.StructurePlacementData;
|
||||
import net.minecraft.structure.StructureTemplate;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.GameRules;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.GenerationStep;
|
||||
|
||||
import net.Chipperfluff.chipi.SpawnPlacedState;
|
||||
import net.Chipperfluff.chipi.armor.ProtectionAuraHandler;
|
||||
import net.Chipperfluff.chipi.block.ChipperPortalBlock;
|
||||
import net.Chipperfluff.chipi.item.ModItems;
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiDungeonGenerator;
|
||||
|
||||
|
||||
public final class ChipiServerEvents {
|
||||
|
||||
@ -33,6 +45,44 @@ public final class ChipiServerEvents {
|
||||
private ChipiServerEvents() {}
|
||||
|
||||
public static void register() {
|
||||
BiomeModifications.addFeature(
|
||||
BiomeSelectors.foundInOverworld(),
|
||||
GenerationStep.Feature.UNDERGROUND_ORES,
|
||||
RegistryKey.of(
|
||||
RegistryKeys.PLACED_FEATURE,
|
||||
new Identifier("chipi", "chipper_ore")
|
||||
)
|
||||
);
|
||||
|
||||
// ===== PLAYER MILK INTERACTION =====
|
||||
UseEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> {
|
||||
if (world.isClient()) return ActionResult.PASS;
|
||||
|
||||
if (!(entity instanceof PlayerEntity target)) return ActionResult.PASS;
|
||||
if (target == player) return ActionResult.FAIL;
|
||||
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
if (!stack.isOf(Items.BUCKET)) return ActionResult.PASS;
|
||||
|
||||
stack.decrement(1);
|
||||
|
||||
ItemStack milk = new ItemStack(ModItems.PLAYER_MILK);
|
||||
if (!player.getInventory().insertStack(milk)) {
|
||||
player.dropItem(milk, false);
|
||||
}
|
||||
|
||||
world.playSound(
|
||||
null,
|
||||
player.getBlockPos(),
|
||||
SoundEvents.ENTITY_COW_MILK,
|
||||
SoundCategory.PLAYERS,
|
||||
1.0f,
|
||||
1.1f
|
||||
);
|
||||
|
||||
return ActionResult.SUCCESS;
|
||||
});
|
||||
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(server -> SERVER = server);
|
||||
ServerTickEvents.END_SERVER_TICK.register(ChipiServerEvents::tickPlayers);
|
||||
ServerTickEvents.END_WORLD_TICK.register(ChipiServerEvents::handleVoidFailsafe);
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
package net.Chipperfluff.chipi.sound;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.Chipperfluff.chipi.ChipiMod;
|
||||
|
||||
public class ModSounds {
|
||||
|
||||
public static final SoundEvent MEP_MILK = register("entity.mep.milk");
|
||||
public static final SoundEvent PLAYER_MILK_SONG = register("player_milk_song");
|
||||
|
||||
private static SoundEvent register(String id) {
|
||||
Identifier identifier = new Identifier(ChipiMod.MOD_ID, id);
|
||||
|
||||
@ -6,9 +6,7 @@ import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
||||
public final class ChipiTrackedData {
|
||||
|
||||
public static final TrackedData<Float> CHIPI_ENERGY =
|
||||
DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||
public static final TrackedData<Float> CHIPI_ENERGY = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||
|
||||
private ChipiTrackedData() {}
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ package net.Chipperfluff.chipi.util;
|
||||
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@ -2,7 +2,6 @@ package net.Chipperfluff.chipi.util;
|
||||
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
package net.Chipperfluff.chipi.world.gen;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.struct.CorridorEWStructure;
|
||||
import net.Chipperfluff.chipi.world.gen.struct.CorridorNSStructure;
|
||||
import net.Chipperfluff.chipi.world.gen.struct.RoomBaseStructure;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class ChipiDungeonGenerator {
|
||||
|
||||
@ -24,13 +25,10 @@ public class ChipiDungeonGenerator {
|
||||
|
||||
// Center-to-center step so corridors start 1 block inside the north room and end 1 block inside
|
||||
// the south room.
|
||||
private static final int STEP_Z =
|
||||
ROOM_EXTENT_SOUTH + CORRIDOR_LENGTH + ROOM_EXTENT_NORTH - 1; // 25
|
||||
private static final int STEP_X =
|
||||
ROOM_EXTENT_EAST + CORRIDOR_LENGTH + ROOM_EXTENT_WEST - 1; // 25
|
||||
private static final int STEP_Z = ROOM_EXTENT_SOUTH + CORRIDOR_LENGTH + ROOM_EXTENT_NORTH - 1; // 25
|
||||
private static final int STEP_X = ROOM_EXTENT_EAST + CORRIDOR_LENGTH + ROOM_EXTENT_WEST - 1; // 25
|
||||
|
||||
private static final int ROWS_SOUTH =
|
||||
40; // rows of rooms south of spawn (spawn room itself is already placed)
|
||||
private static final int ROWS_SOUTH = 40; // rows of rooms south of spawn (spawn room itself is already placed)
|
||||
private static final int COLS_EW = 40; // columns across X (split roughly evenly around center)
|
||||
|
||||
private ChipiDungeonGenerator() {}
|
||||
@ -40,8 +38,7 @@ public class ChipiDungeonGenerator {
|
||||
// Spawn is already placed. Fixed anchors (not relative to portal):
|
||||
// first corridor origin, then the first generated room center is south of spawn.
|
||||
BlockPos firstCorridorAnchor = new BlockPos(5, CORRIDOR_Y, 11);
|
||||
BlockPos firstGeneratedRoomCenter =
|
||||
new BlockPos(5, ROOM_Y, 24); // explicit first floor anchor
|
||||
BlockPos firstGeneratedRoomCenter = new BlockPos(5, ROOM_Y, 24); // explicit first floor anchor
|
||||
|
||||
// First room/corridor use direct instances as requested.
|
||||
RoomBaseStructure firstRoom = WorldMaster.getDefaultRoom();
|
||||
@ -60,16 +57,14 @@ public class ChipiDungeonGenerator {
|
||||
// Place rooms strictly southward (Z never decreases), across X in both directions.
|
||||
for (int row = 0; row < ROWS_SOUTH; row++) {
|
||||
for (int col = minCol; col <= maxCol; col++) {
|
||||
int gridX =
|
||||
col; // grid 0,0 is the first generated room; -X -> negative gridX, +X ->
|
||||
// positive gridX
|
||||
int gridX = col; // grid 0,0 is the first generated room; -X -> negative gridX, +X -> positive gridX
|
||||
int gridY = row; // gridY increases southward only
|
||||
|
||||
BlockPos center =
|
||||
new BlockPos(
|
||||
firstGeneratedRoomCenter.getX() + (col * STEP_X),
|
||||
ROOM_Y,
|
||||
firstGeneratedRoomCenter.getZ() + (row * STEP_Z));
|
||||
BlockPos center = new BlockPos(
|
||||
firstGeneratedRoomCenter.getX() + (col * STEP_X),
|
||||
ROOM_Y,
|
||||
firstGeneratedRoomCenter.getZ() + (row * STEP_Z)
|
||||
);
|
||||
|
||||
RoomBaseStructure room = WorldMaster.resolveRoom(ctx(world, gridX, gridY, center, null));
|
||||
room.placeAt(world, center);
|
||||
@ -84,20 +79,19 @@ public class ChipiDungeonGenerator {
|
||||
int gridX = col;
|
||||
int gridY = row;
|
||||
|
||||
BlockPos currentCenter =
|
||||
new BlockPos(
|
||||
firstGeneratedRoomCenter.getX() + (col * STEP_X),
|
||||
ROOM_Y,
|
||||
firstGeneratedRoomCenter.getZ() + (row * STEP_Z));
|
||||
BlockPos currentCenter = new BlockPos(
|
||||
firstGeneratedRoomCenter.getX() + (col * STEP_X),
|
||||
ROOM_Y,
|
||||
firstGeneratedRoomCenter.getZ() + (row * STEP_Z)
|
||||
);
|
||||
|
||||
BlockPos anchorSouth =
|
||||
new BlockPos(
|
||||
currentCenter.getX(),
|
||||
CORRIDOR_Y,
|
||||
currentCenter.getZ() + ROOM_EXTENT_SOUTH);
|
||||
BlockPos anchorSouth = new BlockPos(
|
||||
currentCenter.getX(),
|
||||
CORRIDOR_Y,
|
||||
currentCenter.getZ() + ROOM_EXTENT_SOUTH
|
||||
);
|
||||
|
||||
CorridorNSStructure corridorNS =
|
||||
WorldMaster.resolveCorridorNS(ctx(world, gridX, gridY, anchorSouth, null));
|
||||
CorridorNSStructure corridorNS = WorldMaster.resolveCorridorNS(ctx(world, gridX, gridY, anchorSouth, null));
|
||||
corridorNS.placeAt(world, anchorSouth);
|
||||
WorldMaster.afterPlaceCorridorNS(ctx(world, gridX, gridY, anchorSouth, corridorNS));
|
||||
}
|
||||
@ -109,20 +103,19 @@ public class ChipiDungeonGenerator {
|
||||
int gridX = col;
|
||||
int gridY = row;
|
||||
|
||||
BlockPos currentCenter =
|
||||
new BlockPos(
|
||||
firstGeneratedRoomCenter.getX() + (col * STEP_X),
|
||||
ROOM_Y,
|
||||
firstGeneratedRoomCenter.getZ() + (row * STEP_Z));
|
||||
BlockPos currentCenter = new BlockPos(
|
||||
firstGeneratedRoomCenter.getX() + (col * STEP_X),
|
||||
ROOM_Y,
|
||||
firstGeneratedRoomCenter.getZ() + (row * STEP_Z)
|
||||
);
|
||||
|
||||
BlockPos anchorEast =
|
||||
new BlockPos(
|
||||
currentCenter.getX() + ROOM_EXTENT_EAST,
|
||||
CORRIDOR_Y,
|
||||
currentCenter.getZ());
|
||||
BlockPos anchorEast = new BlockPos(
|
||||
currentCenter.getX() + ROOM_EXTENT_EAST,
|
||||
CORRIDOR_Y,
|
||||
currentCenter.getZ()
|
||||
);
|
||||
|
||||
CorridorEWStructure corridorEW =
|
||||
WorldMaster.resolveCorridorEW(ctx(world, gridX, gridY, anchorEast, null));
|
||||
CorridorEWStructure corridorEW = WorldMaster.resolveCorridorEW(ctx(world, gridX, gridY, anchorEast, null));
|
||||
corridorEW.placeAt(world, anchorEast);
|
||||
WorldMaster.afterPlaceCorridorEW(ctx(world, gridX, gridY, anchorEast, corridorEW));
|
||||
}
|
||||
@ -136,18 +129,10 @@ public class ChipiDungeonGenerator {
|
||||
|
||||
runInChipi(world, "fill 7 87 15 3 91 16 minecraft:air");
|
||||
|
||||
runInChipi(
|
||||
world,
|
||||
"setblock 4 88 15 minecraft:deepslate_tile_stairs[facing=west,waterlogged=true]");
|
||||
runInChipi(
|
||||
world,
|
||||
"setblock 4 88 16 minecraft:deepslate_tile_stairs[facing=west,waterlogged=true]");
|
||||
runInChipi(
|
||||
world,
|
||||
"setblock 6 88 15 minecraft:deepslate_tile_stairs[facing=east,waterlogged=true]");
|
||||
runInChipi(
|
||||
world,
|
||||
"setblock 6 88 16 minecraft:deepslate_tile_stairs[facing=east,waterlogged=true]");
|
||||
runInChipi(world, "setblock 4 88 15 minecraft:deepslate_tile_stairs[facing=west,waterlogged=true]");
|
||||
runInChipi(world, "setblock 4 88 16 minecraft:deepslate_tile_stairs[facing=west,waterlogged=true]");
|
||||
runInChipi(world, "setblock 6 88 15 minecraft:deepslate_tile_stairs[facing=east,waterlogged=true]");
|
||||
runInChipi(world, "setblock 6 88 16 minecraft:deepslate_tile_stairs[facing=east,waterlogged=true]");
|
||||
|
||||
runInChipi(world, "fill 7 88 15 7 91 16 minecraft:deepslate_tiles");
|
||||
runInChipi(world, "fill 3 88 16 3 91 15 minecraft:deepslate_tiles");
|
||||
@ -180,10 +165,11 @@ public class ChipiDungeonGenerator {
|
||||
|
||||
private static void runInChipi(ServerWorld world, String command) {
|
||||
world.getServer()
|
||||
.getCommandManager()
|
||||
.executeWithPrefix(
|
||||
world.getServer().getCommandSource(),
|
||||
"execute in chipi:chipi_dimension run " + command);
|
||||
.getCommandManager()
|
||||
.executeWithPrefix(
|
||||
world.getServer().getCommandSource(),
|
||||
"execute in chipi:chipi_dimension run " + command
|
||||
);
|
||||
}
|
||||
|
||||
private static DungeonContext ctx(ServerWorld world, int gridX, int gridY, BlockPos origin, ChipiStructure structure) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package net.Chipperfluff.chipi.world.gen;
|
||||
|
||||
import java.util.Optional;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.entity.StructureBlockBlockEntity;
|
||||
import net.minecraft.block.enums.StructureBlockMode;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
@ -9,7 +9,7 @@ import net.minecraft.structure.StructureTemplate;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
import net.minecraft.block.Blocks;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class ChipiStructure {
|
||||
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
package net.Chipperfluff.chipi.world.gen;
|
||||
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.struct.CorridorEWStructure;
|
||||
import net.Chipperfluff.chipi.world.gen.struct.CorridorNSStructure;
|
||||
import net.Chipperfluff.chipi.world.gen.struct.RoomBaseStructure;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public final class WorldMaster {
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package net.Chipperfluff.chipi.world.gen.struct;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiStructure; // <-- THIS WAS MISSING
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiStructure; // <-- THIS WAS MISSING
|
||||
|
||||
public class ChipiStructures {
|
||||
|
||||
private static final Map<String, ChipiStructure> REGISTRY = new HashMap<>();
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
package net.Chipperfluff.chipi.world.gen.struct;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiStructure;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiStructure;
|
||||
|
||||
public class CorridorEWStructure extends ChipiStructure {
|
||||
|
||||
public CorridorEWStructure() {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
package net.Chipperfluff.chipi.world.gen.struct;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiStructure;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiStructure;
|
||||
|
||||
public class CorridorNSStructure extends ChipiStructure {
|
||||
|
||||
public CorridorNSStructure() {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
package net.Chipperfluff.chipi.world.gen.struct;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiStructure;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiStructure;
|
||||
|
||||
public class RoomBaseStructure extends ChipiStructure {
|
||||
|
||||
public RoomBaseStructure() {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
package net.Chipperfluff.chipi.world.gen.struct;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiStructure;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.Chipperfluff.chipi.world.gen.ChipiStructure;
|
||||
|
||||
public class SpawnStructure extends ChipiStructure {
|
||||
|
||||
public SpawnStructure() {
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
{
|
||||
"variants": {
|
||||
"": { "model": "chipi:block/jingle_block" }
|
||||
}
|
||||
}
|
||||
@ -2,17 +2,32 @@
|
||||
"death.attack.void_block": "§8%1$s stepped beyond safety — the Outside answered.",
|
||||
"death.attack.chipi.void_block_fire": "§c%1$s tried to save themselves.§r §8It got worse.",
|
||||
|
||||
"itemGroup.chipi.chipi": "Chipi",
|
||||
|
||||
"effect.chipi.chipi_blessing": "Chipi's Blessing",
|
||||
|
||||
"entity.chipi.mep": "Merp :3",
|
||||
"effect.chipi.chipi_blessing": "§bChipi's Blessing",
|
||||
"effect.chipi.pregnant": "§dyou are Pregnant",
|
||||
|
||||
"block.chipi.void_block": "Void Block",
|
||||
"block.chipi.chipper_frame": "Chipper Frame",
|
||||
"block.chipi.chipper_portal": "Chipper Portal",
|
||||
"block.chipi.chipper_ore": "Chipper Ore",
|
||||
"block.chipi.chipper_alloy_block": "Chipper Alloy Block",
|
||||
"block.chipi.jingle_block": "Jingle Block",
|
||||
|
||||
"item.chipi.chipi_record_aa9": "Chipi Record – Aa9",
|
||||
"item.chipi.chipi_record_aa9.desc": "Chipi Record – Aa9",
|
||||
"item.chipi.chipi_record_abc": "Chipi Record – Abc",
|
||||
"item.chipi.chipi_record_abc.desc": "Chipi Record – Abc",
|
||||
"item.chipi.chipi_record_fs": "Chipi Record – Fs",
|
||||
"item.chipi.chipi_record_fs.desc": "Chipi Record – Fs",
|
||||
"item.chipi.chipi_record_phone": "Chipi Record – Phone",
|
||||
"item.chipi.chipi_record_phone.desc": "Chipi Record – Phone",
|
||||
"item.chipi.chipi_record_wha": "Chipi Record – Wha",
|
||||
"item.chipi.chipi_record_wha.desc": "Chipi Record – Wha",
|
||||
"item.chipi.chipi_record_who": "Chipi Record – Who",
|
||||
"item.chipi.chipi_record_who.desc": "Chipi Record – Who",
|
||||
"item.chipi.chipi_record_working_as_intented": "Chipi Record – Working As Intented",
|
||||
"item.chipi.chipi_record_working_as_intented.desc": "Chipi Record – Working As Intented",
|
||||
|
||||
"itemGroup.chipi.chipi": "Chipi",
|
||||
|
||||
"item.chipi.void_block": "Void Block",
|
||||
"item.chipi.chipper_frame": "Chipper Frame",
|
||||
@ -23,9 +38,7 @@
|
||||
"item.chipi.chipper_ingot": "Chipper Ingot",
|
||||
"item.chipi.chipper_alloy": "Chipper Alloy",
|
||||
"item.chipi.mep_spawn_egg": "Mep Spawn Egg",
|
||||
|
||||
"item.chipi.nut": "Nut",
|
||||
"item.chipi.mep_milk": "Mep Milk",
|
||||
"item.chipi.jingle_block": "Jingle Block",
|
||||
|
||||
"item.chipi.chipper_helmet": "Chipper Helmet",
|
||||
"item.chipi.chipper_chestplate": "Chipper Chestplate",
|
||||
@ -38,30 +51,34 @@
|
||||
"item.chipi.chipper_shovel": "Chipper Shovel",
|
||||
"item.chipi.chipper_hoe": "Chipper Hoe",
|
||||
|
||||
"tooltip.chipi.void_block": "§8It hums quietly.§r §7Do not listen.",
|
||||
"tooltip.chipi.chipper_frame": "§7Built to hold a mistake in place.",
|
||||
"tooltip.chipi.chipper_portal": "§5Something on the other side is already aware of you.",
|
||||
"tooltip.chipi.chipper_ore": "§7Common.§r §8Uncomfortably so.",
|
||||
"tooltip.chipi.chipper_alloy_block": "§7Pressed together until it stopped screaming.",
|
||||
"item.chipi.nut": "Nut",
|
||||
"item.chipi.mep_milk": "Mep Milk",
|
||||
"item.chipi.player_milk": "Player Milk",
|
||||
|
||||
"tooltip.chipi.nut": "§7Probably edible.§r §8Probably.",
|
||||
"tooltip.chipi.raw_chipper_ore": "§7Still warm to the touch.",
|
||||
"tooltip.chipi.chipper_ingot": "§7Dense.§r §8Too dense.",
|
||||
"tooltip.chipi.chipper_alloy": "§7Stronger than it looks.§r §8Worse than it feels.",
|
||||
"tooltip.chipi.void_block": "§8It hums quietly.§r §7You are not supposed to notice that.",
|
||||
"tooltip.chipi.chipper_frame": "§7Built to hold a mistake.§r §8It is doing its best.",
|
||||
"tooltip.chipi.chipper_portal": "§5Something on the other side noticed you.§r §8It did not look away.",
|
||||
"tooltip.chipi.chipper_ore": "§7Common.§r §8Suspiciously so.",
|
||||
"tooltip.chipi.chipper_alloy_block": "§7Pressed together until it stopped complaining.§r §8Mostly.",
|
||||
"tooltip.chipi.jingle_block": "§7It makes a noise.§r §8You didn’t ask when.",
|
||||
|
||||
"tooltip.chipi.mep_spawn_egg": "§8It knows where you are.§r §7It always did.",
|
||||
"tooltip.chipi.raw_chipper_ore": "§7Still warm to the touch.§r §8That seems unnecessary.",
|
||||
"tooltip.chipi.chipper_ingot": "§7Dense and stubborn.§r §8Refuses to fail politely.",
|
||||
"tooltip.chipi.chipper_alloy": "§7Stronger than it looks.§r §8Judges you silently.",
|
||||
"tooltip.chipi.mep_spawn_egg": "§8It already knows where you are.§r §7Spawning is a courtesy.",
|
||||
|
||||
"tooltip.chipi.chipper_helmet": "§7Soaks the hit.§r §8Cracks immediately.",
|
||||
"tooltip.chipi.chipper_chestplate": "§7Lets you stand your ground.§r §8Once.",
|
||||
"tooltip.chipi.chipper_leggings": "§7Heavy steps.§r §8Short lifespan.",
|
||||
"tooltip.chipi.chipper_boots": "§7You won’t be moved.§r §8You will be broken.",
|
||||
"tooltip.chipi.chipper_helmet": "§7Heavy and awkward.§r §8Feels incomplete alone.",
|
||||
"tooltip.chipi.chipper_chestplate": "§7Looks like armor.§r §8Does nothing by itself.",
|
||||
"tooltip.chipi.chipper_leggings": "§7Built to last.§r §8Waiting for the rest.",
|
||||
"tooltip.chipi.chipper_boots": "§7Sturdy soles.§r §8Missing something important.",
|
||||
|
||||
"tooltip.chipi.chipper_sword": "§7Cuts clean.§r §8Leaves regret.",
|
||||
"tooltip.chipi.chipper_pickaxe": "§7Breaks stone.§r §8Breaks trust.",
|
||||
"tooltip.chipi.chipper_axe": "§7Heavy swing.§r §8Heavier consequence.",
|
||||
"tooltip.chipi.chipper_shovel": "§7Digs fast.§r §8Finds nothing good.",
|
||||
"tooltip.chipi.chipper_hoe": "§7Makes things grow.§r §8They shouldn’t.",
|
||||
|
||||
"tooltip.chipi.mep_milk": "§7Warm.§r §8You probably shouldn't drink this."
|
||||
"tooltip.chipi.chipper_sword": "§7Sharp and eager.§r §8Five swings of confidence.",
|
||||
"tooltip.chipi.chipper_pickaxe": "§7Fast bite on stone.§r §8Gives up immediately after.",
|
||||
"tooltip.chipi.chipper_axe": "§7Clean chop.§r §8Handle resents you.",
|
||||
"tooltip.chipi.chipper_shovel": "§7Quick dig.§r §8Gravel smells weakness.",
|
||||
"tooltip.chipi.chipper_hoe": "§7Turns soil fast.§r §8Blunts before the sprouts.",
|
||||
|
||||
"tooltip.chipi.nut": "§7Probably edible.§r §8Confidence not included.",
|
||||
"tooltip.chipi.mep_milk": "§7Temporary comfort in liquid form.§r §8The bucket survives.",
|
||||
"tooltip.chipi.player_milk": "what the fuck did you just just put in me"
|
||||
}
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:block/cube_all",
|
||||
"textures": {
|
||||
"all": "chipi:block/jingle_block"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "chipi:item/chipi_record_aa9"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "chipi:item/chipi_record_abc"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "chipi:item/chipi_record_fs"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "chipi:item/chipi_record_phone"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "chipi:item/chipi_record_wha"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "chipi:item/chipi_record_who"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "chipi:item/chipi_record_working_as_intented"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "chipi:block/jingle_block"
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "chipi:item/player_milk"
|
||||
}
|
||||
}
|
||||
@ -3,5 +3,31 @@
|
||||
"sounds": [
|
||||
"chipi:mep_milk"
|
||||
]
|
||||
},
|
||||
"player_milk_song": {
|
||||
"sounds": [
|
||||
"chipi:player_milk"
|
||||
]
|
||||
},
|
||||
"chipi_record_aa9": {
|
||||
"sounds": [{ "name": "chipi:chipi_record_aa9", "stream": true }]
|
||||
},
|
||||
"chipi_record_abc": {
|
||||
"sounds": [{ "name": "chipi:chipi_record_abc", "stream": true }]
|
||||
},
|
||||
"chipi_record_fs": {
|
||||
"sounds": [{ "name": "chipi:chipi_record_fs", "stream": true }]
|
||||
},
|
||||
"chipi_record_phone": {
|
||||
"sounds": [{ "name": "chipi:chipi_record_phone", "stream": true }]
|
||||
},
|
||||
"chipi_record_wha": {
|
||||
"sounds": [{ "name": "chipi:chipi_record_wha", "stream": true }]
|
||||
},
|
||||
"chipi_record_who": {
|
||||
"sounds": [{ "name": "chipi:chipi_record_who", "stream": true }]
|
||||
},
|
||||
"chipi_record_working_as_intented": {
|
||||
"sounds": [{ "name": "chipi:chipi_record_working_as_intented", "stream": true }]
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/main/resources/assets/chipi/sounds/chipi_record_aa9.ogg
Normal file
BIN
src/main/resources/assets/chipi/sounds/chipi_record_abc.ogg
Normal file
BIN
src/main/resources/assets/chipi/sounds/chipi_record_fs.ogg
Normal file
BIN
src/main/resources/assets/chipi/sounds/chipi_record_phone.ogg
Normal file
BIN
src/main/resources/assets/chipi/sounds/chipi_record_wha.ogg
Normal file
BIN
src/main/resources/assets/chipi/sounds/chipi_record_who.ogg
Normal file
BIN
src/main/resources/assets/chipi/sounds/player_milk.ogg
Normal file
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 336 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 759 B |
BIN
src/main/resources/assets/chipi/textures/block/diamond_block.png
Normal file
|
After Width: | Height: | Size: 263 B |
BIN
src/main/resources/assets/chipi/textures/block/jingle_block.png
Normal file
|
After Width: | Height: | Size: 225 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 312 B |
BIN
src/main/resources/assets/chipi/textures/item/player_milk.png
Normal file
|
After Width: | Height: | Size: 339 B |
BIN
src/main/resources/assets/chipi/textures/mob_effect/pregnant.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
@ -0,0 +1,22 @@
|
||||
{
|
||||
"parent": "chipi:mishaps/root",
|
||||
"display": {
|
||||
"icon": { "item": "chipi:mep_milk" },
|
||||
"title": "Wait wait wait",
|
||||
"description": "Where is the milk from?",
|
||||
"frame": "task",
|
||||
"show_toast": true,
|
||||
"announce_to_chat": true,
|
||||
"hidden": false
|
||||
},
|
||||
"criteria": {
|
||||
"get_mep_milk": {
|
||||
"trigger": "minecraft:inventory_changed",
|
||||
"conditions": {
|
||||
"items": [
|
||||
{ "items": ["chipi:mep_milk"] }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
{
|
||||
"parent": "chipi:mishaps/root",
|
||||
"display": {
|
||||
"icon": {
|
||||
"item": "chipi:mep_milk"
|
||||
},
|
||||
"title": "Wait wait wait",
|
||||
"description": "Where is the milk from?",
|
||||
"frame": "task",
|
||||
"show_toast": true,
|
||||
"announce_to_chat": true,
|
||||
"hidden": false
|
||||
},
|
||||
"criteria": {
|
||||
"get_mep_milk": {
|
||||
"trigger": "minecraft:inventory_changed",
|
||||
"conditions": {
|
||||
"items": [
|
||||
{
|
||||
"items": [
|
||||
"chipi:mep_milk"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/main/resources/data/chipi/advancements/mishaps/root.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"parent": "chipi:root",
|
||||
"display": {
|
||||
"icon": {
|
||||
"item": "chipi:mep_milk"
|
||||
},
|
||||
"title": "Chipi Mishaps",
|
||||
"description": "Regrettable, memorable, unavoidable",
|
||||
"frame": "task",
|
||||
"hidden": true,
|
||||
"show_toast": false,
|
||||
"announce_to_chat": false
|
||||
},
|
||||
"criteria": {
|
||||
"tick": {
|
||||
"trigger": "minecraft:tick"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,9 @@
|
||||
{
|
||||
"parent": "chipi:root",
|
||||
"parent": "chipi:mishaps/root",
|
||||
"display": {
|
||||
"icon": { "item": "chipi:void_block" },
|
||||
"icon": {
|
||||
"item": "chipi:void_block"
|
||||
},
|
||||
"title": "Consumed by the Void",
|
||||
"description": "Some knowledge was never meant to be obtained.",
|
||||
"frame": "challenge",
|
||||
@ -1,7 +1,9 @@
|
||||
{
|
||||
"parent": "chipi:root",
|
||||
"parent": "chipi:mishaps/root",
|
||||
"display": {
|
||||
"icon": { "item": "minecraft:lava_bucket" },
|
||||
"icon": {
|
||||
"item": "minecraft:lava_bucket"
|
||||
},
|
||||
"title": "That Didn’t Help",
|
||||
"description": "Tried to save yourself. Landed somewhere even worse.",
|
||||
"frame": "challenge",
|
||||