Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
radstevee committed Oct 17, 2024
0 parents commit 8b2caab
Show file tree
Hide file tree
Showing 16 changed files with 535 additions and 0 deletions.
40 changes: 40 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# gradle

.gradle/
build/
out/
classes/

# eclipse

*.launch

# idea

.idea/
*.iml
*.ipr
*.iws

# vscode

.settings/
.vscode/
bin/
.classpath
.project

# macos

*.DS_Store

# fabric

run*/

# java

hs_err_*.log
replay_*.log
*.hprof
*.jfr
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2024 MC Brawls

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# inject
Inject is a simple server-side mod to allow developers to inject into
Netty easier.

HTTP example:
```kt
object MyEpicHttpInjector : HttpInjector() {
override fun isRelevant(ctx: InjectorContext, request: HttpRequest) = true
override fun intercept(ctx: ChannelHandlerContext, request: HttpRequest) = ctx.buildHttpBuffer {
writeStatusLine("1.1", 200, "OK")
writeText("Hello, from Minecraft!")
}
}

object MyMod : DedicatedServerModInitializer {
override fun onInitializeServer() {
MyEpicHttpInjector.register()
}
}
```

This will register an HTTP injector which will respond with `Hello, from Minecraft!`
to any HTTP request to the Minecraft port.

```bash
$ curl http://localhost:25565
Hello, from Minecraft!
```

## Usage
Add the andante repo to gradle:
```groovy
repositories {
maven {
name = "Andante"
url = "https://maven.andante.dev/releases/"
}
}
```

Add the dependency:
```groovy
dependencies {
include modImplementation("net.mcbrawls:inject:VERSION")
}
```

Replace `VERSION` with the latest version from the releases tab.
113 changes: 113 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm") version "2.0.21"
id("fabric-loom") version "1.7.1"
id("maven-publish")
}

version = project.property("mod_version") as String
group = project.property("maven_group") as String

base {
archivesName.set(project.property("archives_base_name") as String)
}
val targetJavaVersion = 21
java {
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
// if it is present.
// If you remove this line, sources will not be generated.
withSourcesJar()
}

loom {
splitEnvironmentSourceSets()

mods {
register("inject") {
sourceSet("main")
sourceSet("client")
}
}
}

repositories {
// Add repositories to retrieve artifacts from in here.
// You should only use this when depending on other mods because
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
}

dependencies {
// To change the versions see the gradle.properties file
minecraft("com.mojang:minecraft:${project.property("minecraft_version")}")
mappings("net.fabricmc:yarn:${project.property("yarn_mappings")}:v2")
modImplementation("net.fabricmc:fabric-loader:${project.property("loader_version")}")
modImplementation("net.fabricmc:fabric-language-kotlin:${project.property("kotlin_loader_version")}")

modImplementation("net.fabricmc.fabric-api:fabric-api:${project.property("fabric_version")}")
}

tasks.processResources {
inputs.property("version", project.version)
inputs.property("minecraft_version", project.property("minecraft_version"))
inputs.property("loader_version", project.property("loader_version"))
filteringCharset = "UTF-8"

filesMatching("fabric.mod.json") {
expand(
"version" to project.version,
"minecraft_version" to project.property("minecraft_version"),
"loader_version" to project.property("loader_version"),
"kotlin_loader_version" to project.property("kotlin_loader_version")
)
}
}

tasks.withType<JavaCompile>().configureEach {
// ensure that the encoding is set to UTF-8, no matter what the system default is
// this fixes some edge cases with special characters not displaying correctly
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
// If Javadoc is generated, this must be specified in that task too.
options.encoding = "UTF-8"
options.release.set(targetJavaVersion)
}

tasks.withType<KotlinCompile>().configureEach {
compilerOptions.jvmTarget.set(JvmTarget.fromTarget(targetJavaVersion.toString()))
}

tasks.jar {
from("LICENSE") {
rename { "${it}_${project.base.archivesName}" }
}
}
// configure the maven publication
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifactId = project.property("archives_base_name") as String
from(components["java"])
}
}

repositories {
val mavenUser = runCatching { System.getenv("MAVEN_USERNAME_ANDANTE") }.getOrNull()
val mavenPass = runCatching { System.getenv("MAVEN_PASSWORD_ANDANTE") }.getOrNull()

if (mavenUser == null || mavenPass == null) return@repositories

maven {
name = "Andante"
url = uri("https://maven.andante.dev/releases/")

credentials {
username = mavenUser
password = mavenPass
}
}
}
}
15 changes: 15 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://modmuss50.me/fabric.html
minecraft_version=1.21.1
yarn_mappings=1.21.1+build.3
loader_version=0.16.7
kotlin_loader_version=1.12.3+kotlin.2.0.21
# Mod Properties
mod_version=1.0
maven_group=net.mcbrawls
archives_base_name=inject
# Dependencies
# check this on https://modmuss50.me/fabric.html
fabric_version=0.106.0+1.21.1
1 change: 1 addition & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
8 changes: 8 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pluginManagement {
repositories {
maven("https://maven.fabricmc.net/") {
name = "Fabric"
}
gradlePluginPortal()
}
}
21 changes: 21 additions & 0 deletions src/main/java/net/mcbrawls/inject/mixin/ClientConnectionMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package net.mcbrawls.inject.mixin;

