Compare commits

...

33 Commits

Author SHA1 Message Date
c4aed126d8
chore: update to 1.21.3
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-10-23 21:37:19 +02:00
fa5aa9edf9
chore: update to 1.21
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-06-14 14:21:37 +02:00
de00f51b06
fix: build in gradle:latest
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-04-25 22:21:50 +02:00
3fa30b834d
chore: update to 1.20.5
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/tag/woodpecker Pipeline failed
2024-04-25 21:51:15 +02:00
0e036599cf
fix: don't respond to events for other players if on client
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-03-31 14:13:42 +02:00
3b5e262bea
fix: hook additional methods for a better chance to catch damage
Some checks are pending
ci/woodpecker/tag/woodpecker Pipeline is pending
ci/woodpecker/push/woodpecker Pipeline was successful
2024-03-31 13:58:58 +02:00
26ef532b30
chore: update to 1.20.4
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-12-07 21:16:27 +01:00
70758f3966
fix: switch default crash provider. Someone had reported issues with the previous default, this one might work better.
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-11-02 17:16:12 +01:00
d924c522a7
chore: update to 1.20.2
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-22 21:16:51 +02:00
d074812af3
feat: Use JNA for WinApiProvider, remove natives
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-07-28 18:54:31 +02:00
49b97ad38d
Bump to 1.20
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2023-06-09 17:31:37 +02:00
d9bdd56c6b
Bump to 1.19.4 and add "Hang" crash
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/tag/woodpecker Pipeline was successful
2023-03-14 22:31:09 +01:00
2a20216d32
Additional crash providers: OOM, Segfault and StackOverflow
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-03-11 12:13:47 +01:00
21690627d4
Update natives for new paths
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/manual/woodpecker Pipeline failed
ci/woodpecker/tag/woodpecker Pipeline was successful
2023-01-06 11:43:12 +01:00
1cd569d200
Ensure initialized
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-12-29 15:59:00 +01:00
2289839966
Use new config compiler and experiment with panama (untested and disabled)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-12-29 15:51:08 +01:00
41b9062065
Update to 1.19.3
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2022-12-07 22:30:46 +01:00
875901d280
Tweak build
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-12-03 16:30:16 +01:00
dd47e1008e
Simplify build script
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-12-03 16:19:36 +01:00
d10d8e36cd
Attempt to fix
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-12-02 19:03:35 +01:00
b672e8f929
Migrate to new infrastructure
Some checks failed
ci/woodpecker/manual/woodpecker Pipeline failed
2022-12-02 18:59:18 +01:00
ca2e166a9d
Migrate to LibJF 3 for config instead of cloth 2022-08-28 16:27:55 +02:00
69b46c124e Attempt to fix CI pt.2 2022-07-28 16:08:04 +00:00
a82187b296 Attempt to fix CI 2022-07-28 15:53:48 +00:00
25b49918e3
Update for 1.19.1 2022-07-28 15:30:15 +02:00
059b13881e README: Add modrinth_exlucde to building section 2022-06-13 06:52:41 +00:00
5ed982b453
Update for 1.19 2022-06-08 12:00:57 +02:00
0b3323fb9c
Tweak README 2022-03-13 17:13:53 +01:00
834bc06cc2
Remove unneeded fabric api dependency 2022-03-02 18:09:24 +01:00
969abd7587 Adjust ci once again 2022-03-01 14:25:19 +00:00
8a30fdbed8 Adjust ci for changes in jfmod scripts 2022-03-01 14:12:36 +00:00
ceef702f99
Update for 1.18.2 2022-02-28 21:44:18 +01:00
5e90077e36 Update .gitlab-ci.yml file 2021-11-30 19:21:36 +00:00
45 changed files with 542 additions and 768 deletions

1
.gitignore vendored
View File

@ -119,3 +119,4 @@ run/
# No temporary natives! # No temporary natives!
src/main/c/natives.dll src/main/c/natives.dll
src/main/java/io/gitlab/jfronny/breakme/crash/KnownProviders.java

View File

@ -1,53 +0,0 @@
stages:
- compile_native
- build
- deploy
variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
build_natives:
tags:
- windows
stage: compile_native
script:
- .\src\main\c\build.bat
artifacts:
paths:
- src/main/resources/native/natives.dll
only:
- master
build_test:
image: gradle:jdk17
stage: deploy
script:
- gradle --build-cache build publish -Pmaven="$CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/maven"
- mv build/libs/* ./
- mv *-dev.jar dev-free.zip
- mv *.jar latest.zip
- gradle --build-cache -Pflavor=curseforge build
- cp build/libs/* ./
- mv *-dev.jar dev.zip
- mv *.jar latest-cf.jar
- mv latest.zip latest.jar
- mv dev-free.zip latest-dev.jar
- mv dev.zip latest-cf-dev.jar
artifacts:
paths:
- latest.jar
- latest-cf.jar
- latest-dev.jar
- latest-cf-dev.jar
only:
- master
deploy:
image: gradle:jdk17
rules:
- if: $CI_COMMIT_TAG && '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^master/'
stage: deploy
script:
- gradle --build-cache build publish modrinth -Prelease -Pmaven="$CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/maven"
- rm build/libs/*
- gradle --build-cache -Pflavor=curseforge build curseforge -Prelease

32
.woodpecker.yml Normal file
View File

@ -0,0 +1,32 @@
#include https://pages.frohnmeyer-wds.de/scripts/clone.yml
steps:
build_test:
image: gradle:latest
pull: true
commands:
- mkdir artifacts
- if [ $CI_PIPELINE_EVENT = tag ]; then
- gradle --build-cache moveArtifacts curseforge -Pflavour=curseforge -Prelease
- gradle --build-cache moveArtifacts publish modrinth modrinthSyncBody -Prelease -Pmaven="https://maven.frohnmeyer-wds.de/artifacts"
- else
- gradle --build-cache moveArtifacts -Pflavour=curseforge
- gradle --build-cache moveArtifacts deployDebug -Pmaven="https://maven.frohnmeyer-wds.de/artifacts"
- fi
secrets: [ maven_token, maven_name, modrinth_api_token, curseforge_api_token ]
artifacts:
image: woodpeckerci/plugin-s3
pull: true
settings:
bucket: pages
region: nebula
path_style: true
endpoint: https://s3.frohnmeyer-wds.de
access_key: pages
secret_key:
from_secret: pages_secret
source: build/artifacts/**/*
strip_prefix: build/
target: /${CI_REPO}
when:
- branch: ${CI_REPO_DEFAULT_BRANCH}

