This commit is contained in:
parent
25c4d6e490
commit
79cea96292
@ -11,6 +11,12 @@ jobs:
|
||||
RUNNER_TOOL_CACHE: /toolcache
|
||||
REGISTRY: tuxpa.in
|
||||
IMAGE_ROOT: a/wynn
|
||||
strategy:
|
||||
matrix:
|
||||
options:
|
||||
name: ts
|
||||
context: ./ts
|
||||
file: ./ts/Dockerfile
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@ -25,13 +31,13 @@ jobs:
|
||||
- name: build and push typescript
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./ts
|
||||
file: ./ts/Dockerfile
|
||||
context: ${{ matrix.options.context }}
|
||||
file: ${{ matrix.options.file }}
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_ROOT }}/ts:cache
|
||||
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_ROOT }}/ts:cache,mode=max,image-manifest=true,oci-mediatypes=true,type=registry
|
||||
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_ROOT }}/${{matrix.options.name}}:cache
|
||||
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_ROOT }}/${{matrix.options.name}}:cache,mode=max,image-manifest=true,oci-mediatypes=true,type=registry
|
||||
tags: |
|
||||
${{env.REGISTRY}}/${{env.IMAGE_ROOT}}/ts:${{ gitea.ref_name }},
|
||||
${{env.REGISTRY}}/${{env.IMAGE_ROOT}}/ts:${{ gitea.head_ref || gitea.ref_name }}
|
||||
${{env.REGISTRY}}/${{env.IMAGE_ROOT}}/${{matrix.options.name}}:${{ gitea.ref_name }},
|
||||
${{env.REGISTRY}}/${{env.IMAGE_ROOT}}/${{matrix.options.name}}:${{ gitea.head_ref || gitea.ref_name }}
|
||||
|
||||
|
119
java/clientmod/.gitignore
vendored
Normal file
119
java/clientmod/.gitignore
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
# User-specific stuff
|
||||
.idea/
|
||||
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
Thumbs.db:encryptable
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
.gradle
|
||||
build/
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
**/build/
|
||||
|
||||
# Common working directory
|
||||
run/
|
||||
runs/
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
2
java/clientmod/LICENSE.txt
Normal file
2
java/clientmod/LICENSE.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Copyright (c) 2025
|
||||
All rights reserved.
|
116
java/clientmod/build.gradle.kts
Normal file
116
java/clientmod/build.gradle.kts
Normal file
@ -0,0 +1,116 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "2.1.10"
|
||||
kotlin("plugin.serialization") version "2.1.10"
|
||||
id("fabric-loom") version "1.10.1"
|
||||
id("maven-publish")
|
||||
}
|
||||
|
||||
version = project.property("mod_version") as String
|
||||
group = project.property("maven_group") as String
|
||||
|
||||
val ktor_version = "3.1.1"
|
||||
|
||||
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("wynnreporter") {
|
||||
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")}")
|
||||
|
||||
|
||||
// non minecraft-related dependencies
|
||||
implementation("io.ktor:ktor-client-core:$ktor_version")
|
||||
implementation("io.ktor:ktor-client-cio:$ktor_version")
|
||||
implementation("io.ktor:ktor-client-resources:$ktor_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
|
||||
}
|
||||
|
||||
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"])
|
||||
}
|
||||
}
|
||||
|
||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||
repositories {
|
||||
// Add repositories to publish to here.
|
||||
// Notice: This block does NOT have the same function as the block in the top level.
|
||||
// The repositories here will be used for publishing your artifact, not for
|
||||
// retrieving dependencies.
|
||||
}
|
||||
}
|
15
java/clientmod/gradle.properties
Normal file
15
java/clientmod/gradle.properties
Normal file
@ -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.4
|
||||
yarn_mappings=1.21.4+build.8
|
||||
loader_version=0.16.10
|
||||
kotlin_loader_version=1.13.1+kotlin.2.1.10
|
||||
# Mod Properties
|
||||
mod_version=1.0-SNAPSHOT
|
||||
maven_group=org.tux
|
||||
archives_base_name=clientmod
|
||||
# Dependencies
|
||||
# check this on https://modmuss50.me/fabric.html
|
||||
fabric_version=0.118.0+1.21.4
|
1
java/clientmod/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
1
java/clientmod/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1 @@
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
|
8
java/clientmod/settings.gradle.kts
Normal file
8
java/clientmod/settings.gradle.kts
Normal file
@ -0,0 +1,8 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven("https://maven.fabricmc.net/") {
|
||||
name = "Fabric"
|
||||
}
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package org.tux.wynnreporter.client
|
||||
|
||||
import client.kotlin.org.tux.wynnreporter.client.singleton.InventoryReader
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.fabricmc.api.ClientModInitializer
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import org.tux.wynnreporter.Wynnreporter
|
||||
import org.tux.wynnreporter.client.processors.InventoryProcessor
|
||||
import org.tux.wynnreporter.client.structs.InventoryPayload
|
||||
|
||||
class WynnreporterClient : ClientModInitializer {
|
||||
|
||||
private val inventoryPayloadChannel = Channel<InventoryPayload>()
|
||||
private val inventoryReader: InventoryReader = InventoryReader(inventoryPayloadChannel)
|
||||
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
override fun onInitializeClient() {
|
||||
Wynnreporter.LOGGER.info("initializing client")
|
||||
ClientTickEvents.END_CLIENT_TICK.register(this::onEndClientTick)
|
||||
val inventoryProcessor = InventoryProcessor(inventoryPayloadChannel)
|
||||
// can you tell i write golang lol
|
||||
runBlocking {
|
||||
GlobalScope.launch{
|
||||
inventoryProcessor.start()
|
||||
}
|
||||
}
|
||||
ClientLifecycleEvents.CLIENT_STARTED.register { client ->
|
||||
Wynnreporter.LOGGER.info("client starting")
|
||||
Wynnreporter.LOGGER.info("client started")
|
||||
}
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.register { client ->
|
||||
Wynnreporter.LOGGER.info("client stopping")
|
||||
inventoryPayloadChannel.close()
|
||||
Wynnreporter.LOGGER.info("client stopped")
|
||||
}
|
||||
}
|
||||
|
||||
fun onEndClientTick(client: MinecraftClient?) {
|
||||
inventoryReader.handle(client)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package org.tux.wynnreporter.client.processors
|
||||
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import org.tux.wynnreporter.Wynnreporter
|
||||
import org.tux.wynnreporter.client.structs.InventoryPayload
|
||||
|
||||
class InventoryProcessor (
|
||||
val invChannel: Channel<InventoryPayload>
|
||||
){
|
||||
suspend fun start() {
|
||||
for(item in invChannel) {
|
||||
Wynnreporter.LOGGER.info("got item {}", item)
|
||||
}
|
||||
Wynnreporter.LOGGER.info("inventory payload channel closed. exiting")
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package client.kotlin.org.tux.wynnreporter.client.singleton
|
||||
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.onFailure
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen
|
||||
import org.tux.wynnreporter.Wynnreporter
|
||||
import org.tux.wynnreporter.client.structs.InventoryPayload
|
||||
import org.tux.wynnreporter.client.structs.InventoryPayloadItem
|
||||
import java.util.*
|
||||
|
||||
|
||||
class InventoryReader(
|
||||
val invChannel: Channel<InventoryPayload>
|
||||
){
|
||||
private var previousScreen: Screen? = null
|
||||
|
||||
private fun tick(client: MinecraftClient, screen: Screen) {
|
||||
val containerScreen = screen as? GenericContainerScreen ?: return
|
||||
val inventory = containerScreen.screenHandler.inventory
|
||||
if(inventory.isEmpty) {
|
||||
return
|
||||
}
|
||||
|
||||
val itemList = mutableListOf<InventoryPayloadItem>()
|
||||
// iterate over size
|
||||
for(i in 0 until inventory.size()) {
|
||||
val stack= inventory.getStack(i)
|
||||
if(stack.isEmpty) {
|
||||
continue
|
||||
}
|
||||
val item = stack.item;
|
||||
val components = stack.components
|
||||
val componentMap = mutableMapOf<String, String>()
|
||||
components.forEach { component ->
|
||||
componentMap[component.type.toString()] = component.value.toString()
|
||||
}
|
||||
// create a copy to send to the channel so that we dont block main thread :)
|
||||
itemList.add(InventoryPayloadItem(
|
||||
item.name.toString(),
|
||||
stack.count,
|
||||
componentMap,
|
||||
))
|
||||
}
|
||||
val payload = InventoryPayload(
|
||||
client.player?.uuid ?: UUID(0,0),
|
||||
containerScreen.title.toString(),
|
||||
itemList,
|
||||
)
|
||||
invChannel.trySend(payload).onFailure { cause ->
|
||||
Wynnreporter.LOGGER.warn("failed to send inventory payload", cause)
|
||||
};
|
||||
}
|
||||
|
||||
fun handle(client: MinecraftClient?) {
|
||||
val screen: Screen? = client?.currentScreen
|
||||
// see if the screen changed
|
||||
if (screen == null || screen == previousScreen) {
|
||||
return
|
||||
}
|
||||
this.tick(client, screen)
|
||||
// screen didnt change, run callback
|
||||
this.previousScreen = screen
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.tux.wynnreporter.client.services
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.cio.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.plugins.*
|
||||
import io.ktor.client.plugins.resources.*
|
||||
import io.ktor.client.plugins.resources.Resources
|
||||
import io.ktor.resources.*
|
||||
import java.util.UUID
|
||||
|
||||
|
||||
|
||||
class ApiClient(val rootUrl: String) {
|
||||
|
||||
val client = HttpClient(CIO) {
|
||||
expectSuccess = true
|
||||
defaultRequest {
|
||||
url(rootUrl)
|
||||
}
|
||||
install(Resources)
|
||||
}
|
||||
|
||||
suspend fun RequestChallenge(uuid: UUID) {
|
||||
val response = client.get {
|
||||
url("/api/v1/ingame/challenge")
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package org.tux.wynnreporter.client.services.ApiClientSpec
|
||||
|
||||
import io.ktor.resources.*
|
||||
|
||||
@Resource("/api/v1")
|
||||
class ApiV1 {
|
||||
@Resource("ingame")
|
||||
class Ingame {
|
||||
@Resource("challenge")
|
||||
class Challenge(val parent:)
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.tux.wynnreporter.client.services.ApiClientSpec
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GetChallengeResponse()
|
@ -0,0 +1,8 @@
|
||||
package org.tux.wynnreporter.client.structs
|
||||
import java.util.UUID
|
||||
|
||||
data class InventoryPayload(
|
||||
val opener: UUID,
|
||||
val name: String,
|
||||
val items: List<InventoryPayloadItem>,
|
||||
)
|
@ -0,0 +1,7 @@
|
||||
package org.tux.wynnreporter.client.structs
|
||||
|
||||
data class InventoryPayloadItem(
|
||||
val itemName: String,
|
||||
val stackSize: Int,
|
||||
val components: Map<String, String>,
|
||||
)
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "org.tux.wynnreporter.mixin.client",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"client": [
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.tux.wynnreporter
|
||||
|
||||
import net.fabricmc.api.ModInitializer
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
class Wynnreporter : ModInitializer {
|
||||
|
||||
companion object {
|
||||
private const val MOD_ID: String = "wynnreporter"
|
||||
val LOGGER: Logger = LoggerFactory.getLogger(MOD_ID)
|
||||
}
|
||||
|
||||
override fun onInitialize() {
|
||||
LOGGER.info("initializing wynnreporter")
|
||||
}
|
||||
}
|
33
java/clientmod/src/main/resources/fabric.mod.json
Normal file
33
java/clientmod/src/main/resources/fabric.mod.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "wynnreporter",
|
||||
"version": "${version}",
|
||||
"name": "wynnreporter",
|
||||
"description": "",
|
||||
"authors": [],
|
||||
"contact": {},
|
||||
"license": "All-Rights-Reserved",
|
||||
"icon": "assets/wynnreporter/icon.png",
|
||||
"environment": "client",
|
||||
"entrypoints": {
|
||||
"client": [
|
||||
"org.tux.wynnreporter.client.WynnreporterClient"
|
||||
],
|
||||
"main": [
|
||||
"org.tux.wynnreporter.Wynnreporter"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"wynnreporter.mixins.json",
|
||||
{
|
||||
"config": "wynnreporter.client.mixins.json",
|
||||
"environment": "client"
|
||||
}
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=${loader_version}",
|
||||
"fabric-language-kotlin": ">=${kotlin_loader_version}",
|
||||
"fabric": "*",
|
||||
"minecraft": "${minecraft_version}"
|
||||
}
|
||||
}
|
11
java/clientmod/src/main/resources/wynnreporter.mixins.json
Normal file
11
java/clientmod/src/main/resources/wynnreporter.mixins.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "org.tux.wynnreporter.mixin",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"mixins": [
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
Binary file not shown.
@ -18,9 +18,11 @@
|
||||
"@temporalio/common": "^1.11.7",
|
||||
"@temporalio/worker": "^1.11.7",
|
||||
"@temporalio/workflow": "^1.11.7",
|
||||
"@ts-rest/core": "https://gitpkg.vercel.app/aidant/ts-rest/libs/ts-rest/core?feat-standard-schema",
|
||||
"@ts-rest/fastify": "https://gitpkg.vercel.app/aidant/ts-rest/libs/ts-rest/fastify?feat-standard-schema",
|
||||
"@types/node": "^22.13.4",
|
||||
"any-date-parser": "^2.0.3",
|
||||
"arktype": "2.0.4",
|
||||
"arktype": "2.1.1",
|
||||
"axios": "^1.7.9",
|
||||
"axios-cache-interceptor": "^1.6.2",
|
||||
"chrono-node": "^2.7.8",
|
||||
|
@ -60,7 +60,6 @@ export async function update_guild({
|
||||
created = EXCLUDED.created
|
||||
`
|
||||
const {total, ...rest} = parsed.members
|
||||
|
||||
for(const [rank_name, rank] of Object.entries(rest)){
|
||||
for(const [userName, member] of Object.entries(rank)) {
|
||||
await sql`insert into wynn_guild_members
|
||||
@ -71,7 +70,6 @@ export async function update_guild({
|
||||
joined_at = EXCLUDED.joined_at,
|
||||
contributed = EXCLUDED.contributed
|
||||
`
|
||||
|
||||
await sql`insert into minecraft_user
|
||||
(uid, name, server) values (${member.uuid}, ${userName}, ${member.server})
|
||||
on conflict (uid) do update set
|
||||
|
50
ts/src/apiserver/contract.ts
Normal file
50
ts/src/apiserver/contract.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { initContract } from "@ts-rest/core/src";
|
||||
import { type } from "arktype";
|
||||
|
||||
const con = initContract();
|
||||
|
||||
|
||||
const ingameauth = con.router({
|
||||
challenge: {
|
||||
description: "generate a challenge for the client to solve",
|
||||
method: "GET",
|
||||
path: "/challenge",
|
||||
responses: {
|
||||
200: type({
|
||||
challenge: "string.uuid",
|
||||
}),
|
||||
},
|
||||
query: type({
|
||||
uuid: "string.uuid",
|
||||
}),
|
||||
},
|
||||
solve: {
|
||||
description: "attempt to solve the challenge and get the token for the challenge",
|
||||
method: "POST",
|
||||
path: "/solve",
|
||||
body: type({
|
||||
challenge: "string.uuid",
|
||||
uuid: "string.uuid",
|
||||
}),
|
||||
responses: {
|
||||
200: type({
|
||||
success: "true",
|
||||
challenge: "string.uuid",
|
||||
uuid: "string.uuid",
|
||||
}),
|
||||
401: type({
|
||||
success: "false",
|
||||
reason: "string",
|
||||
}),
|
||||
},
|
||||
}
|
||||
}, {pathPrefix: "/ingame"})
|
||||
|
||||
export const api = con.router({
|
||||
"ingameauth": ingameauth,
|
||||
}, {pathPrefix: "/api/v1"})
|
||||
|
||||
export const contract = con.router({
|
||||
api: api
|
||||
})
|
||||
|
@ -1,7 +1,8 @@
|
||||
import {bot} from "#/bot"
|
||||
import {Bot, BotType} from "#/bot"
|
||||
import { ActivityTypes, ApplicationCommandOptionTypes, InteractionTypes } from "discordeno"
|
||||
import { InteractionType, MuxHandler, SlashHandler } from "./types"
|
||||
import { uuid4 } from "@temporalio/workflow"
|
||||
import { c } from "#/di"
|
||||
|
||||
|
||||
export const slashHandler = async (interaction: InteractionType, rootHandler: SlashHandler) => {
|
||||
@ -58,6 +59,7 @@ export const events = (rootHandler: SlashHandler) => {return {
|
||||
return
|
||||
},
|
||||
ready: async ({shardId}) => {
|
||||
const bot = await c.getAsync(Bot)
|
||||
await bot.gateway.editShardStatus(shardId, {
|
||||
status: 'online',
|
||||
activities: [
|
||||
@ -71,4 +73,4 @@ export const events = (rootHandler: SlashHandler) => {return {
|
||||
],
|
||||
})
|
||||
}
|
||||
} as typeof bot.events}
|
||||
} as BotType['events']}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import {bot} from "#/bot"
|
||||
import {BotType} from "#/bot"
|
||||
|
||||
export type BotEventsType = typeof bot.events
|
||||
export type InteractionHandler = NonNullable<typeof bot.events.interactionCreate>
|
||||
|
||||
export type BotEventsType = BotType['events']
|
||||
export type InteractionHandler = NonNullable<BotType['events']['interactionCreate']>
|
||||
export type InteractionType = Parameters<InteractionHandler>[0]
|
||||
|
||||
export type MuxHandler<T> = (interaction: InteractionType, params?: T) => Promise<any>
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { config } from "#/config";
|
||||
import { c } from "#/di";
|
||||
import { InjectionToken } from "@needle-di/core";
|
||||
|
||||
import {createBot, Intents} from "discordeno"
|
||||
|
||||
@ -45,28 +47,16 @@ export const createBotWithToken = (token: string) => createBot({
|
||||
}
|
||||
})
|
||||
|
||||
export const bot = createBot({
|
||||
intents: intents.reduce((acc, curr) => acc | curr, Intents.Guilds),
|
||||
token: config.DISCORD_TOKEN || "",
|
||||
desiredProperties: {
|
||||
interaction: {
|
||||
id: true,
|
||||
data: true,
|
||||
type: true,
|
||||
token: true,
|
||||
message: true,
|
||||
channelId: true,
|
||||
channel: true,
|
||||
guildId: true,
|
||||
guild: true,
|
||||
user: true,
|
||||
member: true,
|
||||
},
|
||||
message: {
|
||||
id: true,
|
||||
member: true,
|
||||
guildId: true,
|
||||
},
|
||||
export type BotType = ReturnType<typeof createBotWithToken>
|
||||
export const Bot = new InjectionToken<BotType>("DISCORD_BOT")
|
||||
c.bind({
|
||||
provide: Bot,
|
||||
async: true,
|
||||
useFactory: async () => {
|
||||
let token = config.DISCORD_TOKEN
|
||||
if(!token) {
|
||||
throw new Error('no discord token found. bot cant start');
|
||||
}
|
||||
return createBotWithToken(token)
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { Command } from 'clipanion';
|
||||
// di
|
||||
import "#/services/pg"
|
||||
import { DISCORD_GUILD_ID } from '#/constants';
|
||||
import { bot } from '#/bot';
|
||||
import { Bot } from '#/bot';
|
||||
import { events } from '#/bot/botevent/handler';
|
||||
import { SlashCommandHandler } from '#/bot/botevent/slash_commands';
|
||||
import { c } from '#/di';
|
||||
@ -18,6 +18,7 @@ export class BotCommand extends Command {
|
||||
throw new Error('no discord token found. bot cant start');
|
||||
}
|
||||
const rootHandler = await c.getAsync(SlashCommandHandler)
|
||||
const bot = await c.getAsync(Bot)
|
||||
bot.events = events(rootHandler.root())
|
||||
console.log('registring slash commands');
|
||||
await bot.rest.upsertGuildApplicationCommands(DISCORD_GUILD_ID, rootHandler.commands()).catch(console.error)
|
||||
|
@ -4,11 +4,8 @@ import { c } from '#/di';
|
||||
import { runMigrations } from '#/services/pg/migrations';
|
||||
|
||||
// di
|
||||
import "#/services/pg"
|
||||
import "#/services/temporal"
|
||||
|
||||
import { NativeConnection, Worker } from '@temporalio/worker';
|
||||
import { config } from '#/config';
|
||||
import * as activities from '../activities';
|
||||
import path from 'path';
|
||||
import { Client, ScheduleNotFoundError, ScheduleOptions, ScheduleOverlapPolicy } from '@temporalio/client';
|
||||
@ -16,6 +13,9 @@ import { workflowSyncAllGuilds, workflowSyncGuilds, workflowSyncOnline, workflow
|
||||
import { PG } from '#/services/pg';
|
||||
|
||||
|
||||
import { config } from '#/config';
|
||||
|
||||
|
||||
|
||||
const schedules: ScheduleOptions[] = [
|
||||
{
|
||||
|
58
ts/yarn.lock
58
ts/yarn.lock
@ -5,19 +5,19 @@ __metadata:
|
||||
version: 8
|
||||
cacheKey: 10c0
|
||||
|
||||
"@ark/schema@npm:0.39.0":
|
||||
version: 0.39.0
|
||||
resolution: "@ark/schema@npm:0.39.0"
|
||||
"@ark/schema@npm:0.42.0":
|
||||
version: 0.42.0
|
||||
resolution: "@ark/schema@npm:0.42.0"
|
||||
dependencies:
|
||||
"@ark/util": "npm:0.39.0"
|
||||
checksum: 10c0/8a279ac688218937ca5585670e6eb8f3bac9c3ccf5f1868e3223ff9f1edabe713e76b30715510606f154e8f0208cd2e1b6551fd947f6cfae309bd7a65cf6c315
|
||||
"@ark/util": "npm:0.42.0"
|
||||
checksum: 10c0/d0e93fc456d0ee835ad6fa70317202992d7ede0f847506ad61d7317ce9677f96731f2e2ab1380f8e372b1b3f6e0a95c76305a81eb0abf02184ee90fea719ac75
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@ark/util@npm:0.39.0":
|
||||
version: 0.39.0
|
||||
resolution: "@ark/util@npm:0.39.0"
|
||||
checksum: 10c0/0e5a580e0e238ef457c07aa68f9382ae34fae8ced93dddd5c3402bce9898b8372e2a2022327b9d234eab8adc7d9a347e731721d329049dad17be37c9257b05f8
|
||||
"@ark/util@npm:0.42.0":
|
||||
version: 0.42.0
|
||||
resolution: "@ark/util@npm:0.42.0"
|
||||
checksum: 10c0/7639c66aa876c475d66f41c8767e4977958293c5516e36cbd6541ce98421b091d6ec97455522e7a0361cfca5383991e4fbc40ccc3fd9bf701a0ac227561cccbc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -746,6 +746,30 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@ts-rest/core@https://gitpkg.vercel.app/aidant/ts-rest/libs/ts-rest/core?feat-standard-schema":
|
||||
version: 3.52.0
|
||||
resolution: "@ts-rest/core@https://gitpkg.vercel.app/aidant/ts-rest/libs/ts-rest/core?feat-standard-schema"
|
||||
peerDependencies:
|
||||
"@types/node": ^18.18.7 || >=20.8.4
|
||||
zod: ^3.24.0
|
||||
peerDependenciesMeta:
|
||||
"@types/node":
|
||||
optional: true
|
||||
zod:
|
||||
optional: true
|
||||
checksum: 10c0/fba55ca7d1a5161d3ec1af850c9c98d34efd1b4373ad8ca4108737c2d75fa11ef033da6e9cb657cd5078465c09ff6761c029053f9c59022075b8d3e128f298a5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@ts-rest/fastify@https://gitpkg.vercel.app/aidant/ts-rest/libs/ts-rest/fastify?feat-standard-schema":
|
||||
version: 3.52.0
|
||||
resolution: "@ts-rest/fastify@https://gitpkg.vercel.app/aidant/ts-rest/libs/ts-rest/fastify?feat-standard-schema"
|
||||
peerDependencies:
|
||||
fastify: ^4.0.0
|
||||
checksum: 10c0/8e8a31fda5a49c4fc976962df29129a24ad3c9c4896af38a6deb95bf60e36943c29bef56ff601bb63cab883d845095c7793ae266e92876cf74a7a05d238ba00f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/eslint-scope@npm:^3.7.7":
|
||||
version: 3.7.7
|
||||
resolution: "@types/eslint-scope@npm:3.7.7"
|
||||
@ -1116,13 +1140,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"arktype@npm:2.0.4":
|
||||
version: 2.0.4
|
||||
resolution: "arktype@npm:2.0.4"
|
||||
"arktype@npm:2.1.1":
|
||||
version: 2.1.1
|
||||
resolution: "arktype@npm:2.1.1"
|
||||
dependencies:
|
||||
"@ark/schema": "npm:0.39.0"
|
||||
"@ark/util": "npm:0.39.0"
|
||||
checksum: 10c0/2bff7326ffebedee74ada3456147a3adb833df939db0c48cb9a78e6aa433592cc1f1877999a2ed0559f1021b70ab1dfbdfa3a6eee2b52d0a5dd68e0249471acf
|
||||
"@ark/schema": "npm:0.42.0"
|
||||
"@ark/util": "npm:0.42.0"
|
||||
checksum: 10c0/6e416a61bbd6890fb589be222bf69b86b79145cda1a025fb87b6a78818629669a7cc8aadd6261b8d99e74d43e8858d959fcacdebd222341f97e73eefa3a39498
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1176,10 +1200,12 @@ __metadata:
|
||||
"@temporalio/common": "npm:^1.11.7"
|
||||
"@temporalio/worker": "npm:^1.11.7"
|
||||
"@temporalio/workflow": "npm:^1.11.7"
|
||||
"@ts-rest/core": "https://gitpkg.vercel.app/aidant/ts-rest/libs/ts-rest/core?feat-standard-schema"
|
||||
"@ts-rest/fastify": "https://gitpkg.vercel.app/aidant/ts-rest/libs/ts-rest/fastify?feat-standard-schema"
|
||||
"@types/node": "npm:^22.13.4"
|
||||
"@types/object-hash": "npm:^3"
|
||||
any-date-parser: "npm:^2.0.3"
|
||||
arktype: "npm:2.0.4"
|
||||
arktype: "npm:2.1.1"
|
||||
axios: "npm:^1.7.9"
|
||||
axios-cache-interceptor: "npm:^1.6.2"
|
||||
barrelsby: "npm:^2.8.1"
|
||||
|
Loading…
Reference in New Issue
Block a user