import io.netty.channel.ChannelPipeline;
import net.mcbrawls.inject.InjectMod;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.NetworkSide;
import net.minecraft.network.handler.PacketSizeLogger;
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(ClientConnection.class)
public class ClientConnectionMixin {
@Inject(method = "addHandlers", at = @At("TAIL"))
private static void addHandlers(ChannelPipeline pipeline, NetworkSide side, boolean local, PacketSizeLogger packetSizeLogger, CallbackInfo ci) {
var channel = pipeline.channel();

InjectMod.INSTANCE.getInjectors$inject().forEach(injector -> channel.pipeline().addFirst(injector));
}
}
13 changes: 13 additions & 0 deletions src/main/kotlin/net/mcbrawls/inject/InjectMod.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.mcbrawls.inject

import net.fabricmc.api.DedicatedServerModInitializer
import org.slf4j.LoggerFactory

object InjectMod : DedicatedServerModInitializer {
internal val injectors = mutableListOf<Injector>()
val LOGGER = LoggerFactory.getLogger("Inject")

override fun onInitializeServer() {
LOGGER.info("Inject initialising")
}
}
42 changes: 42 additions & 0 deletions src/main/kotlin/net/mcbrawls/inject/Injector.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package net.mcbrawls.inject

import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelDuplexHandler
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.ChannelHandlerContext

/**
* A Netty injector.
*/
@Sharable
abstract class Injector : ChannelDuplexHandler() {
/**
* Predicate for matching if this injector is relevant
* to the given context.
* @param ctx The context.
* @return true if it's relevant, false if not.
*/
abstract fun isRelevant(ctx: InjectorContext): Boolean

/**
* Gets executed on every channel read.
* @param ctx The context.
* @return true if the channel read was handled and should not get
* delegated to the superclass, false if it should be delegated to the superclass.
*/
abstract fun onRead(ctx: ChannelHandlerContext, buf: ByteBuf): Boolean

override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
val buf = msg as ByteBuf
val shouldDelegate = !onRead(ctx, buf)

if (shouldDelegate) super.channelRead(ctx, msg)
}

/**
* Registers this injector.
*/
fun register() {
InjectMod.injectors.add(this)
}
}
6 changes: 6 additions & 0 deletions src/main/kotlin/net/mcbrawls/inject/InjectorContext.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package net.mcbrawls.inject

import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelPipeline

data class InjectorContext(val pipeline: ChannelPipeline, val message: ByteBuf)
47 changes: 47 additions & 0 deletions src/main/kotlin/net/mcbrawls/inject/http/HttpByteBuf.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package net.mcbrawls.inject.http

import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import java.nio.charset.StandardCharsets

/**
* A custom [ByteBuf] used for sending HTTP responses using [HttpInterceptor].
* @param inner The inner byte buffer.
*/
class HttpByteBuf(val inner: ByteBuf) {
/**
* Writes the status line to the buffer.
* Format is as following:
* ```
* HTTP/{protocolVersion} {statusCode} {statusMessage} \n
* ```
*/
fun writeStatusLine(protocolVersion: String, statusCode: Int, statusMessage: String) {
inner.writeCharSequence("HTTP/$protocolVersion $statusCode $statusMessage\n", StandardCharsets.US_ASCII)
}

/**
* Writes an HTTP header to the buffer.
*/
fun writeHeader(header: String, value: String) {
inner.writeCharSequence("$header: $value\n", StandardCharsets.US_ASCII)
}

/**
* Writes text to the buffer.
*/
fun writeText(text: String) {
inner.writeCharSequence("\n" + text, StandardCharsets.US_ASCII)
}

/**
* Writes a byte array to the buffer.
*/
fun writeBytes(bytes: ByteArray) {
inner.writeCharSequence("\n", StandardCharsets.US_ASCII)
inner.writeBytes(bytes)
}
}

fun ChannelHandlerContext.httpBuffer() = HttpByteBuf(alloc().buffer())
inline fun ChannelHandlerContext.buildHttpBuffer(block: HttpByteBuf.() -> Unit) = httpBuffer().apply(block)
Loading

0 comments on commit 8b2caab

Please sign in to comment.