View File

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2020 JFronny Copyright (c) 2022 JFronny
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,8 +1,8 @@
# BreakMe [![pipeline status](https://gitlab.com/jfmods/BreakMe/badges/master/pipeline.svg)](https://gitlab.com/jfmods/BreakMe/-/commits/master) BreakMe allows configuring an event (death/taking damage) that causes minecraft to crash. It can also be configured to shut down or crash the whole OS.
BreakMe crashes Minecraft in creative ways. It uses Fabric (although porting should be trivial, most of the code is standard java & some JNI)\ It uses Fabric (although porting should be trivial, most of the code is standard java & some JNI)
# Installing Please note that shutting down (or worse: crashing) an OS while things are still open might cause data loss,
I recommend you to use the automatically built packages, you can download the latest curseforge build [here](https://gitlab.com/jfmods/BreakMe/-/jobs/artifacts/master/raw/latest-cf.jar?job=build_test) and the latest non-cf build [here](https://gitlab.com/jfmods/BreakMe/-/jobs/artifacts/master/raw/latest.jar?job=build_test) I am not responsible for that if you decide to enable that setting
# Configuration # Configuration
You can use [Mod Menu](https://www.curseforge.com/minecraft/mc-mods/modmenu) to change the configuration.\ You can use [Mod Menu](https://www.curseforge.com/minecraft/mc-mods/modmenu) to change the configuration.\
@ -17,16 +17,21 @@ The values are explained in more detail below
- Method: - Method:
- Unsafe_Universal_Forkbomb: Launch a self-multiplying process - Unsafe_Universal_Forkbomb: Launch a self-multiplying process
- Unsafe_Windows_WinAPI: Do some JNI-magic to instantly produce a blue-screen on windows - Unsafe_Windows_WinAPI: Do some JNI-magic to instantly produce a blue-screen on windows
- Unsafe_Universal_OOM: Causes an OOM exception
- Broken_Universal_ExitCode: Exit the integrated Server. The game still displays, but you can no longer interact with the world or quit. - Broken_Universal_ExitCode: Exit the integrated Server. The game still displays, but you can no longer interact with the world or quit.
- Safe_Universal_Hang: Hang both the client and integrated server thread.
- Safe_Universal_Exception: Performs an invalid operation. Behaves like every other crash and just closes the game, leaving a crash log. - Safe_Universal_Exception: Performs an invalid operation. Behaves like every other crash and just closes the game, leaving a crash log.
- SemiUnsafe_Universal_Exception: Throws a security exceptions. This does not work properly for 1.16.2 - SemiUnsafe_Universal_Exception: Throws a security exceptions. This does not work properly for 1.16.2
- SemiUnsafe_Universal_Shutdown: Attempts to run a shutdown command. Since these are specific to some systems this might not always work. - SemiUnsafe_Universal_Shutdown: Attempts to run a shutdown command. Since these are specific to some systems this might not always work.
- SemiUnsafe_Universal_Segfault: Causes a segmentation fault using lwjgl.
- SemiUnsafe_Universal_StackOverflow: Causes a stack overflow via infinite recursion.
- None: Do nothing - None: Do nothing
Please note that all methods marked "Unsafe" as well as the shutdown method are not available in the curseforge release Please note that all methods marked "Unsafe" as well as the shutdown method are not available in the CurseForge release
<!-- modrinth_exclude.start -->
# Building # Building
BreakMe consists of two parts: The main mod and the DLL used for Unsafe_Windows_WinAPI, which are built separately.\ A prebuilt DLL is included in the source tree and will be removed once it is replaced by a panama implementation.\
If you don't build on windows you can use the dll contained in the latest [CI build](https://gitlab.com/jfmods/BreakMe/-/jobs/artifacts/master/browse/build/libs?job=build_test) and place it in src/main/resources/native.\ If you want to build it yourself, use src/main/c/build.bat to build it on a windows PC.\
If you want to build the dll, use [this](https://gitlab.com/jfmods/BreakMe/-/blob/master/src/main/c/build.bat) as a reference (requires VS build tools).\ The mod itself is built like any other fabric mod: using gradle
The mod itself is built like any other fabric mod: using gradle. Look at the [CI config](https://gitlab.com/jfmods/BreakMe/-/blob/master/.gitlab-ci.yml#L10) for an example\ <!-- modrinth_exclude.end -->

View File

@ -1,19 +0,0 @@
apply from: "https://jfmods.gitlab.io/scripts/jfmod.gradle"
ext.flavor = project.hasProperty('flavor') ? project.getProperty('flavor') : 'modrinth'
repositories {
maven { url = "https://maven.shedaniel.me/"; name = "Cloth Config" }
}
dependencies {
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modApi include ("me.shedaniel.cloth:cloth-config-fabric:6.+")
modImplementation "com.terraformersmc:modmenu:3.+"
}
if (flavor == "curseforge") {
sourceSets.main.java.filter.exclude("**/unsafe/*")
sourceSets.main.resources.exclude("**/native/*")
}

108
build.gradle.kts Normal file
View File

@ -0,0 +1,108 @@
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeSpec
import io.gitlab.jfronny.scripts.*
import java.nio.file.Files
import java.util.*
import java.util.function.Supplier
import javax.lang.model.element.Modifier.*
plugins {
id("jfmod") version "1.6-SNAPSHOT"
}
allprojects { group = "io.gitlab.jfronny" }
base.archivesName = "breakme"
// https://fabricmc.net/develop/
jfMod {
minecraftVersion = "1.21.3"
yarn("build.2")
loaderVersion = "0.16.7"
libJfVersion = "3.18.0"
fabricApiVersion = "0.106.1+1.21.3"
modrinth {
projectId = "breakme"
requiredDependencies.add("libjf")
optionalDependencies.add("modmenu")
}
curseforge {
projectId = "400842"
requiredDependencies.add("libjf")
optionalDependencies.add("modmenu")
}
}
if (flavour == "") flavour = "modrinth"
dependencies {
modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v2")
// Dev env
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil")
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-config-ui-tiny")
modLocalRuntime("net.fabricmc.fabric-api:fabric-api")
modLocalRuntime("com.terraformersmc:modmenu:12.0.0-beta.1")
}
loom {
runs {
this.named("client").get().vmArg("-Xmx2G")
}
}
fun list(`package`: String): List<ClassName> = Files.list(projectDir.resolve("src/main/java").resolve(`package`.replace('.', '/')).toPath()).use { stream ->
stream
.map { it.fileName.toString() }
.map { it.substring(0, it.lastIndexOf('.')) }
.filter { it.endsWith("Provider") }
.map { ClassName.get(`package`, it) }
.toList()
}
val classes = LinkedList(list("io.gitlab.jfronny.breakme.crash.safe"))
if (flavour == "curseforge") {
sourceSets.main.get().java.filter.exclude("**/unsafe/*")
} else {
classes.addAll(list("io.gitlab.jfronny.breakme.crash.unsafe"))
}
sourceSets {
main {
generate(project) {
val providerType = ClassName.get("io.gitlab.jfronny.breakme.crash", "CrashProvider")
val supplierType = ParameterizedTypeName.get(ClassName.get(Supplier::class.java), providerType)
`enum`("io.gitlab.jfronny.breakme.crash", "Method") {
modifiers(PUBLIC)
superInterface(providerType)
for (klazz in classes) {
val name = klazz.simpleName()
enumConstant(name.substring(0, name.length - "Provider".length), TypeSpec.anonymousClassBuilder("\$T::new", klazz).build())
}
field(supplierType, "provider", PRIVATE, FINAL)
constructor {
parameter(supplierType, "provider")
code {
addStatement("this.provider = new \$T<>(provider)", ClassName.get("io.gitlab.jfronny.commons", "LazySupplier"))
}
}
method("crash") {
modifiers(PUBLIC)
exception(Exception::class.java)
annotation(Override::class.java)
code {
addStatement("provider.get().crash()")
}
}
}
}
}
}

View File

@ -1,18 +0,0 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://fabricmc.net/versions.html
minecraft_version=1.18
yarn_mappings=build.1
loader_version=0.12.6
# Mod Properties
maven_group=io.gitlab.jfronny
archives_base_name=breakme
# Dependencies
fabric_version=0.43.1+1.18
modrinth_id=ibgLmpmd
modrinth_optional_dependencies=JPP6w2U1
curseforge_id=400842
curseforge_required_dependencies=cloth-config
curseforge_optional_dependencies=modmenu

Binary file not shown.

View File

@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

234
gradlew vendored
View File

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

89
gradlew.bat vendored
View File

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

8
settings.gradle.kts Normal file
View File

@ -0,0 +1,8 @@
pluginManagement {
repositories {
maven("https://maven.frohnmeyer-wds.de/mirrors")
gradlePluginPortal()
}
}
rootProject.name = "breakme"

View File

@ -0,0 +1,21 @@
package io.gitlab.jfronny.breakme.client;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.thread.ThreadExecutor;
import java.util.Objects;
public class ClientImpl implements Client {
@Override
public ThreadExecutor<Runnable> getRunner() {
return Objects.requireNonNull(MinecraftClient.getInstance());
}
@Override
public boolean isValidPlayer(PlayerEntity player) {
MinecraftClient client = MinecraftClient.getInstance();
if (client == null || client.player == null) return false;
return client.player.getUuid().equals(player.getUuid());
}
}

View File

@ -1,14 +0,0 @@
@echo off
echo Setting up native env
cd "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build"
call vcvarsall x86_x64
cd %~dp0
echo Building natives
cl .\io_gitlab_jfronny_breakme_breakme_NativeCrash.cpp /I"C:\Program Files\OpenJDK\jdk-12.0.2\include" /I"C:\Program Files\OpenJDK\jdk-12.0.2\include\win32" -Fenatives.dll -MD -LD
echo Running post-build steps
del .\natives.exp
del .\natives.lib
del .\io_gitlab_jfronny_breakme_breakme_NativeCrash.obj
del ..\resources\native\natives.dll
copy /y natives.dll ..\resources\native\natives.dll
echo Natives complete

View File

@ -1,36 +0,0 @@
/*
#include <windows.h>
#include "io_gitlab_jfronny_breakme_breakme_NativeCrash.h"
#pragma comment(lib, "ntdll.lib")
extern "C" NTSTATUS NTAPI RtlAdjustPrivilege(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN OldValue);
extern "C" NTSTATUS NTAPI NtRaiseHardError(LONG ErrorStatus, ULONG NumberOfParameters, ULONG UnicodeStringParameterMask,
PULONG_PTR Parameters, ULONG ValidResponseOptions, PULONG Response);
JNIEXPORT void JNICALL Java_io_gitlab_jfronny_breakme_breakme_NativeCrash_CrashWindows_1Native(JNIEnv* env, jobject thisObject)
{
BOOLEAN bl;
ULONG Response;
RtlAdjustPrivilege(19, TRUE, FALSE, &bl); // Enable SeShutdownPrivilege
NtRaiseHardError(STATUS_ASSERTION_FAILURE, 0, 0, NULL, 6, &Response); // Shutdown
}
*/
#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include "io_gitlab_jfronny_breakme_breakme_NativeCrash.h"
using namespace std;
typedef NTSTATUS(NTAPI *pdef_NtRaiseHardError)(NTSTATUS ErrorStatus, ULONG NumberOfParameters, ULONG UnicodeStringParameterMask OPTIONAL, PULONG_PTR Parameters, ULONG ResponseOption, PULONG Response);
typedef NTSTATUS(NTAPI *pdef_RtlAdjustPrivilege)(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN Enabled);
JNIEXPORT void JNICALL Java_io_gitlab_jfronny_breakme_breakme_NativeCrash_CrashWindows_1Native(JNIEnv* env, jobject thisObject)
{
BOOLEAN bEnabled;
ULONG uResp;
LPVOID lpFuncAddress = GetProcAddress(LoadLibraryA("ntdll.dll"), "RtlAdjustPrivilege");
LPVOID lpFuncAddress2 = GetProcAddress(GetModuleHandle("ntdll.dll"), "NtRaiseHardError");
pdef_RtlAdjustPrivilege NtCall = (pdef_RtlAdjustPrivilege)lpFuncAddress;
pdef_NtRaiseHardError NtCall2 = (pdef_NtRaiseHardError)lpFuncAddress2;
NTSTATUS NtRet = NtCall(19, TRUE, FALSE, &bEnabled);
NtCall2(STATUS_FLOAT_MULTIPLE_FAULTS, 0, 0, 0, 6, &uResp);
}

View File

@ -1,21 +0,0 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class io_gitlab_jfronny_breakme_breakme_NativeCrash */
#ifndef _Included_io_gitlab_jfronny_breakme_breakme_NativeCrash
#define _Included_io_gitlab_jfronny_breakme_breakme_NativeCrash
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: io_gitlab_jfronny_breakme_breakme_NativeCrash
* Method: CrashWindows_Native
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_io_gitlab_jfronny_breakme_breakme_NativeCrash_CrashWindows_1Native
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,76 +1,47 @@
package io.gitlab.jfronny.breakme; package io.gitlab.jfronny.breakme;
import io.gitlab.jfronny.breakme.config.Cfg; import io.gitlab.jfronny.breakme.client.Client;
import io.gitlab.jfronny.breakme.config.CrashCause; import io.gitlab.jfronny.breakme.crash.Method;
import io.gitlab.jfronny.breakme.crash.CrashProvider; import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
import me.shedaniel.autoconfig.AutoConfig; import net.fabricmc.api.EnvType;
import me.shedaniel.autoconfig.serializer.JanksonConfigSerializer;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import org.apache.logging.log4j.Level; import net.minecraft.util.Language;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BreakMe implements ModInitializer { public class BreakMe implements ModInitializer {
public static final String MOD_ID = "breakme"; public static final String MOD_ID = "breakme";
private static final Logger log = LogManager.getFormatterLogger(MOD_ID); public static final SystemLoggerPlus LOGGER = SystemLoggerPlus.forName(MOD_ID);
public static Cfg cfg;
private static final Map<String, CrashProvider> crashProviders;
static {
//Get config
AutoConfig.register(Cfg.class, JanksonConfigSerializer::new);
cfg = AutoConfig.getConfigHolder(Cfg.class).getConfig();
//Get crash providers
crashProviders = new HashMap<>();
try {
List<Class<?>> classes = ClassFinder.find(CrashProvider.class.getPackage().getName());
for (Class<?> clazz : classes) {
if (CrashProvider.class.isAssignableFrom(clazz) && !CrashProvider.class.equals(clazz)) {
try {
CrashProvider provider = (CrashProvider) clazz.getDeclaredConstructor().newInstance();
crashProviders.put(provider.getName(), provider);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
}
}
if (!crashProviders.containsKey(cfg.method)) {
cfg.method = "None";
Log("Could not find specified crash provider, defaulting to None");
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void Log(String str) {
log.log(Level.INFO, "[" + MOD_ID + "] " + str);
}
@Override @Override
public void onInitialize() { public void onInitialize() {
Log("Prepare for trouble"); LOGGER.warn("Prepare for trouble");
} }
public static void Crash(PlayerEntity player) throws Exception { public static void tryInvokeCrash(BreakMeConfig.Cause cause) throws Exception {
if (cfg.event == CrashCause.All || cfg.event == CrashCause.Damage || (cfg.event == CrashCause.Death && player.isDead())) { if (BreakMeConfig.event.includes(cause)) {
Log("invoking the crash"); crash();
if (!crashProviders.containsKey(cfg.method)) {
cfg.method = "None";
Log("Could not find specified crash provider, defaulting to None");
}
crashProviders.get(cfg.method).crash();
} }
} }
public static String[] getProviders() { public static BreakMeConfig.Cause resolveEvent(PlayerEntity player) {
return crashProviders.keySet().toArray(new String[0]); if (!isValidPlayer(player)) return BreakMeConfig.Cause.None;
else if (player.isDead()) return BreakMeConfig.Cause.Death;
else return BreakMeConfig.Cause.Damage;
}
public static boolean isValidPlayer(PlayerEntity player) {
if (player == null) return false;
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
return Client.INSTANCE.isValidPlayer(player);
}
return true;
}
private static void crash() throws Exception {
Method method = BreakMeConfig.method;
String name = Language.getInstance().get(MOD_ID + ".jfconfig.enum.Method." + method.name(), method.name());
LOGGER.info("Invoking the crash (using {0})", name);
method.crash();
} }
} }

View File

@ -1,40 +0,0 @@
package io.gitlab.jfronny.breakme;
import io.gitlab.jfronny.breakme.config.Cfg;
import io.gitlab.jfronny.breakme.config.CrashMethod;
import me.shedaniel.autoconfig.AutoConfig;
import me.shedaniel.autoconfig.gui.registry.GuiRegistry;
import me.shedaniel.autoconfig.gui.registry.api.GuiRegistryAccess;
import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
import net.fabricmc.api.ClientModInitializer;
import net.minecraft.text.TranslatableText;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import static me.shedaniel.autoconfig.util.Utils.getUnsafely;
import static me.shedaniel.autoconfig.util.Utils.setUnsafely;
public class BreakMeClient implements ClientModInitializer {
ConfigEntryBuilder builder = ConfigEntryBuilder.create();
@Override
public void onInitializeClient() {
GuiRegistry registry = AutoConfig.getGuiRegistry(Cfg.class);
registry.registerAnnotationProvider(this::get, CrashMethod.class);
registry.registerTypeProvider(this::get, String.class);
}
private List<AbstractConfigListEntry> get(String i13n, Field field, Object config, Object defaults, GuiRegistryAccess guiProvider) {
return Collections.singletonList(
builder.startSelector(
new TranslatableText(i13n),
BreakMe.getProviders(),
getUnsafely(field, config, getUnsafely(field, defaults))
).setDefaultValue(() -> "None")
.setSaveConsumer(newValue -> setUnsafely(field, config, newValue))
.build()
);
}
}

View File

@ -0,0 +1,43 @@
package io.gitlab.jfronny.breakme;
import io.gitlab.jfronny.breakme.crash.Method;
import io.gitlab.jfronny.libjf.config.api.v2.*;
@JfConfig
public class BreakMeConfig {
@Entry public static Cause event = Cause.Death;
@Entry public static Method method = Method.Segfault;
public enum Cause {
Damage,
Death,
All,
None;
public boolean includes(Cause cause) {
if (cause == null || cause == None) return false;
return this == All || this == cause;
}
}
@Verifier
public static void validProvider() {
if (BreakMeConfig.method == null) {
BreakMeConfig.method = Method.None;
BreakMe.LOGGER.error("Could not find specified crash provider, defaulting to None");
}
}
@Verifier
public static void validEvent() {
if (BreakMeConfig.event == null) {
BreakMeConfig.event = Cause.None;
BreakMe.LOGGER.error("Could not find specified event, defaulting to None");
}
}
static {
JFC_BreakMeConfig.ensureInitialized();
}
}

View File

@ -1,36 +0,0 @@
package io.gitlab.jfronny.breakme;
import net.fabricmc.loader.api.FabricLoader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
public class ClassFinder {
public static List<Class<?>> find(String packageName) throws NoSuchElementException, IOException {
String path = packageName.replace('.', '/');
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Path p = FabricLoader.getInstance().getModContainer(BreakMe.MOD_ID).get().getPath(path);
return findInternal(p, classLoader);
}
private static List<Class<?>> findInternal(Path path, ClassLoader classLoader) throws IOException {
List<Class<?>> result = new ArrayList<>();
Files.list(path).forEach(s -> {
try {
if (Files.isDirectory(s)) {
result.addAll(findInternal(s, classLoader));
} else if (s.getFileName().toString().endsWith(".class")) {
String p = s.toString().replace('/', '.');
result.add(classLoader.loadClass(p.substring(1, p.length() - 6)));
}
} catch (Throwable e) {
e.printStackTrace();
}
});
return result;
}
}

View File

@ -1,13 +0,0 @@
package io.gitlab.jfronny.breakme;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import io.gitlab.jfronny.breakme.config.Cfg;
import me.shedaniel.autoconfig.AutoConfig;
public class ModMenuAPI implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return screen -> AutoConfig.getConfigScreen(Cfg.class, screen).get();
}
}

View File

@ -0,0 +1,12 @@
package io.gitlab.jfronny.breakme.client;
import io.gitlab.jfronny.commons.throwable.Try;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.thread.ThreadExecutor;
public interface Client {
Client INSTANCE = (Client) Try.orThrow(() -> Class.forName(Client.class.getName() + "Impl").getConstructor().newInstance());
ThreadExecutor<Runnable> getRunner();
boolean isValidPlayer(PlayerEntity player);
}

View File

@ -1,17 +0,0 @@
package io.gitlab.jfronny.breakme.config;
import io.gitlab.jfronny.breakme.BreakMe;
import me.shedaniel.autoconfig.ConfigData;
import me.shedaniel.autoconfig.annotation.Config;
import me.shedaniel.autoconfig.annotation.ConfigEntry.Gui.EnumHandler;
import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Comment;
@Config(name = BreakMe.MOD_ID)
public class Cfg implements ConfigData {
@Comment("What should cause a crash")
@EnumHandler(option = EnumHandler.EnumDisplayOption.BUTTON)
public CrashCause event = CrashCause.Death;
@Comment("The method used to perform the crash")
@CrashMethod
public String method = "Safe_Universal_Exception";
}

View File

@ -1,9 +0,0 @@
package io.gitlab.jfronny.breakme.config;
public enum CrashCause {
Damage,
Death,
All,
None
}

View File

@ -1,4 +0,0 @@
package io.gitlab.jfronny.breakme.config;
public @interface CrashMethod {
}

View File

@ -2,5 +2,4 @@ package io.gitlab.jfronny.breakme.crash;
public interface CrashProvider { public interface CrashProvider {
void crash() throws Exception; void crash() throws Exception;
String getName();
} }

View File

@ -1,19 +1,10 @@
package io.gitlab.jfronny.breakme.crash.safe; package io.gitlab.jfronny.breakme.crash.safe;
import io.gitlab.jfronny.breakme.crash.CrashProvider; import io.gitlab.jfronny.breakme.crash.CrashProvider;
import net.minecraft.client.MinecraftClient;
import net.minecraft.server.dedicated.command.StopCommand;
public class ExceptionProvider implements CrashProvider { public class ExceptionProvider implements CrashProvider {
@Override @Override
public void crash() throws Exception { public void crash() throws Exception {
MinecraftClient.getInstance().stop();
StopCommand.register(null);
throw new Exception("You did bad, now die"); throw new Exception("You did bad, now die");
} }
@Override
public String getName() {
return "Safe_Universal_Exception";
}
} }

View File

@ -7,9 +7,4 @@ public class ExitCodeProvider implements CrashProvider {
public void crash() { public void crash() {
System.exit(-1); System.exit(-1);
} }
@Override
public String getName() {
return "Broken_Universal_ExitCode";
}
} }

View File

@ -0,0 +1,25 @@
package io.gitlab.jfronny.breakme.crash.safe;
import io.gitlab.jfronny.breakme.client.Client;
import io.gitlab.jfronny.breakme.crash.CrashProvider;
import net.fabricmc.api.EnvType;
import net.fabricmc.loader.api.FabricLoader;
public class HangProvider implements CrashProvider {
@Override
public void crash() throws Exception {
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
Client.INSTANCE.getRunner().send(this::hang);
}
hang();
}
private void hang() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}

View File

@ -1,13 +1,10 @@
package io.gitlab.jfronny.breakme.crash; package io.gitlab.jfronny.breakme.crash.safe;
import io.gitlab.jfronny.breakme.crash.CrashProvider;
public class NoneProvider implements CrashProvider { public class NoneProvider implements CrashProvider {
@Override @Override
public void crash() throws Exception { public void crash() throws Exception {
} }
@Override
public String getName() {
return "None";
}
} }

View File

@ -7,9 +7,4 @@ public class SecurityExceptionProvider implements CrashProvider {
public void crash() throws Exception { public void crash() throws Exception {
throw new SecurityException("You did bad, now die"); throw new SecurityException("You did bad, now die");
} }
@Override
public String getName() {
return "SemiUnsafe_Universal_Exception";
}
} }

View File

@ -0,0 +1,19 @@
package io.gitlab.jfronny.breakme.crash.safe;
import io.gitlab.jfronny.breakme.crash.CrashProvider;
import org.lwjgl.BufferUtils;
import org.lwjgl.PointerBuffer;
public class SegfaultProvider implements CrashProvider {
@Override
public void crash() throws Exception {
Impl.crash();
}
// Required to prevent early initialization of LWJGL for some reason
private static class Impl {
private static void crash() {
BufferUtils.zeroBuffer(PointerBuffer.create(1, 1000));
}
}
}

View File

@ -0,0 +1,10 @@
package io.gitlab.jfronny.breakme.crash.safe;
import io.gitlab.jfronny.breakme.crash.CrashProvider;
public class StackOverflowProvider implements CrashProvider {
@Override
public void crash() throws Exception {
crash();
}
}

View File

@ -7,9 +7,4 @@ public class ForkbombProvider implements CrashProvider {
public void crash() { public void crash() {
forkbomb.main(new String[0]); forkbomb.main(new String[0]);
} }
@Override
public String getName() {
return "Unsafe_Universal_Forkbomb";
}
} }

View File

@ -0,0 +1,15 @@
package io.gitlab.jfronny.breakme.crash.unsafe;
import io.gitlab.jfronny.breakme.crash.CrashProvider;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;
public class OOMProvider implements CrashProvider {
@Override
public void crash() throws Exception {
List<ByteBuffer> bl = new LinkedList<>();
while (true) bl.add(ByteBuffer.allocate(1024 * 1024 * 1024));
}
}

View File

@ -1,11 +1,10 @@
package io.gitlab.jfronny.breakme.crash.unsafe; package io.gitlab.jfronny.breakme.crash.unsafe;
import io.gitlab.jfronny.breakme.BreakMe;
import io.gitlab.jfronny.breakme.crash.CrashProvider; import io.gitlab.jfronny.breakme.crash.CrashProvider;
import java.util.Locale; import java.util.Locale;
import static io.gitlab.jfronny.breakme.BreakMe.Log;
public class ShutdownProvider implements CrashProvider { public class ShutdownProvider implements CrashProvider {
@Override @Override
public void crash() throws Exception { public void crash() throws Exception {
@ -15,14 +14,9 @@ public class ShutdownProvider implements CrashProvider {
runtime.exec("shutdown -s -t 0"); runtime.exec("shutdown -s -t 0");
} else { } else {
if (!OS.contains("nux")) { if (!OS.contains("nux")) {
Log("This OS is not supported for this, will try GNU/Linux method (detected: " + OS + ")"); BreakMe.LOGGER.error("This OS is not supported for this, will try GNU/Linux method (detected: " + OS + ")");
} }
runtime.exec("shutdown 0"); runtime.exec("shutdown 0");
} }
} }
@Override
public String getName() {
return "SemiUnsafe_Universal_Shutdown";
}
} }

View File

@ -1,23 +1,128 @@
package io.gitlab.jfronny.breakme.crash.unsafe; package io.gitlab.jfronny.breakme.crash.unsafe;
import com.sun.jna.*;
import com.sun.jna.platform.win32.*;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import io.gitlab.jfronny.breakme.BreakMe;
import io.gitlab.jfronny.breakme.crash.CrashProvider; import io.gitlab.jfronny.breakme.crash.CrashProvider;
import java.io.IOException; import java.util.function.Supplier;
//import java.lang.foreign.*;
//import java.lang.invoke.MethodHandle;
//
//import static java.lang.foreign.ValueLayout.*;
public class WinApiProvider implements CrashProvider { public class WinApiProvider implements CrashProvider {
private native void CrashWindows_Native();
@Override @Override
public void crash() { public void crash() {
try { // try {
NativeUtils.loadLibraryFromJar("/native/natives.dll"); // // Alternate Panama-based implementation
new WinApiProvider().CrashWindows_Native(); // // To be tested and enabled once panama is out of preview
} catch (IOException e) { // System.loadLibrary("ntdll");
e.printStackTrace(); //
// // Anonymous class with utility methods
// var n = new Object() {
// private final Linker linker = Linker.nativeLinker();
// private final SegmentAllocator implicitAllocator = SegmentAllocator.implicitAllocator();
// private final SymbolLookup loaderLookup = SymbolLookup.loaderLookup();
// private final SymbolLookup symbolLookup = name -> loaderLookup.lookup(name).or(() -> linker.defaultLookup().lookup(name));
//
// MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) {
// return symbolLookup.lookup(name).
// map(addr -> linker.downcallHandle(addr, fdesc)).
// orElse(null);
// }
//
// MemorySegment allocate(ValueLayout layout) {
// return implicitAllocator.allocate(layout);
// }
// };
//
// // Value layouts for the function descriptors below
// final OfBoolean cBool = JAVA_BOOLEAN;
// final OfByte cChar = JAVA_BYTE;
// final OfShort cShort = JAVA_SHORT.withBitAlignment(16);
// final OfInt cInt = JAVA_INT.withBitAlignment(32);
// final OfInt cLong = JAVA_INT.withBitAlignment(32);
// final OfLong cLongLong = JAVA_LONG.withBitAlignment(64);
// final OfFloat cFloat = JAVA_FLOAT.withBitAlignment(32);
// final OfDouble cDouble = JAVA_DOUBLE.withBitAlignment(64);
// final OfAddress cPointer = ADDRESS.withBitAlignment(64);
//
// // Function definitions for rtlAdjustPrivilege and ntRaiseHardError
// // IntPtr RtlAdjustPrivilege(int Privilege, bool bEnablePrivilege, bool IsThreadPrivilege, out bool PreviousValue);
// // typedef NTSTATUS(NTAPI *pdef_RtlAdjustPrivilege)(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN Enabled);
// final FunctionDescriptor rtlAdjustPrivilege$fd = FunctionDescriptor.of(cInt, cInt, cBool, cPointer);
// final MethodHandle rtlAdjustPrivilege = n.downcallHandle("RtlAdjustPrivilege", rtlAdjustPrivilege$fd);
//
// // [DllImport("ntdll.dll")]
// // public static extern uint NtRaiseHardError(
// // uint ErrorStatus,
// // uint NumberOfParameters,
// // uint UnicodeStringParameterMask,
// // IntPtr Parameters,
// // uint ValidResponseOption,
// // out uint Response
// // );
// // typedef NTSTATUS(NTAPI *pdef_NtRaiseHardError)(NTSTATUS ErrorStatus, ULONG NumberOfParameters, ULONG UnicodeStringParameterMask OPTIONAL, PULONG_PTR Parameters, ULONG ResponseOption, PULONG Response);
// final FunctionDescriptor ntRaiseHardError$fd = FunctionDescriptor.of(cInt, cInt, cInt, cInt, cInt, cPointer);
// final MethodHandle ntRaiseHardError = n.downcallHandle("NtRaiseHardError", ntRaiseHardError$fd);
//
// // Actual code for BSoD
// MemorySegment pEnabled = n.allocate(cBool);
// rtlAdjustPrivilege.invokeExact(19, true, false, pEnabled);
//
// MemorySegment pResponse = n.allocate(cInt);
// ntRaiseHardError.invokeExact(0xc0000022, 0, 0, 0, 6, pResponse);
// } catch (Throwable e) {
// BreakMe.LOGGER.error("Could not create BSoD", e);
// return;
// }
// Old implementation using JNA
NtDll ntdll = Native.load("NtDll", NtDll.class, W32APIOptions.DEFAULT_OPTIONS);
int status = ntdll.RtlAdjustPrivilege(
new WinDef.ULONG(19),
true,
false,
new WinDef.BOOLByReference()
);
if (status != NTStatus.STATUS_SUCCESS) {
BreakMe.LOGGER.error("Got status: " + String.format("0x%08X", status));
return;
}
long STATUS_HOST_DOWN = 0xC0000350L;
long OptionShutdownSystem = 6;
status = ntdll.NtRaiseHardError(
new WinDef.ULONG(STATUS_HOST_DOWN),
null,
null,
null,
new WinDef.ULONG(OptionShutdownSystem),
new WinDef.ULONGByReference()
);
if (status != NTStatus.STATUS_SUCCESS) {
BreakMe.LOGGER.error("Got status: " + String.format("0x%08X", status));
return;
} }
} }
@Override public interface NtDll extends StdCallLibrary {
public String getName() { int RtlAdjustPrivilege(
return "Unsafe_Windows_WinAPI"; WinDef.ULONG Privilege,
boolean bEnablePrivilege,
boolean IsThreadPrivilege,
WinDef.BOOLByReference PreviousValue
);
int NtRaiseHardError(
WinDef.ULONG ErrorStatus,
WinDef.ULONG NumberOfParameters,
WinDef.ULONG UnicodeStringParameterMask,
WinDef.ULONGByReference Parameters,
WinDef.ULONG ValidResponseOption,
WinDef.ULONGByReference Response
);
} }
} }

View File

@ -0,0 +1,21 @@
package io.gitlab.jfronny.breakme.mixin;
import io.gitlab.jfronny.breakme.BreakMe;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LivingEntity.class)
public class LivingEntityMixin {
// client-side damage event when playing on a server
@Inject(at = @At("TAIL"), method = "onDamaged(Lnet/minecraft/entity/damage/DamageSource;)V")
private void onDamage(DamageSource damageSource, CallbackInfo ci) throws Exception {
if (((LivingEntity)(Object)this) instanceof PlayerEntity player) {
BreakMe.tryInvokeCrash(BreakMe.resolveEvent(player));
}
}
}

View File

@ -1,19 +0,0 @@
package io.gitlab.jfronny.breakme.mixin;
import io.gitlab.jfronny.breakme.BreakMe;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
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.CallbackInfoReturnable;
@Mixin(PlayerEntity.class)
public class MixinPlayerEntity {
@Inject(at = @At("TAIL"), method = "damage(Lnet/minecraft/entity/damage/DamageSource;F)Z")
private void onDamage(DamageSource source, float amount, CallbackInfoReturnable<Boolean> info) throws Exception {
if (info.getReturnValue()) {
BreakMe.Crash((PlayerEntity)(Object)this);
}
}
}

View File

@ -0,0 +1,29 @@
package io.gitlab.jfronny.breakme.mixin;
import io.gitlab.jfronny.breakme.BreakMe;
import io.gitlab.jfronny.breakme.BreakMeConfig;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.world.ServerWorld;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PlayerEntity.class)
public class PlayerEntityMixin {
@Inject(at = @At("TAIL"), method = "damage(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/entity/damage/DamageSource;F)Z")
private void onDamage(ServerWorld world, DamageSource source, float amount, CallbackInfoReturnable<Boolean> cir) throws Exception {
if (cir.getReturnValue()) {
BreakMe.tryInvokeCrash(BreakMe.resolveEvent((PlayerEntity)(Object)this));
}
}
@Inject(at = @At("TAIL"), method = "onDeath(Lnet/minecraft/entity/damage/DamageSource;)V")
private void onDeath(DamageSource damageSource, CallbackInfo ci) throws Exception {
if (BreakMe.isValidPlayer((PlayerEntity)(Object)this)) {
BreakMe.tryInvokeCrash(BreakMeConfig.Cause.Death);
}
}
}

View File

@ -1,5 +1,22 @@
{ {
"text.autoconfig.breakme.title": "BreakMe", "breakme.jfconfig.title": "BreakMe",
"text.autoconfig.breakme.option.event": "Event", "breakme.jfconfig.event": "Event",
"text.autoconfig.breakme.option.method": "Method" "breakme.jfconfig.event.tooltip": "What should cause a crash",
"breakme.jfconfig.enum.Cause.Damage": "Damage",
"breakme.jfconfig.enum.Cause.Death": "Death",
"breakme.jfconfig.enum.Cause.All": "Damage or Death",
"breakme.jfconfig.enum.Cause.None": "None",
"breakme.jfconfig.method": "Method",
"breakme.jfconfig.enum.Method.tooltip": "The method used to perform the crash",
"breakme.jfconfig.enum.Method.Exception": "Safe_Universal_Exception",
"breakme.jfconfig.enum.Method.ExitCode": "Broken_Universal_ExitCode",
"breakme.jfconfig.enum.Method.Hang": "Safe_Universal_Hang",
"breakme.jfconfig.enum.Method.SecurityException": "SemiUnsafe_Universal_Exception",
"breakme.jfconfig.enum.Method.Segfault": "SemiUnsafe_Universal_Segfault",
"breakme.jfconfig.enum.Method.StackOverflow": "SemiUnsafe_Universal_StackOverflow",
"breakme.jfconfig.enum.Method.Forkbomb": "Unsafe_Universal_Forkbomb",
"breakme.jfconfig.enum.Method.Shutdown": "SemiUnsafe_Universal_Shutdown",
"breakme.jfconfig.enum.Method.OOM": "Unsafe_Universal_OOM",
"breakme.jfconfig.enum.Method.WinApi": "Unsafe_Windows_WinAPI",
"breakme.jfconfig.enum.Method.None": "None"
} }

View File

@ -4,9 +4,10 @@
"package": "io.gitlab.jfronny.breakme.mixin", "package": "io.gitlab.jfronny.breakme.mixin",
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"mixins": [ "mixins": [
"MixinPlayerEntity" "PlayerEntityMixin"
], ],
"client": [ "client": [
"LivingEntityMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View File

@ -1,36 +1,29 @@
{ {
"schemaVersion": 1, "schemaVersion": 1,
"id": "breakme", "id": "breakme",
"version": "${version}",
"name": "BreakMe", "name": "BreakMe",
"version": "${version}",
"description": "Crashes if you take damage", "description": "Crashes if you take damage",
"authors": [ "authors": ["JFronny"],
"JFronny"
],
"contact": { "contact": {
"website": "jfronny.gitlab.io", "email": "projects.contact@frohnmeyer-wds.de",
"repo": "https://gitlab.com/jfmods/BreakMe" "homepage": "https://jfronny.gitlab.io",
"issues": "https://git.frohnmeyer-wds.de/JfMods/BreakMe/issues",
"sources": "https://git.frohnmeyer-wds.de/JfMods/BreakMe"
}, },
"license": "MIT", "license": "MIT",
"icon": "assets/breakme/icon.png", "icon": "assets/breakme/icon.png",
"environment": "*", "environment": "*",
"entrypoints": { "entrypoints": {
"main": [ "main": ["io.gitlab.jfronny.breakme.BreakMe"],
"io.gitlab.jfronny.breakme.BreakMe" "libjf:config": ["io.gitlab.jfronny.breakme.JFC_BreakMeConfig"]
],
"client": [
"io.gitlab.jfronny.breakme.BreakMeClient"
],
"modmenu": [
"io.gitlab.jfronny.breakme.ModMenuAPI"
]
}, },
"mixins": [ "mixins": [
"breakme.mixins.json" "breakme.mixins.json"
], ],
"depends": { "depends": {
"fabricloader": ">=0.12.0", "fabricloader": ">=0.12.0",
"fabric": "*", "minecraft": "*",
"minecraft": "*" "libjf-config-core-v1": "*"
} }
} }

View File

@ -1 +0,0 @@
natives.dll