最初的提交
This commit is contained in:
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 CinemaMod Group
|
||||||
|
|
||||||
|
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.
|
||||||
49
META-INF/mods.toml
Normal file
49
META-INF/mods.toml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
modLoader="javafml" #mandatory
|
||||||
|
|
||||||
|
# Use NeoForge's FML loader range for 1.21.1
|
||||||
|
loaderVersion="[1,)" #mandatory
|
||||||
|
|
||||||
|
license="MIT"
|
||||||
|
|
||||||
|
issueTrackerURL="" #optional
|
||||||
|
|
||||||
|
[[mods]] #mandatory
|
||||||
|
|
||||||
|
modId="webdisplays" #mandatory
|
||||||
|
|
||||||
|
# Align mod version with 1.21.1 build
|
||||||
|
version="2.0.1-1.21.1" #mandatory
|
||||||
|
|
||||||
|
displayName="WebDisplays" #mandatory
|
||||||
|
|
||||||
|
displayURL="https://github.com/CinemaMod/webdisplays" #optional
|
||||||
|
|
||||||
|
logoFile= "" #optional
|
||||||
|
|
||||||
|
credits="" #optional
|
||||||
|
|
||||||
|
authors="GiantLuigi4, ds58, Mysticpasta1, montoyo, WaterPicker" #optional
|
||||||
|
|
||||||
|
description='''
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[dependencies.webdisplays]] #optional
|
||||||
|
modId="neoforge" #mandatory
|
||||||
|
mandatory=true #mandatory
|
||||||
|
versionRange="[21.1.0,)" #mandatory
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
||||||
|
|
||||||
|
[[dependencies.webdisplays]]
|
||||||
|
modId="minecraft"
|
||||||
|
mandatory=true
|
||||||
|
versionRange="[1.21.1]"
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
||||||
|
|
||||||
|
[[dependencies.webdisplays]]
|
||||||
|
modId="mcef"
|
||||||
|
mandatory=true
|
||||||
|
versionRange="[2.1.6-1.21.1, )"
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
||||||
49
META-INF/neoforge.mods.toml
Normal file
49
META-INF/neoforge.mods.toml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
modLoader="javafml" #mandatory
|
||||||
|
|
||||||
|
# Use NeoForge's FML loader range for 1.21.1
|
||||||
|
loaderVersion="[1,)" #mandatory
|
||||||
|
|
||||||
|
license="MIT"
|
||||||
|
|
||||||
|
issueTrackerURL="" #optional
|
||||||
|
|
||||||
|
[[mods]] #mandatory
|
||||||
|
|
||||||
|
modId="webdisplays" #mandatory
|
||||||
|
|
||||||
|
# Align mod version with 1.21.1 build
|
||||||
|
version="2.0.1-1.21.1" #mandatory
|
||||||
|
|
||||||
|
displayName="WebDisplays" #mandatory
|
||||||
|
|
||||||
|
displayURL="https://github.com/CinemaMod/webdisplays" #optional
|
||||||
|
|
||||||
|
logoFile= "" #optional
|
||||||
|
|
||||||
|
credits="" #optional
|
||||||
|
|
||||||
|
authors="GiantLuigi4, ds58, Mysticpasta1, montoyo, WaterPicker" #optional
|
||||||
|
|
||||||
|
description='''
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[dependencies.webdisplays]] #optional
|
||||||
|
modId="neoforge" #mandatory
|
||||||
|
mandatory=true #mandatory
|
||||||
|
versionRange="[21.1.0,)" #mandatory
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
||||||
|
|
||||||
|
[[dependencies.webdisplays]]
|
||||||
|
modId="minecraft"
|
||||||
|
mandatory=true
|
||||||
|
versionRange="[1.21.1]"
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
||||||
|
|
||||||
|
[[dependencies.webdisplays]]
|
||||||
|
modId="mcef"
|
||||||
|
mandatory=true
|
||||||
|
versionRange="[2.1.6-1.21.1, )"
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
||||||
54
README.md
Normal file
54
README.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# WebDisplays(NeoForge 1.21.1 适配版)
|
||||||
|
|
||||||
|
本仓库来源于原始项目并在本地克隆后进行适配与修复:
|
||||||
|
- 上游仓库:`https://github.com/CinemaMod/webdisplays.git`
|
||||||
|
- 本分支目标:适配 Minecraft 1.21.1(NeoForge)并在可用范围内修复关键问题
|
||||||
|
- 大量代码改动由多位 AI 大模型辅助完成(自动化迁移、代码生成、问题定位与修复)
|
||||||
|
|
||||||
|
## 当前状态
|
||||||
|
- 完成基础功能适配(屏幕方块、模型加载、基础网络消息、MinePad 使用流程等)
|
||||||
|
- 修复 MinePad 初次使用时 URL 为空导致的崩溃(自定义负载编码 NPE)
|
||||||
|
- 调整屏幕模型贴图加载逻辑(通过 `assets/webdisplays/atlases/blocks.json` 注册 `screen0..screen15` 贴图)
|
||||||
|
- 默认主页为 `https://git.lnkos.cn`(`CommonConfig.Browser.homepage`)
|
||||||
|
- 已验证可构建并产出 JAR(Windows,JDK 21,NeoGradle)
|
||||||
|
|
||||||
|
## 已知问题(进行中)
|
||||||
|
- 外置键盘(左/右部件)在某些朝向或交互下存在异常
|
||||||
|
- 屏幕边框/部分贴图在某些资源包或拼图场景下异常(已加入图集声明,但仍需进一步兼容性验证)
|
||||||
|
- 代码中存在一定数量的弃用/迁移警告(不影响构建,后续逐步清理)
|
||||||
|
|
||||||
|
## 构建环境与依赖
|
||||||
|
- JDK:`21`
|
||||||
|
- 构建:`Gradle Wrapper`(已内置)
|
||||||
|
- Mod 平台:`NeoForge 1.21.1`
|
||||||
|
- 建议依赖:`MCEF (com.cinemamod:mcef-neoforge)` 对应 1.21.1 版本
|
||||||
|
|
||||||
|
## 本地构建
|
||||||
|
在仓库根目录执行:
|
||||||
|
- Windows:`./gradlew.bat build -x test`
|
||||||
|
- 其他平台:`./gradlew build -x test`
|
||||||
|
构建成功后,JAR 位于 `build/libs/`。
|
||||||
|
|
||||||
|
## 安装与试用
|
||||||
|
- 将生成的 `webdisplays-*.jar` 放入 `mods/`
|
||||||
|
- 确保安装对应版本的 `NeoForge` 与 `MCEF`
|
||||||
|
- 启动 1.21.1 客户端,创建世界,放置屏幕方块进行验证
|
||||||
|
|
||||||
|
## 主要改动摘要
|
||||||
|
- 屏幕自定义模型:`ScreenModelLoader`/`ScreenBaker`
|
||||||
|
- 通过 `atlases/blocks.json` 将 `screen0..screen15` 注册至方块图集
|
||||||
|
- 自定义烘焙模型以实现屏幕边框/连接效果
|
||||||
|
- 网络与数据修复:
|
||||||
|
- MinePad URL 为空值编码导致崩溃修复(`C2SMessageMinepadUrl` 编码前对 `null` 处理)
|
||||||
|
- GUI 初始化对 `null` URL 防御式赋值,避免界面 NPE
|
||||||
|
|
||||||
|
## 贡献与致谢
|
||||||
|
- 原始项目与创意来源归上游仓库及其作者所有
|
||||||
|
- 本地适配工作由多位 AI 大模型参与完成,辅助完成迁移、修复与文档编写
|
||||||
|
- 欢迎提交 Issue/PR,共同完善 1.21.1 的适配与修复
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
- 许可证遵循上游仓库约定(详见本仓库 `LICENSE`)
|
||||||
|
|
||||||
|
---
|
||||||
|
说明:本项目仍在持续迭代阶段,优先确保基础功能在 1.21.1 可用,其它外围与兼容性问题会逐步修复与完善。
|
||||||
60
backup_old_config/build.gradle
Normal file
60
backup_old_config/build.gradle
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
plugins {
|
||||||
|
id 'net.neoforged.gradle.userdev' version '7.0.+'
|
||||||
|
id 'org.spongepowered.mixin' version '0.7.+'
|
||||||
|
id 'maven-publish'
|
||||||
|
}
|
||||||
|
|
||||||
|
var mod_version = project.mod_version
|
||||||
|
|
||||||
|
archivesBaseName = project.archives_base_name
|
||||||
|
version = mod_version
|
||||||
|
group = maven_group
|
||||||
|
|
||||||
|
java.toolchain.languageVersion = JavaLanguageVersion.of(java_version as int)
|
||||||
|
|
||||||
|
sourceSets.main.resources.srcDirs += 'src/generated/resources'
|
||||||
|
mixin.add sourceSets.main, "webdisplays.refmap.json"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = "cursemaven"
|
||||||
|
url = "https://www.cursemaven.com"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = 'mcef-releases'
|
||||||
|
url = 'https://mcef-download.cinemamod.com/repositories/releases/'
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = 'neoforged'
|
||||||
|
url = 'https://maven.neoforged.net/releases'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'net.neoforged:neoforge:21.1.203'
|
||||||
|
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
|
||||||
|
|
||||||
|
// useful for debugging performance problems
|
||||||
|
implementation "curse.maven:spark-361579:4381167"
|
||||||
|
// here because we need to manually open the VR keyboard
|
||||||
|
compileOnly "curse.maven:vivecraft-667903:4794431"
|
||||||
|
|
||||||
|
implementation("com.cinemamod:mcef-neoforge:2.1.6-1.21.1") {
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes([
|
||||||
|
"Specification-Title": "WebDisplays",
|
||||||
|
"Specification-Vendor": "CinemaMod Group",
|
||||||
|
"Specification-Version": "1",
|
||||||
|
"Implementation-Title": project.name,
|
||||||
|
"Implementation-Version": project.version,
|
||||||
|
"Implementation-Vendor": "CinemaMod Group",
|
||||||
|
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||||
|
"MixinConfigs": "webdisplays.mixins.json"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
15
backup_old_config/gradle.properties
Normal file
15
backup_old_config/gradle.properties
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Done to increase the memory available to gradle.
|
||||||
|
org.gradle.jvmargs = -Xmx8G
|
||||||
|
mod_version = 2.0.2-1.21.1
|
||||||
|
maven_group = com.cinemamod
|
||||||
|
archives_base_name = webdisplays
|
||||||
|
|
||||||
|
# NeoForge 1.21.1 configuration
|
||||||
|
minecraft_version = 1.21.1
|
||||||
|
neoforge_version = 21.1.203
|
||||||
|
java_version = 21
|
||||||
|
|
||||||
|
systemProp.http.proxyHost=127.0.0.1
|
||||||
|
systemProp.http.proxyPort=20803
|
||||||
|
systemProp.https.proxyHost=127.0.0.1
|
||||||
|
systemProp.https.proxyPort=20803
|
||||||
28
backup_old_config/settings.gradle
Normal file
28
backup_old_config/settings.gradle
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
maven {
|
||||||
|
name = 'NeoForged'
|
||||||
|
url = 'https://maven.neoforged.net/releases'
|
||||||
|
}
|
||||||
|
maven { url = 'https://maven.parchmentmc.org' } // Add this line
|
||||||
|
}
|
||||||
|
// resolutionStrategy {
|
||||||
|
// eachPlugin {
|
||||||
|
// switch (requested.id.toString()) {
|
||||||
|
// case "net.minecraftforge.gradle": {
|
||||||
|
// useModule("${requested.id}:ForgeGradle:${requested.version}")
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// case "org.spongepowered.mixin": {
|
||||||
|
// useModule("org.spongepowered:mixingradle:${requested.version}")
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
|
||||||
|
}
|
||||||
45
build.gradle
Normal file
45
build.gradle
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java-library'
|
||||||
|
id 'maven-publish'
|
||||||
|
id 'net.neoforged.gradle.userdev' version '7.0.192'
|
||||||
|
}
|
||||||
|
|
||||||
|
version = mod_version
|
||||||
|
group = mod_group_id
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = 'https://maven.neoforged.net/releases' }
|
||||||
|
maven {
|
||||||
|
name = "cursemaven"
|
||||||
|
url = "https://www.cursemaven.com"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = 'mcef-releases'
|
||||||
|
url = 'https://mcef-download.cinemamod.com/repositories/releases/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
base {
|
||||||
|
archivesName = mod_id
|
||||||
|
}
|
||||||
|
|
||||||
|
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "net.neoforged:neoforge:${neo_version}"
|
||||||
|
|
||||||
|
// Project dependencies
|
||||||
|
implementation "curse.maven:spark-361579:4381167"
|
||||||
|
compileOnly "curse.maven:vivecraft-667903:4794431"
|
||||||
|
|
||||||
|
implementation("com.cinemamod:mcef-neoforge:2.1.6-1.21.1") {
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Improve compiler diagnostics to speed up fixing API changes
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
options.compilerArgs += ['-Xdiags:verbose', '-Xlint:deprecation', '-Xlint:unchecked']
|
||||||
|
}
|
||||||
1
cursors.piskel
Normal file
1
cursors.piskel
Normal file
File diff suppressed because one or more lines are too long
39
gradle.properties
Normal file
39
gradle.properties
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
||||||
|
org.gradle.jvmargs=-Xmx4G
|
||||||
|
org.gradle.daemon=true
|
||||||
|
org.gradle.parallel=true
|
||||||
|
org.gradle.caching=true
|
||||||
|
org.gradle.configuration-cache=true
|
||||||
|
|
||||||
|
#read more on this at https://github.com/neoforged/NeoGradle/blob/NG_7.0/README.md#apply-parchment-mappings
|
||||||
|
# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started
|
||||||
|
neogradle.subsystems.parchment.minecraftVersion=1.21.1
|
||||||
|
neogradle.subsystems.parchment.mappingsVersion=2024.11.17
|
||||||
|
|
||||||
|
# Environment Properties
|
||||||
|
# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge
|
||||||
|
# The Minecraft version must agree with the Neo version to get a valid artifact
|
||||||
|
minecraft_version=1.21.1
|
||||||
|
# The Minecraft version range can use any release version of Minecraft as bounds.
|
||||||
|
minecraft_version_range=[1.21.1]
|
||||||
|
# The Neo version must agree with the Minecraft version to get a valid artifact
|
||||||
|
neo_version=21.1.213
|
||||||
|
# The loader version range can only use the major version of FML as bounds
|
||||||
|
loader_version_range=[1,)
|
||||||
|
|
||||||
|
## Mod Properties
|
||||||
|
|
||||||
|
# The unique mod identifier for the mod. Must be lowercase in English locale.
|
||||||
|
mod_id=webdisplays
|
||||||
|
# The human-readable display name for the mod.
|
||||||
|
mod_name=WebDisplays
|
||||||
|
# The license of the mod.
|
||||||
|
mod_license=LGPL-3.0
|
||||||
|
# The mod version.
|
||||||
|
mod_version=1.1
|
||||||
|
# The group ID for the mod.
|
||||||
|
mod_group_id=net.montoyo.wd
|
||||||
|
# The authors of the mod.
|
||||||
|
mod_authors=montoyo, CinemaMod Group
|
||||||
|
# The description of the mod.
|
||||||
|
mod_description=A Minecraft mod that adds web displays to the game using MCEF (Minecraft Chromium Embedded Framework).
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
164
gradlew
vendored
Normal file
164
gradlew
vendored
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn ( ) {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die ( ) {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||||
|
if $cygwin ; then
|
||||||
|
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >&-
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >&-
|
||||||
|
|
||||||
|
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" = "false" -a "$darwin" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||||
|
function splitJvmOpts() {
|
||||||
|
JVM_OPTS=("$@")
|
||||||
|
}
|
||||||
|
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||||
|
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||||
90
gradlew.bat
vendored
Normal file
90
gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
@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
|
||||||
|
|
||||||
|
@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=
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@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 init
|
||||||
|
|
||||||
|
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 init
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windowz variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
goto execute
|
||||||
|
|
||||||
|
:4NT_args
|
||||||
|
@rem Get arguments from the 4NT Shell from JP Software
|
||||||
|
set CMD_LINE_ARGS=%$
|
||||||
|
|
||||||
|
: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 %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
: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
|
||||||
10
settings.gradle
Normal file
10
settings.gradle
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
maven { url = 'https://maven.neoforged.net/releases' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
|
||||||
|
}
|
||||||
148
src/main/java/net/montoyo/wd/SharedProxy.java
Normal file
148
src/main/java/net/montoyo/wd/SharedProxy.java
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd;
|
||||||
|
|
||||||
|
import com.cinemamod.mcef.MCEF;
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.neoforged.neoforge.server.ServerLifecycleHooks;
|
||||||
|
import net.montoyo.wd.core.HasAdvancement;
|
||||||
|
import net.montoyo.wd.core.JSServerRequest;
|
||||||
|
import net.montoyo.wd.data.GuiData;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.ScreenData;
|
||||||
|
import net.montoyo.wd.utilities.*;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector2i;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.data.Rotation;
|
||||||
|
import net.montoyo.wd.utilities.serialization.NameUUIDPair;
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class SharedProxy {
|
||||||
|
public void preInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
MCEF.scheduleForInit((cef) -> onCefInit());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onCefInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
public Level getWorld(ResourceKey<Level> dim) {
|
||||||
|
return getServer().getLevel(dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockGetter getWorld(IPayloadContext context) {
|
||||||
|
if (context.player() != null) return context.player().level();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enqueue(Runnable r) {
|
||||||
|
ServerLifecycleHooks.getCurrentServer().addTickable(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayGui(GuiData data) {
|
||||||
|
Log.error("Called SharedProxy.displayGui() on server side...");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void trackScreen(ScreenBlockEntity tes, boolean track) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAutocompleteResult(NameUUIDPair pairs[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameProfile[] getOnlineGameProfiles() {
|
||||||
|
return ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers().stream().map(Player::getGameProfile).toArray(GameProfile[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void screenUpdateResolutionInGui(Vector3i pos, BlockSide side, Vector2i res) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void screenUpdateRotationInGui(Vector3i pos, BlockSide side, Rotation rot) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void screenUpdateAutoVolumeInGui(Vector3i pos, BlockSide side, boolean av) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displaySetPadURLGui(ItemStack is, String padURL) {
|
||||||
|
Log.error("Called SharedProxy.displaySetPadURLGui() on server side...");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openMinePadGui(UUID padId) {
|
||||||
|
Log.error("Called SharedProxy.openMinePadGui() on server side...");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleJSResponseSuccess(int reqId, JSServerRequest type, byte[] data) {
|
||||||
|
Log.error("Called SharedProxy.handleJSResponseSuccess() on server side...");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleJSResponseError(int reqId, JSServerRequest type, int errCode, String err) {
|
||||||
|
Log.error("Called SharedProxy.handleJSResponseError() on server side...");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public HasAdvancement hasClientPlayerAdvancement(@Nonnull ResourceLocation rl) {
|
||||||
|
return HasAdvancement.DONT_KNOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MinecraftServer getServer() {
|
||||||
|
return ServerLifecycleHooks.getCurrentServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMiniservClientPort(int port) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startMiniservClient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMiniservDisabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeGui(BlockPos bp, BlockSide bs) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderRecipes() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShiftDown() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double distanceTo(ScreenBlockEntity tes, Vec3 position) {
|
||||||
|
double dist = Double.POSITIVE_INFINITY;
|
||||||
|
for (int i = 0; i < tes.screenCount(); i++) {
|
||||||
|
ScreenData scrn = tes.getScreen(i);
|
||||||
|
|
||||||
|
Vector3d pos = new Vector3d(
|
||||||
|
scrn.side.right.x * scrn.size.x / 2d + scrn.size.y * scrn.side.up.x / 2d,
|
||||||
|
scrn.side.right.y * scrn.size.x / 2d + scrn.size.y * scrn.side.up.y / 2d,
|
||||||
|
scrn.side.right.z * scrn.size.x / 2d + scrn.size.y * scrn.side.up.z / 2d
|
||||||
|
).add(tes.getBlockPos().getX(), tes.getBlockPos().getY(), tes.getBlockPos().getZ());
|
||||||
|
|
||||||
|
double dist2 = position.distanceToSqr(pos.x, pos.y, pos.z);
|
||||||
|
dist = Math.min(dist, dist2);
|
||||||
|
}
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
420
src/main/java/net/montoyo/wd/WebDisplays.java
Normal file
420
src/main/java/net/montoyo/wd/WebDisplays.java
Normal file
@@ -0,0 +1,420 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.advancements.Advancement;
|
||||||
|
import net.minecraft.advancements.AdvancementHolder;
|
||||||
|
import net.minecraft.advancements.CriteriaTriggers;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.neoforged.bus.api.IEventBus;
|
||||||
|
import net.neoforged.bus.api.SubscribeEvent;
|
||||||
|
import net.neoforged.fml.ModList;
|
||||||
|
import net.neoforged.fml.common.Mod;
|
||||||
|
import net.neoforged.fml.ModLoadingContext;
|
||||||
|
import net.neoforged.fml.loading.FMLEnvironment;
|
||||||
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
|
import net.neoforged.neoforge.event.ServerChatEvent;
|
||||||
|
import net.neoforged.neoforge.event.entity.item.ItemTossEvent;
|
||||||
|
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
|
||||||
|
import net.neoforged.neoforge.event.level.LevelEvent;
|
||||||
|
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
|
||||||
|
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.montoyo.wd.client.ClientProxy;
|
||||||
|
import net.montoyo.wd.client.gui.camera.KeyboardCamera;
|
||||||
|
import net.montoyo.wd.config.ClientConfig;
|
||||||
|
import net.montoyo.wd.config.CommonConfig;
|
||||||
|
import net.montoyo.wd.controls.ScreenControlRegistry;
|
||||||
|
import net.montoyo.wd.core.*;
|
||||||
|
import net.montoyo.wd.miniserv.server.Server;
|
||||||
|
import net.montoyo.wd.net.WDNetworkRegistry;
|
||||||
|
import net.montoyo.wd.net.client_bound.S2CMessageServerInfo;
|
||||||
|
import net.montoyo.wd.registry.BlockRegistry;
|
||||||
|
import net.montoyo.wd.registry.ItemRegistry;
|
||||||
|
import net.montoyo.wd.registry.TileRegistry;
|
||||||
|
import net.montoyo.wd.registry.WDTabs;
|
||||||
|
import net.montoyo.wd.utilities.DistSafety;
|
||||||
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
import net.montoyo.wd.utilities.serialization.Util;
|
||||||
|
import net.montoyo.wd.data.WDDataComponents;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Mod("webdisplays")
|
||||||
|
public class WebDisplays {
|
||||||
|
public static final String MOD_ID = "webdisplays";
|
||||||
|
public static WebDisplays INSTANCE;
|
||||||
|
|
||||||
|
public static SharedProxy PROXY = null;
|
||||||
|
|
||||||
|
public static final ResourceLocation ADV_PAD_BREAK = ResourceLocation.fromNamespaceAndPath("webdisplays", "pad_break");
|
||||||
|
public static final String BLACKLIST_URL = "mod://webdisplays/blacklisted.html";
|
||||||
|
public static final Gson GSON = new Gson();
|
||||||
|
|
||||||
|
//Sounds
|
||||||
|
public SoundEvent soundTyping;
|
||||||
|
public SoundEvent soundUpgradeAdd;
|
||||||
|
public SoundEvent soundUpgradeDel;
|
||||||
|
public SoundEvent soundScreenCfg;
|
||||||
|
public SoundEvent soundServer;
|
||||||
|
public SoundEvent soundIronic;
|
||||||
|
|
||||||
|
//Criterions
|
||||||
|
public WDCriterion criterionPadBreak;
|
||||||
|
public WDCriterion criterionUpgradeScreen;
|
||||||
|
public WDCriterion criterionLinkPeripheral;
|
||||||
|
public WDCriterion criterionKeyboardCat;
|
||||||
|
|
||||||
|
//Config
|
||||||
|
public static final double PAD_RATIO = 59.0 / 30.0;
|
||||||
|
public double padResX;
|
||||||
|
public double padResY;
|
||||||
|
private int lastPadId = 0;
|
||||||
|
public double unloadDistance2;
|
||||||
|
public double loadDistance2;
|
||||||
|
public int miniservPort;
|
||||||
|
public long miniservQuota;
|
||||||
|
public float ytVolume;
|
||||||
|
public float avDist100;
|
||||||
|
public float avDist0;
|
||||||
|
|
||||||
|
// mod detection
|
||||||
|
private boolean hasOC;
|
||||||
|
private boolean hasCC;
|
||||||
|
|
||||||
|
public WebDisplays() {
|
||||||
|
INSTANCE = this;
|
||||||
|
if(FMLEnvironment.dist.isClient()) {
|
||||||
|
PROXY = DistSafety.createProxy();
|
||||||
|
} else {
|
||||||
|
PROXY = new SharedProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FMLEnvironment.dist.isClient()) {
|
||||||
|
// proxies are annoying, so from now on, I'mma be just registering stuff in here
|
||||||
|
ModLoadingContext.get().getActiveContainer().getEventBus().addListener(ClientProxy::onKeybindRegistry);
|
||||||
|
ModLoadingContext.get().getActiveContainer().getEventBus().addListener(ClientProxy::onClientSetup);
|
||||||
|
ModLoadingContext.get().getActiveContainer().getEventBus().addListener(ClientProxy::onModelRegistryEvent);
|
||||||
|
// ClientProxy registers instance event handlers in preInit();
|
||||||
|
// RenderHighlightEvent.Block is handled via ClientProxy#onDrawSelection (instance)
|
||||||
|
NeoForge.EVENT_BUS.addListener(KeyboardCamera::updateCamera);
|
||||||
|
NeoForge.EVENT_BUS.addListener(KeyboardCamera::gameTick);
|
||||||
|
ClientConfig.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CommonConfig.init();
|
||||||
|
|
||||||
|
//Criterions
|
||||||
|
criterionPadBreak = new WDCriterion();
|
||||||
|
criterionUpgradeScreen = new WDCriterion();
|
||||||
|
criterionLinkPeripheral = new WDCriterion();
|
||||||
|
criterionKeyboardCat = new WDCriterion();
|
||||||
|
|
||||||
|
IEventBus bus = ModLoadingContext.get().getActiveContainer().getEventBus();
|
||||||
|
bus.addListener(WDNetworkRegistry::register);
|
||||||
|
// Register custom advancement triggers at the correct time
|
||||||
|
bus.addListener(this::onRegisterTriggers);
|
||||||
|
WDNetworkRegistry.init();
|
||||||
|
SOUNDS.register(bus);
|
||||||
|
onRegisterSounds();
|
||||||
|
WDTabs.init(bus);
|
||||||
|
BlockRegistry.init(bus);
|
||||||
|
ItemRegistry.init(bus);
|
||||||
|
TileRegistry.init(bus);
|
||||||
|
WDDataComponents.DATA_COMPONENTS.register(bus);
|
||||||
|
WDDCapability.ATTACHMENT_TYPES.register(bus);
|
||||||
|
|
||||||
|
PROXY.preInit();
|
||||||
|
|
||||||
|
NeoForge.EVENT_BUS.register(this);
|
||||||
|
|
||||||
|
//Other things
|
||||||
|
PROXY.init();
|
||||||
|
|
||||||
|
PROXY.postInit();
|
||||||
|
hasOC = ModList.get().isLoaded("opencomputers");
|
||||||
|
hasCC = ModList.get().isLoaded("computercraft");
|
||||||
|
|
||||||
|
/* if(hasCC) {
|
||||||
|
try {
|
||||||
|
//We have to do this because the "register" method might be stripped out if CC isn't loaded
|
||||||
|
CCPeripheralProvider.class.getMethod("register").invoke(null);
|
||||||
|
} catch(Throwable t) {
|
||||||
|
Log.error("ComputerCraft was found, but WebDisplays wasn't able to register its CC Interface Peripheral");
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
if (!FMLEnvironment.production) {
|
||||||
|
ScreenControlRegistry.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register custom advancement triggers via registry event to avoid freeze
|
||||||
|
private void onRegisterTriggers(final net.neoforged.neoforge.registries.RegisterEvent event) {
|
||||||
|
event.register(Registries.TRIGGER_TYPE,
|
||||||
|
ResourceLocation.fromNamespaceAndPath(MOD_ID, "pad_break"),
|
||||||
|
() -> criterionPadBreak);
|
||||||
|
event.register(Registries.TRIGGER_TYPE,
|
||||||
|
ResourceLocation.fromNamespaceAndPath(MOD_ID, "upgrade_screen"),
|
||||||
|
() -> criterionUpgradeScreen);
|
||||||
|
event.register(Registries.TRIGGER_TYPE,
|
||||||
|
ResourceLocation.fromNamespaceAndPath(MOD_ID, "link_peripheral"),
|
||||||
|
() -> criterionLinkPeripheral);
|
||||||
|
event.register(Registries.TRIGGER_TYPE,
|
||||||
|
ResourceLocation.fromNamespaceAndPath(MOD_ID, "keyboard_cat"),
|
||||||
|
() -> criterionKeyboardCat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRegisterSounds() {
|
||||||
|
soundTyping = registerSound("keyboard_type");
|
||||||
|
soundUpgradeAdd = registerSound("upgrade_add");
|
||||||
|
soundUpgradeDel = registerSound("upgrade_del");
|
||||||
|
soundScreenCfg = registerSound("screencfg_open");
|
||||||
|
soundServer = registerSound("server");
|
||||||
|
soundIronic = registerSound("ironic");
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<ResourceKey<Level>> serverStartedDimensions = new ArrayList<>();
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onWorldLoad(LevelEvent.Load ev) {
|
||||||
|
if (ev.getLevel() instanceof Level level) {
|
||||||
|
if (ev.getLevel().isClientSide() || level.dimension() != Level.OVERWORLD)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Path worldDir = Objects.requireNonNull(ev.getLevel().getServer()).getServerDirectory();
|
||||||
|
Path f = worldDir.resolve("wd_next.txt");
|
||||||
|
|
||||||
|
if (Files.exists(f)) {
|
||||||
|
try {
|
||||||
|
BufferedReader br = Files.newBufferedReader(f);
|
||||||
|
String idx = br.readLine();
|
||||||
|
Util.silentClose(br);
|
||||||
|
|
||||||
|
if (idx == null)
|
||||||
|
throw new RuntimeException("Seems like the file is empty (1)");
|
||||||
|
|
||||||
|
idx = idx.trim();
|
||||||
|
if (idx.isEmpty())
|
||||||
|
throw new RuntimeException("Seems like the file is empty (2)");
|
||||||
|
|
||||||
|
lastPadId = Integer.parseInt(idx); //This will throw NumberFormatException if it goes wrong
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Log.warningEx("Could not read last minePad ID from %s. I'm afraid this might break all minePads.", t, f.toAbsolutePath().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (miniservPort != 0) {
|
||||||
|
Server sv = Server.getInstance();
|
||||||
|
|
||||||
|
if(!serverStartedDimensions.contains(level.dimension())) {
|
||||||
|
sv.setPort(miniservPort);
|
||||||
|
sv.setDirectory(worldDir.resolve("wd_filehost").toFile());
|
||||||
|
sv.start();
|
||||||
|
serverStartedDimensions.add(level.dimension());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onWorldLeave(LevelEvent.Unload ev) throws IOException {
|
||||||
|
if(ev.getLevel() instanceof Level level) {
|
||||||
|
if (ev.getLevel().isClientSide() || level.dimension() != Level.OVERWORLD)
|
||||||
|
return;
|
||||||
|
Server sw = Server.getInstance();
|
||||||
|
sw.stopServer();
|
||||||
|
serverStartedDimensions.remove(level.dimension());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onWorldSave(LevelEvent.Save ev) {
|
||||||
|
if(ev.getLevel() instanceof Level level) {
|
||||||
|
if (ev.getLevel().isClientSide() || level.dimension() != Level.OVERWORLD)
|
||||||
|
return;
|
||||||
|
Path f = Objects.requireNonNull(ev.getLevel().getServer()).getServerDirectory().resolve("wd_next.txt");
|
||||||
|
|
||||||
|
try {
|
||||||
|
BufferedWriter bw = Files.newBufferedWriter(f);
|
||||||
|
bw.write("" + lastPadId + "\n");
|
||||||
|
Util.silentClose(bw);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Log.warningEx("Could not save last minePad ID (%d) to %s. I'm afraid this might break all minePads.", t, lastPadId, f.toAbsolutePath().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onToss(ItemTossEvent ev) {
|
||||||
|
if(!ev.getEntity().level().isClientSide) {
|
||||||
|
ItemStack is = ev.getEntity().getItem();
|
||||||
|
|
||||||
|
if(is.getItem() == ItemRegistry.MINEPAD.get()) {
|
||||||
|
UUID thrower = ev.getPlayer().getGameProfile().getId();
|
||||||
|
is.set(WDDataComponents.THROWER_MSB.get(), thrower.getMostSignificantBits());
|
||||||
|
is.set(WDDataComponents.THROWER_LSB.get(), thrower.getLeastSignificantBits());
|
||||||
|
is.set(WDDataComponents.THROW_HEIGHT.get(), (float) (ev.getPlayer().getY() + ev.getPlayer().getEyeHeight()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onPlayerCraft(PlayerEvent.ItemCraftedEvent ev) {
|
||||||
|
if(CommonConfig.hardRecipes && ItemRegistry.isCompCraftItem(ev.getCrafting().getItem()) && (CraftComponent.EXTCARD.makeItemStack().is(ev.getCrafting().getItem()))) {
|
||||||
|
if((ev.getEntity() instanceof ServerPlayer && !hasPlayerAdvancement((ServerPlayer) ev.getEntity(), ADV_PAD_BREAK)) || PROXY.hasClientPlayerAdvancement(ADV_PAD_BREAK) != HasAdvancement.YES) {
|
||||||
|
ev.getCrafting().setDamageValue(CraftComponent.BADEXTCARD.ordinal());
|
||||||
|
|
||||||
|
if(!ev.getEntity().level().isClientSide)
|
||||||
|
ev.getEntity().level().playSound(null, ev.getEntity().getX(), ev.getEntity().getY(), ev.getEntity().getZ(), SoundEvents.ITEM_BREAK, SoundSource.MASTER, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onServerStop(ServerStoppingEvent ev) throws IOException {
|
||||||
|
Server.getInstance().stopServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onLogIn(PlayerEvent.PlayerLoggedInEvent ev) {
|
||||||
|
if (!CommonConfig.joinMessage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ev.getEntity().level().isClientSide && ev.getEntity() instanceof ServerPlayer) {
|
||||||
|
IWDDCapability cap = ev.getEntity().getData(WDDCapability.WDD_CAPABILITY.get());
|
||||||
|
|
||||||
|
if(cap.isFirstRun()) {
|
||||||
|
Util.toast(ev.getEntity(), ChatFormatting.LIGHT_PURPLE, "welcome1");
|
||||||
|
Util.toast(ev.getEntity(), ChatFormatting.LIGHT_PURPLE, "welcome2");
|
||||||
|
Util.toast(ev.getEntity(), ChatFormatting.LIGHT_PURPLE, "welcome3");
|
||||||
|
|
||||||
|
cap.clearFirstRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
S2CMessageServerInfo message = new S2CMessageServerInfo(miniservPort);
|
||||||
|
WDNetworkRegistry.INSTANCE.send((ServerPlayer) ev.getEntity(), message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onLogOut(PlayerEvent.PlayerLoggedOutEvent ev) {
|
||||||
|
if(!ev.getEntity().level().isClientSide)
|
||||||
|
Server.getInstance().getClientManager().revokeClientKey(ev.getEntity().getGameProfile().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onPlayerClone(PlayerEvent.Clone ev) {
|
||||||
|
IWDDCapability src = ev.getOriginal().getData(WDDCapability.WDD_CAPABILITY.get());
|
||||||
|
IWDDCapability dst = ev.getEntity().getData(WDDCapability.WDD_CAPABILITY.get());
|
||||||
|
|
||||||
|
if(src == null) {
|
||||||
|
Log.error("src is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dst == null) {
|
||||||
|
Log.error("dst is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
src.cloneTo(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onServerChat(ServerChatEvent ev) {
|
||||||
|
String msg = ev.getMessage().getString().replaceAll("\\s+", " ").toLowerCase();
|
||||||
|
StringBuilder sb = new StringBuilder(msg.length());
|
||||||
|
for(int i = 0; i < msg.length(); i++) {
|
||||||
|
char chr = msg.charAt(i);
|
||||||
|
|
||||||
|
if(chr != '.' && chr != ',' && chr != ';' && chr != '!' && chr != '?' && chr != ':' && chr != '\'' && chr != '\"' && chr != '`')
|
||||||
|
sb.append(chr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sb.toString().equals("ironic he could save others from death but not himself")) {
|
||||||
|
Player ply = ev.getPlayer();
|
||||||
|
ply.level().playSound(null, ply.getX(), ply.getY(), ply.getZ(), soundIronic, SoundSource.PLAYERS, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Update ClientChatEvent for NeoForge 1.21.1
|
||||||
|
// @SubscribeEvent
|
||||||
|
// public void onClientChat(ClientChatEvent ev) {
|
||||||
|
// if(ev.getMessage().equals("!WD render recipes"))
|
||||||
|
// PROXY.renderRecipes();
|
||||||
|
// }
|
||||||
|
|
||||||
|
private boolean hasPlayerAdvancement(ServerPlayer ply, ResourceLocation rl) {
|
||||||
|
MinecraftServer server = PROXY.getServer();
|
||||||
|
if(server == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
AdvancementHolder adv = server.getAdvancements().get(rl);
|
||||||
|
return adv != null && ply.getAdvancements().getOrStartProgress(adv).isDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getNextAvailablePadID() {
|
||||||
|
return new WebDisplays().lastPadId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DeferredRegister<SoundEvent> SOUNDS = DeferredRegister.create(Registries.SOUND_EVENT, "webdisplays");
|
||||||
|
|
||||||
|
private static SoundEvent registerSound(String resName) {
|
||||||
|
ResourceLocation resLoc = ResourceLocation.fromNamespaceAndPath("webdisplays", resName);
|
||||||
|
SoundEvent ret = SoundEvent.createVariableRangeEvent(resLoc);
|
||||||
|
|
||||||
|
SOUNDS.register(resName, () -> ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removed unused helper for older advancement API registration
|
||||||
|
|
||||||
|
// public static boolean isOpenComputersAvailable() {
|
||||||
|
// return INSTANCE.hasOC;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public static boolean isComputerCraftAvailable() {
|
||||||
|
// return INSTANCE.hasCC;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static boolean isSiteBlacklisted(String url) {
|
||||||
|
try {
|
||||||
|
URL url2 = new URL(Util.addProtocol(url));
|
||||||
|
for (String str : CommonConfig.Browser.blacklist)
|
||||||
|
if (str.equalsIgnoreCase(url2.getHost())) return true;
|
||||||
|
return false;
|
||||||
|
} catch(MalformedURLException ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String applyBlacklist(String url) {
|
||||||
|
return isSiteBlacklisted(url) ? BLACKLIST_URL : url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
146
src/main/java/net/montoyo/wd/block/KeyboardBlockLeft.java
Normal file
146
src/main/java/net/montoyo/wd/block/KeyboardBlockLeft.java
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.block;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||||
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||||
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
|
import net.montoyo.wd.core.DefaultPeripheral;
|
||||||
|
import net.montoyo.wd.entity.KeyboardBlockEntity;
|
||||||
|
import net.montoyo.wd.item.ItemLinker;
|
||||||
|
import net.montoyo.wd.net.WDNetworkRegistry;
|
||||||
|
import net.montoyo.wd.net.client_bound.S2CMessageCloseGui;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class KeyboardBlockLeft extends PeripheralBlock {
|
||||||
|
public static final EnumProperty<DefaultPeripheral> TYPE = EnumProperty.create("type", DefaultPeripheral.class);
|
||||||
|
public static final DirectionProperty FACING = DirectionProperty.create("facing", Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST);
|
||||||
|
// public static final DirectionProperty HALF = DirectionProperty.create("facing", Direction.EAST, Direction.WEST);
|
||||||
|
|
||||||
|
public static final VoxelShape[] KEYBOARD_AABBS = new VoxelShape[]{
|
||||||
|
Shapes.box(0.0, 0.0, 3.0 / 16, 1.0, 1.0 / 16.0, 1.0),
|
||||||
|
Shapes.box(0.0, 0.0, 0.0, 1.0, 1.0 / 16.0, 13 / 16.0),
|
||||||
|
Shapes.box(3.0 / 16, 0.0, 0.0, 1.0, 1.0 / 16.0, 1.0),
|
||||||
|
Shapes.box(0.0, 0.0, 0.0, 13 / 16.0, 1.0 / 16.0, 1.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final Property<?>[] properties = new Property<?>[] {TYPE, FACING};
|
||||||
|
|
||||||
|
public KeyboardBlockLeft() {
|
||||||
|
super(DefaultPeripheral.KEYBOARD);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make non static (for extensibility purposes)
|
||||||
|
public static KeyboardBlockEntity getTileEntity(BlockState state, Level world, BlockPos pos) {
|
||||||
|
if (state.getBlock() instanceof KeyboardBlockLeft) {
|
||||||
|
BlockEntity te = world.getBlockEntity(pos); // TODO: check?
|
||||||
|
if (te instanceof KeyboardBlockEntity)
|
||||||
|
return (KeyboardBlockEntity) te;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPos relative = pos.relative(KeyboardBlockLeft.mapDirection(state.getValue(FACING).getOpposite()));
|
||||||
|
BlockState ns = world.getBlockState(relative);
|
||||||
|
|
||||||
|
if (ns.getBlock() instanceof PeripheralBlock) {
|
||||||
|
BlockEntity te = world.getBlockEntity(relative); // TODO: check?
|
||||||
|
if (te instanceof KeyboardBlockEntity)
|
||||||
|
return (KeyboardBlockEntity) te;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Direction mapDirection(Direction facing) {
|
||||||
|
return switch (facing) {
|
||||||
|
case NORTH -> Direction.EAST;
|
||||||
|
case EAST -> Direction.SOUTH;
|
||||||
|
case SOUTH -> Direction.WEST;
|
||||||
|
case WEST -> Direction.NORTH;
|
||||||
|
default -> facing;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||||
|
builder.add(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
|
||||||
|
double rpos = (entity.getY() - ((double) pos.getY())) * 16.0;
|
||||||
|
if (!world.isClientSide && rpos >= 1.0 && rpos <= 2.0 && Math.random() < 0.25) {
|
||||||
|
KeyboardBlockEntity tek = KeyboardBlockLeft.getTileEntity(state, world, pos);
|
||||||
|
|
||||||
|
if (tek != null)
|
||||||
|
tek.simulateCat(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
|
||||||
|
// Note: useWithoutItem doesn't have InteractionHand parameter, so we use MAIN_HAND as default
|
||||||
|
InteractionHand hand = InteractionHand.MAIN_HAND;
|
||||||
|
|
||||||
|
if (player.getItemInHand(hand).getItem() instanceof ItemLinker)
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
|
||||||
|
KeyboardBlockEntity tek = KeyboardBlockLeft.getTileEntity(state, level, pos);
|
||||||
|
if (tek != null)
|
||||||
|
return tek.onRightClick(player, hand);
|
||||||
|
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return KEYBOARD_AABBS[state.getValue(FACING).ordinal() - 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOcclusionShape(BlockState arg, BlockGetter arg2, BlockPos arg3) {
|
||||||
|
return Shapes.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void removeRightPiece(BlockState state, Level world, BlockPos pos) {
|
||||||
|
BlockPos relative = pos.relative(KeyboardBlockLeft.mapDirection(state.getValue(FACING)));
|
||||||
|
|
||||||
|
BlockState ns = world.getBlockState(relative);
|
||||||
|
if (ns.getBlock() instanceof KeyboardBlockRight)
|
||||||
|
world.setBlock(relative, Blocks.AIR.defaultBlockState(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void remove(BlockState state, Level world, BlockPos pos, boolean setState, boolean drop) {
|
||||||
|
removeRightPiece(state, world, pos);
|
||||||
|
if (setState)
|
||||||
|
world.setBlock(pos, Blocks.AIR.defaultBlockState(), 3);
|
||||||
|
// TODO: Rewrite for new networking system
|
||||||
|
// WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(world, pos)), new S2CMessageCloseGui(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(BlockState arg, Level arg2, BlockPos arg3, BlockState arg4, boolean bl) {
|
||||||
|
if (!arg2.isClientSide)
|
||||||
|
remove(arg, arg2, arg3, false, false);
|
||||||
|
super.onRemove(arg, arg2, arg3, arg4, bl);
|
||||||
|
}
|
||||||
|
}
|
||||||
119
src/main/java/net/montoyo/wd/block/KeyboardBlockRight.java
Normal file
119
src/main/java/net/montoyo/wd/block/KeyboardBlockRight.java
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.block;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
|
import net.montoyo.wd.core.IPeripheral;
|
||||||
|
import net.montoyo.wd.entity.KeyboardBlockEntity;
|
||||||
|
import net.montoyo.wd.item.ItemLinker;
|
||||||
|
import net.montoyo.wd.net.WDNetworkRegistry;
|
||||||
|
import net.montoyo.wd.net.client_bound.S2CMessageCloseGui;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import static net.montoyo.wd.block.KeyboardBlockLeft.KEYBOARD_AABBS;
|
||||||
|
|
||||||
|
// TODO: merge into KeyboardLeft
|
||||||
|
public class KeyboardBlockRight extends Block implements IPeripheral {
|
||||||
|
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
||||||
|
|
||||||
|
public KeyboardBlockRight() {
|
||||||
|
super(Properties.ofFullCopy(Blocks.STONE)
|
||||||
|
.strength(1.5f, 10.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void removeLeftPiece(BlockState state, Level world, BlockPos pos) {
|
||||||
|
BlockPos relative = pos.relative(KeyboardBlockLeft.mapDirection(state.getValue(FACING).getOpposite()));
|
||||||
|
|
||||||
|
BlockState ns = world.getBlockState(relative);
|
||||||
|
if (ns.getBlock() instanceof KeyboardBlockLeft)
|
||||||
|
world.setBlock(relative, Blocks.AIR.defaultBlockState(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void remove(BlockState state, Level world, BlockPos pos, boolean setState, boolean drop) {
|
||||||
|
removeLeftPiece(state, world, pos);
|
||||||
|
if (setState)
|
||||||
|
world.setBlock(pos, Blocks.AIR.defaultBlockState(), 3);
|
||||||
|
// TODO: Rewrite for new networking system
|
||||||
|
// WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(world, pos)), new S2CMessageCloseGui(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(BlockState arg, Level arg2, BlockPos arg3, BlockState arg4, boolean bl) {
|
||||||
|
if (!arg2.isClientSide)
|
||||||
|
remove(arg, arg2, arg3, false, false);
|
||||||
|
super.onRemove(arg, arg2, arg3, arg4, bl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||||
|
builder.add(FACING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCollisionShapeFullBlock(BlockState state, BlockGetter level, BlockPos pos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return KEYBOARD_AABBS[state.getValue(FACING).ordinal() - 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean connect(Level world, BlockPos pos, BlockState state, Vector3i scrPos, BlockSide scrSide) {
|
||||||
|
KeyboardBlockEntity keyboard = KeyboardBlockLeft.getTileEntity(state, world, pos);
|
||||||
|
return keyboard != null && keyboard.connect(world, pos, state, scrPos, scrSide);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
|
||||||
|
double rpos = (entity.getY() - ((double) pos.getY())) * 16.0;
|
||||||
|
if (!world.isClientSide && rpos >= 1.0 && rpos <= 2.0 && Math.random() < 0.25) {
|
||||||
|
KeyboardBlockEntity tek = KeyboardBlockLeft.getTileEntity(state, world, pos);
|
||||||
|
|
||||||
|
if (tek != null)
|
||||||
|
tek.simulateCat(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
|
||||||
|
// Note: useWithoutItem doesn't have InteractionHand parameter, so we use MAIN_HAND as default
|
||||||
|
InteractionHand hand = InteractionHand.MAIN_HAND;
|
||||||
|
|
||||||
|
if (player.getItemInHand(hand).getItem() instanceof ItemLinker)
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
|
||||||
|
KeyboardBlockEntity tek = KeyboardBlockLeft.getTileEntity(state, level, pos);
|
||||||
|
if (tek != null)
|
||||||
|
return tek.onRightClick(player, hand);
|
||||||
|
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOcclusionShape(BlockState arg, BlockGetter arg2, BlockPos arg3) {
|
||||||
|
return Shapes.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
160
src/main/java/net/montoyo/wd/block/PeripheralBlock.java
Normal file
160
src/main/java/net/montoyo/wd/block/PeripheralBlock.java
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.block;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Explosion;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.RenderShape;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.material.PushReaction;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
|
import net.montoyo.wd.core.DefaultPeripheral;
|
||||||
|
import net.montoyo.wd.entity.AbstractInterfaceBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.AbstractPeripheralBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.ServerBlockEntity;
|
||||||
|
import net.montoyo.wd.item.ItemLinker;
|
||||||
|
import net.montoyo.wd.net.WDNetworkRegistry;
|
||||||
|
import net.montoyo.wd.net.client_bound.S2CMessageCloseGui;
|
||||||
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class PeripheralBlock extends WDContainerBlock {
|
||||||
|
public static final MapCodec<PeripheralBlock> CODEC = simpleCodec(properties -> new PeripheralBlock(DefaultPeripheral.KEYBOARD));
|
||||||
|
DefaultPeripheral type;
|
||||||
|
|
||||||
|
public PeripheralBlock(DefaultPeripheral type) {
|
||||||
|
super(BlockBehaviour.Properties.ofFullCopy(Blocks.STONE).strength(1.5f, 10.f));
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MapCodec<? extends BaseEntityBlock> codec() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
BlockEntityType.BlockEntitySupplier<? extends BlockEntity> cls = type.getTEClass();
|
||||||
|
if (cls == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return cls.create(pos, state);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Log.errorEx("Couldn't instantiate peripheral TileEntity:", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RenderShape getRenderShape(BlockState state) {
|
||||||
|
return RenderShape.MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
|
||||||
|
if (player.isShiftKeyDown())
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
|
||||||
|
// Note: useWithoutItem doesn't have InteractionHand parameter, so we use MAIN_HAND as default
|
||||||
|
InteractionHand hand = InteractionHand.MAIN_HAND;
|
||||||
|
|
||||||
|
if (player.getItemInHand(hand).getItem() instanceof ItemLinker)
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
|
||||||
|
BlockEntity te = level.getBlockEntity(pos);
|
||||||
|
|
||||||
|
if (te instanceof AbstractPeripheralBlockEntity)
|
||||||
|
return ((AbstractPeripheralBlockEntity) te).onRightClick(player, hand);
|
||||||
|
else if (te instanceof ServerBlockEntity) {
|
||||||
|
((ServerBlockEntity) te).onPlayerRightClick(player);
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
} else
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return Shapes.block();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
|
||||||
|
if (world.isClientSide)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (placer instanceof Player) {
|
||||||
|
BlockEntity te = world.getBlockEntity(pos);
|
||||||
|
|
||||||
|
if (te instanceof ServerBlockEntity)
|
||||||
|
((ServerBlockEntity) te).setOwner((Player) placer);
|
||||||
|
else if (te instanceof AbstractInterfaceBlockEntity)
|
||||||
|
((AbstractInterfaceBlockEntity) te).setOwner((Player) placer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PushReaction getPistonPushReaction(BlockState state) {
|
||||||
|
return PushReaction.IGNORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block neighborType, BlockPos neighbor, boolean isMoving) {
|
||||||
|
BlockEntity te = world.getBlockEntity(pos);
|
||||||
|
if (te instanceof AbstractPeripheralBlockEntity)
|
||||||
|
((AbstractPeripheralBlockEntity) te).onNeighborChange(neighborType, neighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) {
|
||||||
|
if (!world.isClientSide) {
|
||||||
|
// TODO: Rewrite for new networking system
|
||||||
|
// WDNetworkRegistry.INSTANCE.send(PacketDistributor.NEAR.with(() -> point(world, pos)), new S2CMessageCloseGui(pos));
|
||||||
|
}
|
||||||
|
super.playerDestroy(world, player, pos, state, blockEntity, tool);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlockExploded(BlockState state, Level level, BlockPos pos, Explosion explosion) {
|
||||||
|
playerDestroy(level, null, pos, level.getBlockState(pos), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to send packets to players near a position
|
||||||
|
public static void sendToPlayersNear(Level world, BlockPos bp, CustomPacketPayload payload) {
|
||||||
|
if (world instanceof ServerLevel serverLevel) {
|
||||||
|
PacketDistributor.sendToPlayersNear(serverLevel, null, bp.getX(), bp.getY(), bp.getZ(), 64.0, payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendToPlayersNear(Player exclude, Level world, BlockPos bp, CustomPacketPayload payload) {
|
||||||
|
if (world instanceof ServerLevel serverLevel) {
|
||||||
|
PacketDistributor.sendToPlayersNear(serverLevel, (ServerPlayer) exclude, bp.getX(), bp.getY(), bp.getZ(), 64.0, payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
353
src/main/java/net/montoyo/wd/block/ScreenBlock.java
Normal file
353
src/main/java/net/montoyo/wd/block/ScreenBlock.java
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.block;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.RenderShape;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||||
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.level.material.PushReaction;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.config.CommonConfig;
|
||||||
|
import net.montoyo.wd.core.DefaultUpgrade;
|
||||||
|
import net.montoyo.wd.core.IUpgrade;
|
||||||
|
import net.montoyo.wd.core.ScreenRights;
|
||||||
|
import net.montoyo.wd.data.SetURLData;
|
||||||
|
import net.montoyo.wd.entity.ScreenData;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.item.ItemLaserPointer;
|
||||||
|
import net.montoyo.wd.utilities.*;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector2i;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3f;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.serialization.Util;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class ScreenBlock extends BaseEntityBlock {
|
||||||
|
public static final MapCodec<ScreenBlock> CODEC = simpleCodec(ScreenBlock::new);
|
||||||
|
public static final BooleanProperty hasTE = BooleanProperty.create("haste");
|
||||||
|
public static final BooleanProperty emitting = BooleanProperty.create("emitting");
|
||||||
|
private static final Property<?>[] properties = new Property<?>[]{hasTE, emitting};
|
||||||
|
|
||||||
|
public ScreenBlock(Properties properties) {
|
||||||
|
super(properties.strength(1.5f, 10.f));
|
||||||
|
this.registerDefaultState(this.defaultBlockState().setValue(hasTE, false).setValue(emitting, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MapCodec<? extends BaseEntityBlock> codec() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemove(BlockState p_60515_, Level p_60516_, BlockPos p_60517_, BlockState p_60518_, boolean p_60519_) {
|
||||||
|
// TODO: make this also get called on client?
|
||||||
|
if (p_60518_.getBlock() == p_60515_.getBlock()) return;
|
||||||
|
|
||||||
|
for (BlockSide value : BlockSide.values()) {
|
||||||
|
Vector3i vec = new Vector3i(p_60517_.getX(), p_60517_.getY(), p_60517_.getZ());
|
||||||
|
Multiblock.findOrigin(p_60516_, vec, value, null);
|
||||||
|
BlockPos bp = new BlockPos(vec.x, vec.y, vec.z);
|
||||||
|
if (!bp.equals(p_60517_)) {
|
||||||
|
p_60516_.removeBlockEntity(bp);
|
||||||
|
p_60516_.setBlock(
|
||||||
|
bp, p_60516_.getBlockState(bp).setValue(hasTE, false),
|
||||||
|
11
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onRemove(p_60515_, p_60516_, p_60517_, p_60518_, p_60519_);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
|
||||||
|
// Note: useWithoutItem doesn't have InteractionHand parameter, so we use MAIN_HAND as default
|
||||||
|
InteractionHand hand = InteractionHand.MAIN_HAND;
|
||||||
|
|
||||||
|
ItemStack heldItem = player.getItemInHand(hand);
|
||||||
|
boolean isUpgrade = false;
|
||||||
|
if (heldItem.isEmpty())
|
||||||
|
heldItem = null; //Easier to work with
|
||||||
|
else if (!(isUpgrade = heldItem.getItem() instanceof IUpgrade))
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
else if (heldItem.getItem() instanceof ItemLaserPointer)
|
||||||
|
return InteractionResult.FAIL; // laser pointer already handles stuff
|
||||||
|
|
||||||
|
// handling the off hand leads to double clicking
|
||||||
|
if (!isUpgrade && hand == InteractionHand.OFF_HAND)
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
|
||||||
|
if (level.isClientSide)
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
|
||||||
|
boolean sneaking = player.isShiftKeyDown();
|
||||||
|
Vector3i screenPos = new Vector3i(pos);
|
||||||
|
|
||||||
|
BlockSide side = BlockSide.values()[hitResult.getDirection().ordinal()];
|
||||||
|
|
||||||
|
Multiblock.findOrigin(level, screenPos, side, null);
|
||||||
|
ScreenBlockEntity te = (ScreenBlockEntity) level.getBlockEntity(screenPos.toBlock());
|
||||||
|
|
||||||
|
if (te != null && te.getScreen(side) != null) {
|
||||||
|
ScreenData scr = te.getScreen(side);
|
||||||
|
|
||||||
|
if (sneaking) { //Right Click
|
||||||
|
if ((scr.rightsFor(player) & ScreenRights.CHANGE_URL) == 0)
|
||||||
|
Util.toast(player, "restrictions");
|
||||||
|
else
|
||||||
|
(new SetURLData(screenPos, scr.side, scr.url)).sendTo((ServerPlayer) player);
|
||||||
|
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
} else if (heldItem != null) {
|
||||||
|
if (!te.hasUpgrade(side, heldItem)) {
|
||||||
|
if ((scr.rightsFor(player) & ScreenRights.MANAGE_UPGRADES) == 0) {
|
||||||
|
Util.toast(player, "restrictions");
|
||||||
|
return InteractionResult.CONSUME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (te.addUpgrade(side, heldItem, player, false)) {
|
||||||
|
if (!player.isCreative())
|
||||||
|
heldItem.shrink(1);
|
||||||
|
|
||||||
|
Util.toast(player, ChatFormatting.AQUA, "upgradeOk");
|
||||||
|
if (player instanceof ServerPlayer)
|
||||||
|
WebDisplays.INSTANCE.criterionUpgradeScreen.trigger((ServerPlayer) player);
|
||||||
|
} else
|
||||||
|
Util.toast(player, "upgradeError");
|
||||||
|
|
||||||
|
return InteractionResult.CONSUME;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((scr.rightsFor(player) & ScreenRights.INTERACT) == 0) {
|
||||||
|
Util.toast(player, "restrictions");
|
||||||
|
return InteractionResult.CONSUME;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2i tmp = new Vector2i();
|
||||||
|
|
||||||
|
float hitX = ((float) hitResult.getLocation().x) - (float) te.getBlockPos().getX();
|
||||||
|
float hitY = ((float) hitResult.getLocation().y) - (float) te.getBlockPos().getY();
|
||||||
|
float hitZ = ((float) hitResult.getLocation().z) - (float) te.getBlockPos().getZ();
|
||||||
|
|
||||||
|
if (hit2pixels(side, hitResult.getBlockPos(), new Vector3i(hitResult.getBlockPos()), scr, hitX, hitY, hitZ, tmp))
|
||||||
|
te.click(side, tmp);
|
||||||
|
return InteractionResult.CONSUME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else if(sneaking) {
|
||||||
|
// Util.toast(player, "turnOn");
|
||||||
|
// return InteractionResult.SUCCESS;
|
||||||
|
// }
|
||||||
|
|
||||||
|
Vector2i size = Multiblock.measure(level, screenPos, side);
|
||||||
|
if (size.x < 2 && size.y < 2) {
|
||||||
|
Util.toast(player, "tooSmall");
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size.x > CommonConfig.Screen.maxScreenSizeX || size.y > CommonConfig.Screen.maxScreenSizeY) {
|
||||||
|
Util.toast(player, "tooBig", CommonConfig.Screen.maxScreenSizeX, CommonConfig.Screen.maxScreenSizeY);
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3i err = Multiblock.check(level, screenPos, size, side);
|
||||||
|
if (err != null) {
|
||||||
|
Util.toast(player, "invalid", err.toString());
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean created = false;
|
||||||
|
Log.info("Player %s (UUID %s) created a screen at %s of size %dx%d", player.getName(), player.getGameProfile().getId().toString(), screenPos.toString(), size.x, size.y);
|
||||||
|
|
||||||
|
if (te == null) {
|
||||||
|
BlockPos bp = screenPos.toBlock();
|
||||||
|
level.setBlockAndUpdate(bp, level.getBlockState(bp).setValue(hasTE, true));
|
||||||
|
te = (ScreenBlockEntity) level.getBlockEntity(bp);
|
||||||
|
created = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
te.addScreen(side, size, null, player, true);
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos source,
|
||||||
|
boolean isMoving) {
|
||||||
|
if (block != this && !world.isClientSide && !state.getValue(emitting)) {
|
||||||
|
for (BlockSide side : BlockSide.values()) {
|
||||||
|
Vector3i vec = new Vector3i(pos);
|
||||||
|
Multiblock.findOrigin(world, vec, side, null);
|
||||||
|
|
||||||
|
ScreenBlockEntity tes = (ScreenBlockEntity) world.getBlockEntity(vec.toBlock());
|
||||||
|
if (tes != null && tes.hasUpgrade(side, DefaultUpgrade.REDINPUT)) {
|
||||||
|
Direction facing = Direction.from2DDataValue(side.reverse().ordinal()); //Opposite face
|
||||||
|
vec.sub(pos.getX(), pos.getY(), pos.getZ()).neg();
|
||||||
|
// tes.updateJSRedstone(side, new Vector2i(vec.dot(side.right), vec.dot(side.up)), world.getSignal(pos, facing));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hit2pixels(BlockSide side, BlockPos bpos, Vector3i pos, ScreenData scr, float hitX, float hitY, float hitZ, Vector2i dst) {
|
||||||
|
if(side.right.x < 0)
|
||||||
|
hitX -= 1.f;
|
||||||
|
|
||||||
|
if(side.right.z < 0 || side == BlockSide.TOP || side == BlockSide.BOTTOM)
|
||||||
|
hitZ -= 1.f;
|
||||||
|
|
||||||
|
Vector3f rel = new Vector3f(hitX, hitY, hitZ);
|
||||||
|
|
||||||
|
// this dot is acting as a "get distance from plane" where the plane is the edge of the screen
|
||||||
|
float cx = rel.dot(side.right.toFloat()) - 2.f / 16.f;
|
||||||
|
float cy = rel.dot(side.up.toFloat()) - 2.f / 16.f;
|
||||||
|
float sw = ((float) scr.size.x) - 4.f / 16.f;
|
||||||
|
float sh = ((float) scr.size.y) - 4.f / 16.f;
|
||||||
|
|
||||||
|
cx /= sw;
|
||||||
|
cy /= sh;
|
||||||
|
|
||||||
|
if (cx >= 0.f && cx <= 1.0 && cy >= 0.f && cy <= 1.f) {
|
||||||
|
if (side != BlockSide.BOTTOM)
|
||||||
|
cy = 1.f - cy;
|
||||||
|
|
||||||
|
switch (scr.rotation) {
|
||||||
|
case ROT_90:
|
||||||
|
cy = 1.0f - cy;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROT_180:
|
||||||
|
cx = 1.0f - cx;
|
||||||
|
cy = 1.0f - cy;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROT_270:
|
||||||
|
cx = 1.0f - cx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cx *= (float) scr.resolution.x;
|
||||||
|
cy *= (float) scr.resolution.y;
|
||||||
|
|
||||||
|
if (scr.rotation.isVertical) {
|
||||||
|
dst.x = (int) cy;
|
||||||
|
dst.y = (int) cx;
|
||||||
|
} else {
|
||||||
|
dst.x = (int) cx;
|
||||||
|
dst.y = (int) cy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************* DESTRUCTION HANDLING *************************************************/
|
||||||
|
|
||||||
|
private void onDestroy(Level world, BlockPos pos, Player ply) {
|
||||||
|
if (!world.isClientSide) {
|
||||||
|
Vector3i bp = new Vector3i(pos);
|
||||||
|
Multiblock.BlockOverride override = new Multiblock.BlockOverride(bp, Multiblock.OverrideAction.SIMULATE);
|
||||||
|
|
||||||
|
for (BlockSide bs : BlockSide.values())
|
||||||
|
destroySide(world, bp.clone(), bs, override, ply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroySide(Level world, Vector3i pos, BlockSide side, Multiblock.BlockOverride override, Player
|
||||||
|
source) {
|
||||||
|
Multiblock.findOrigin(world, pos, side, override);
|
||||||
|
BlockPos bp = pos.toBlock();
|
||||||
|
BlockEntity te = world.getBlockEntity(bp);
|
||||||
|
|
||||||
|
if (te instanceof ScreenBlockEntity) {
|
||||||
|
((ScreenBlockEntity) te).onDestroy(source);
|
||||||
|
world.setBlock(bp, world.getBlockState(bp).setValue(hasTE, false), Block.UPDATE_ALL_IMMEDIATE); //Destroy tile entity.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDestroyedByPlayer(BlockState state, Level level, BlockPos pos, Player player,
|
||||||
|
boolean willHarvest, FluidState fluid) {
|
||||||
|
onDestroy(level, pos, player);
|
||||||
|
return super.onDestroyedByPlayer(state, level, pos, player, willHarvest, fluid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlacedBy(Level world, @NotNull BlockPos pos, @NotNull BlockState
|
||||||
|
state, @org.jetbrains.annotations.Nullable LivingEntity whoDidThisShit, @NotNull ItemStack stack) {
|
||||||
|
if (world.isClientSide)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Multiblock.BlockOverride override = new Multiblock.BlockOverride(new Vector3i(pos), Multiblock.OverrideAction.IGNORE);
|
||||||
|
Vector3i[] neighbors = new Vector3i[6];
|
||||||
|
|
||||||
|
neighbors[0] = new Vector3i(pos.getX() + 1, pos.getY(), pos.getZ());
|
||||||
|
neighbors[1] = new Vector3i(pos.getX() - 1, pos.getY(), pos.getZ());
|
||||||
|
neighbors[2] = new Vector3i(pos.getX(), pos.getY() + 1, pos.getZ());
|
||||||
|
neighbors[3] = new Vector3i(pos.getX(), pos.getY() - 1, pos.getZ());
|
||||||
|
neighbors[4] = new Vector3i(pos.getX(), pos.getY(), pos.getZ() + 1);
|
||||||
|
neighbors[5] = new Vector3i(pos.getX(), pos.getY(), pos.getZ() - 1);
|
||||||
|
|
||||||
|
for (Vector3i neighbor : neighbors) {
|
||||||
|
if (world.getBlockState(neighbor.toBlock()).getBlock() instanceof ScreenBlock) {
|
||||||
|
for (BlockSide bs : BlockSide.values())
|
||||||
|
destroySide(world, neighbor.clone(), bs, override, (whoDidThisShit instanceof Player) ? ((Player) whoDidThisShit) : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************* STUFF THAT'S UNLIKELY TO BE TOUCHED BUT NEEDS TO BE HERE *************************************************/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull PushReaction getPistonPushReaction(BlockState state) {
|
||||||
|
return PushReaction.IGNORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
|
||||||
|
return state.getValue(emitting) ? 15 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSignalSource(BlockState state) {
|
||||||
|
return state.getValue(emitting);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
return state.getValue(hasTE) ? new ScreenBlockEntity(pos, state) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RenderShape getRenderShape(BlockState state) {
|
||||||
|
return RenderShape.MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||||
|
builder.add(properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/main/java/net/montoyo/wd/block/WDContainerBlock.java
Normal file
22
src/main/java/net/montoyo/wd/block/WDContainerBlock.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.block;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.BlockItem;
|
||||||
|
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||||
|
|
||||||
|
public abstract class WDContainerBlock extends BaseEntityBlock {
|
||||||
|
|
||||||
|
protected static BlockItem itemBlock;
|
||||||
|
|
||||||
|
public WDContainerBlock(Properties arg) {
|
||||||
|
super(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockItem getItem() {
|
||||||
|
return itemBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
54
src/main/java/net/montoyo/wd/block/item/KeyboardItem.java
Normal file
54
src/main/java/net/montoyo/wd/block/item/KeyboardItem.java
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package net.montoyo.wd.block.item;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.item.BlockItem;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.montoyo.wd.block.KeyboardBlockLeft;
|
||||||
|
import net.montoyo.wd.registry.BlockRegistry;
|
||||||
|
|
||||||
|
public class KeyboardItem extends BlockItem {
|
||||||
|
public KeyboardItem(Block arg, Properties arg2) {
|
||||||
|
super(arg, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean placeBlock(BlockPlaceContext arg, BlockState arg2) {
|
||||||
|
Direction facing = arg.getHorizontalDirection();
|
||||||
|
arg2 = arg2.setValue(KeyboardBlockLeft.FACING, facing);
|
||||||
|
|
||||||
|
Direction d = KeyboardBlockLeft.mapDirection(facing);
|
||||||
|
|
||||||
|
if (isValid(arg.getClickedPos(), arg.getLevel(), arg2, d)) {
|
||||||
|
Block kbRight = BlockRegistry.blockKbRight.get();
|
||||||
|
BlockState rightState = kbRight.defaultBlockState();
|
||||||
|
|
||||||
|
rightState = rightState.setValue(KeyboardBlockLeft.FACING, facing);
|
||||||
|
if (!arg.getLevel().setBlock(
|
||||||
|
arg.getClickedPos().relative(d),
|
||||||
|
rightState,
|
||||||
|
11
|
||||||
|
)) return false;
|
||||||
|
return arg.getLevel().setBlock(arg.getClickedPos(), arg2, 11);// 161
|
||||||
|
} else if (isValid(arg.getClickedPos().relative(d.getOpposite(), 2), arg.getLevel(), arg2, d)) {
|
||||||
|
Block kbRight = BlockRegistry.blockKbRight.get();
|
||||||
|
BlockState rightState = kbRight.defaultBlockState();
|
||||||
|
|
||||||
|
rightState = rightState.setValue(KeyboardBlockLeft.FACING, facing);
|
||||||
|
if (!arg.getLevel().setBlock(
|
||||||
|
arg.getClickedPos(),
|
||||||
|
rightState,
|
||||||
|
11
|
||||||
|
)) return false;
|
||||||
|
return arg.getLevel().setBlock(arg.getClickedPos().relative(d.getOpposite()), arg2, 11);// 161
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValid(BlockPos pos, Level level, BlockState state, Direction d) {
|
||||||
|
return level.getBlockState(pos.relative(d)).isAir();
|
||||||
|
}
|
||||||
|
}
|
||||||
862
src/main/java/net/montoyo/wd/client/ClientProxy.java
Normal file
862
src/main/java/net/montoyo/wd/client/ClientProxy.java
Normal file
@@ -0,0 +1,862 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client;
|
||||||
|
|
||||||
|
import com.cinemamod.mcef.MCEF;
|
||||||
|
import com.cinemamod.mcef.MCEFBrowser;
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
import com.mojang.blaze3d.platform.InputConstants;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import net.minecraft.advancements.Advancement;
|
||||||
|
import net.minecraft.advancements.AdvancementHolder;
|
||||||
|
import net.minecraft.advancements.AdvancementProgress;
|
||||||
|
import net.minecraft.client.Camera;
|
||||||
|
import net.minecraft.client.KeyMapping;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.Options;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
|
import net.minecraft.client.multiplayer.ClientAdvancements;
|
||||||
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.NonNullList;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.packs.resources.ReloadableResourceManager;
|
||||||
|
import net.minecraft.server.packs.resources.ResourceManager;
|
||||||
|
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.HumanoidArm;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.inventory.Slot;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.ClipContext;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.neoforge.client.event.ModelEvent;
|
||||||
|
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent;
|
||||||
|
import net.neoforged.neoforge.client.event.RenderHandEvent;
|
||||||
|
import net.neoforged.neoforge.client.event.RenderHighlightEvent;
|
||||||
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
|
import net.neoforged.neoforge.event.tick.LevelTickEvent;
|
||||||
|
import net.neoforged.neoforge.client.event.ClientTickEvent;
|
||||||
|
import net.neoforged.neoforge.event.level.LevelEvent;
|
||||||
|
import net.neoforged.bus.api.SubscribeEvent;
|
||||||
|
import net.neoforged.fml.LogicalSide;
|
||||||
|
import net.neoforged.fml.common.Mod;
|
||||||
|
import net.neoforged.fml.common.EventBusSubscriber;
|
||||||
|
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.SharedProxy;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.block.ScreenBlock;
|
||||||
|
import net.montoyo.wd.client.gui.*;
|
||||||
|
import net.montoyo.wd.client.gui.loading.GuiLoader;
|
||||||
|
import net.montoyo.wd.client.renderers.*;
|
||||||
|
import net.montoyo.wd.core.HasAdvancement;
|
||||||
|
import net.montoyo.wd.data.GuiData;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.ScreenData;
|
||||||
|
import net.montoyo.wd.item.ItemLaserPointer;
|
||||||
|
import net.montoyo.wd.item.ItemMinePad2;
|
||||||
|
import net.montoyo.wd.item.WDItem;
|
||||||
|
import net.montoyo.wd.miniserv.client.Client;
|
||||||
|
import net.montoyo.wd.registry.BlockRegistry;
|
||||||
|
import net.montoyo.wd.registry.ItemRegistry;
|
||||||
|
import net.montoyo.wd.registry.TileRegistry;
|
||||||
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
import net.montoyo.wd.utilities.Multiblock;
|
||||||
|
import net.montoyo.wd.utilities.browser.WDBrowser;
|
||||||
|
import net.montoyo.wd.utilities.browser.handlers.DisplayHandler;
|
||||||
|
import net.montoyo.wd.utilities.browser.handlers.WDRouter;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.data.Rotation;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector2i;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
import net.montoyo.wd.utilities.serialization.NameUUIDPair;
|
||||||
|
import net.montoyo.wd.data.WDDataComponents;
|
||||||
|
import org.cef.browser.CefBrowser;
|
||||||
|
import org.cef.browser.CefMessageRouter;
|
||||||
|
import org.cef.misc.CefCursorType;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class ClientProxy extends SharedProxy implements ResourceManagerReloadListener {
|
||||||
|
|
||||||
|
private static ClientProxy INSTANCE;
|
||||||
|
|
||||||
|
public ClientProxy() {
|
||||||
|
INSTANCE = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void renderCrosshair(Options options, int screenWidth, int screenHeight, int offset, GuiGraphics poseStack, CallbackInfo ci) {
|
||||||
|
ItemStack stack = Minecraft.getInstance().player.getItemInHand(InteractionHand.MAIN_HAND);
|
||||||
|
ItemStack stack1 = Minecraft.getInstance().player.getItemInHand(InteractionHand.OFF_HAND);
|
||||||
|
|
||||||
|
if (stack.getItem() instanceof ItemMinePad2) {
|
||||||
|
float sign = 1;
|
||||||
|
if (Minecraft.getInstance().player.getMainArm() == HumanoidArm.LEFT) sign = -1;
|
||||||
|
if (!MinePadRenderer.renderAtSide(sign)) {
|
||||||
|
ci.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (stack1.getItem() instanceof ItemMinePad2) {
|
||||||
|
float sign = -1;
|
||||||
|
if (Minecraft.getInstance().player.getMainArm() == HumanoidArm.LEFT) sign = 1;
|
||||||
|
if (!MinePadRenderer.renderAtSide(sign)) {
|
||||||
|
ci.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(stack.getItem() instanceof ItemLaserPointer ||
|
||||||
|
stack1.getItem() instanceof ItemLaserPointer))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!LaserPointerRenderer.isOn()) {
|
||||||
|
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.ONE_MINUS_DST_COLOR, GlStateManager.DestFactor.ONE_MINUS_SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||||
|
|
||||||
|
poseStack.blit(ResourceLocation.fromNamespaceAndPath(
|
||||||
|
"webdisplays", "textures/gui/cursors.png"
|
||||||
|
), (screenWidth - 15) / 2, (screenHeight - 15) / 2, offset, 240, 240, 15, 15, 256, 256);
|
||||||
|
ci.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
|
||||||
|
BlockHitResult result = raycast(64.0); //TODO: Make that distance configurable
|
||||||
|
|
||||||
|
BlockPos bpos = result.getBlockPos();
|
||||||
|
|
||||||
|
if (result.getType() != HitResult.Type.BLOCK || mc.level.getBlockState(bpos).getBlock() != BlockRegistry.SCREEN_BLOCk.get()) {
|
||||||
|
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.ONE_MINUS_DST_COLOR, GlStateManager.DestFactor.ONE_MINUS_SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||||
|
|
||||||
|
poseStack.blit(ResourceLocation.fromNamespaceAndPath(
|
||||||
|
"webdisplays", "textures/gui/cursors.png"
|
||||||
|
), (screenWidth - 15) / 2, (screenHeight - 15) / 2, offset, 240, 240, 15, 15, 256, 256);
|
||||||
|
ci.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3i pos = new Vector3i(result.getBlockPos());
|
||||||
|
BlockSide side = BlockSide.values()[result.getDirection().ordinal()];
|
||||||
|
|
||||||
|
Multiblock.findOrigin(mc.level, pos, side, null);
|
||||||
|
ScreenBlockEntity te = (ScreenBlockEntity) mc.level.getBlockEntity(pos.toBlock());
|
||||||
|
|
||||||
|
ScreenData sc = te.getScreen(side);
|
||||||
|
|
||||||
|
if (sc == null) return;
|
||||||
|
|
||||||
|
int coordX = sc.mouseType * 15;
|
||||||
|
int coordY = coordX / 255;
|
||||||
|
coordX -= coordY * 255;
|
||||||
|
coordY *= 15;
|
||||||
|
// for some reason, the cursor gets offset at this value
|
||||||
|
if (sc.mouseType >= CefCursorType.NOT_ALLOWED.ordinal()) coordX -= 15;
|
||||||
|
|
||||||
|
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.ONE_MINUS_DST_COLOR, GlStateManager.DestFactor.ONE_MINUS_SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||||
|
|
||||||
|
poseStack.blit(ResourceLocation.fromNamespaceAndPath(
|
||||||
|
"webdisplays", "textures/gui/cursors.png"
|
||||||
|
), (screenWidth - 15) / 2, (screenHeight - 15) / 2, offset, coordX, coordY, 15, 15, 256, 256);
|
||||||
|
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ScreenBlockEntity> getScreens() {
|
||||||
|
return screenTracking;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PadData> getPads() {
|
||||||
|
return padList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PadData {
|
||||||
|
|
||||||
|
public CefBrowser view;
|
||||||
|
public final UUID id;
|
||||||
|
private boolean isInHotbar;
|
||||||
|
private long lastURLSent;
|
||||||
|
|
||||||
|
public int activeCursor;
|
||||||
|
|
||||||
|
private PadData(String url, UUID id) {
|
||||||
|
String webUrl;
|
||||||
|
try {
|
||||||
|
webUrl = ScreenBlockEntity.url(url);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
view = WDBrowser.createBrowser(WebDisplays.applyBlacklist(webUrl), false);
|
||||||
|
if (view instanceof MCEFBrowser browser) {
|
||||||
|
browser.resize((int) WebDisplays.INSTANCE.padResX, (int) WebDisplays.INSTANCE.padResY);
|
||||||
|
browser.setCursorChangeListener((cursor) -> {
|
||||||
|
activeCursor = cursor;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
isInHotbar = true;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateTime() {
|
||||||
|
lastURLSent = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long lastSent() {
|
||||||
|
return lastURLSent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Minecraft mc;
|
||||||
|
private MinePadRenderer minePadRenderer;
|
||||||
|
private LaserPointerRenderer laserPointerRenderer;
|
||||||
|
private Screen nextScreen;
|
||||||
|
private boolean isF1Down;
|
||||||
|
|
||||||
|
//Miniserv handling
|
||||||
|
private int miniservPort;
|
||||||
|
private boolean msClientStarted;
|
||||||
|
|
||||||
|
//Client-side advancement hack
|
||||||
|
private final Field advancementToProgressField = findAdvancementToProgressField();
|
||||||
|
private ClientAdvancements lastAdvMgr;
|
||||||
|
private Map advancementToProgress;
|
||||||
|
|
||||||
|
//Tracking
|
||||||
|
private final ArrayList<ScreenBlockEntity> screenTracking = new ArrayList<>();
|
||||||
|
private int lastTracked = 0;
|
||||||
|
|
||||||
|
//MinePads Management
|
||||||
|
private final HashMap<UUID, PadData> padMap = new HashMap<>();
|
||||||
|
private final ArrayList<PadData> padList = new ArrayList<>();
|
||||||
|
private int minePadTickCounter = 0;
|
||||||
|
|
||||||
|
/**************************************** INHERITED METHODS ****************************************/
|
||||||
|
public static void onClientSetup(FMLClientSetupEvent event) {
|
||||||
|
BlockEntityRenderers.register(TileRegistry.SCREEN_BLOCK_ENTITY.get(), new ScreenRenderer.ScreenRendererProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onModelRegistryEvent(ModelEvent.RegisterGeometryLoaders event) {
|
||||||
|
event.register(ResourceLocation.fromNamespaceAndPath("webdisplays", "screen_loader"), new ScreenModelLoader());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preInit() {
|
||||||
|
super.preInit();
|
||||||
|
mc = Minecraft.getInstance();
|
||||||
|
NeoForge.EVENT_BUS.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCefInit() {
|
||||||
|
minePadRenderer = new MinePadRenderer();
|
||||||
|
laserPointerRenderer = new LaserPointerRenderer();
|
||||||
|
|
||||||
|
if (!MCEF.isInitialized()) return;
|
||||||
|
|
||||||
|
MCEF.getApp().getHandle().registerSchemeHandlerFactory(
|
||||||
|
"webdisplays", "",
|
||||||
|
(browser, frame, url, request) -> {
|
||||||
|
// TODO: check if it's a webdisplays browser?
|
||||||
|
return new WDScheme(request.getURL());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
MCEF.getClient().addDisplayHandler(DisplayHandler.INSTANCE);
|
||||||
|
MCEF.getClient().getHandle().addMessageRouter(CefMessageRouter.create(WDRouter.INSTANCE));
|
||||||
|
|
||||||
|
findAdvancementToProgressField();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postInit() {
|
||||||
|
((ReloadableResourceManager) mc.getResourceManager()).registerReloadListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Level getWorld(ResourceKey<Level> dim) {
|
||||||
|
Level ret = mc.level;
|
||||||
|
// if(dim == CURRENT_DIMENSION)
|
||||||
|
// return ret;
|
||||||
|
if (ret != null) {
|
||||||
|
if (!ret.dimension().equals(dim))
|
||||||
|
throw new RuntimeException("Can't get non-current dimension " + dim + " from client.");
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Level on client is null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enqueue(Runnable r) {
|
||||||
|
mc.submit(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayGui(GuiData data) {
|
||||||
|
Screen gui = data.createGui(mc.screen, mc.level);
|
||||||
|
if (gui != null)
|
||||||
|
mc.setScreen(gui);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trackScreen(ScreenBlockEntity tes, boolean track) {
|
||||||
|
int idx = -1;
|
||||||
|
for (int i = 0; i < screenTracking.size(); i++) {
|
||||||
|
if (screenTracking.get(i) == tes) {
|
||||||
|
idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track) {
|
||||||
|
if (idx < 0)
|
||||||
|
screenTracking.add(tes);
|
||||||
|
} else if (idx >= 0)
|
||||||
|
screenTracking.remove(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutocompleteResult(NameUUIDPair[] pairs) {
|
||||||
|
if (mc.screen != null && mc.screen instanceof WDScreen screen) {
|
||||||
|
if (pairs.length == 0)
|
||||||
|
(screen).onAutocompleteFailure();
|
||||||
|
else
|
||||||
|
(screen).onAutocompleteResult(pairs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GameProfile[] getOnlineGameProfiles() {
|
||||||
|
return new GameProfile[]{mc.player.getGameProfile()};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void screenUpdateResolutionInGui(Vector3i pos, BlockSide side, Vector2i res) {
|
||||||
|
if (mc.screen != null && mc.screen instanceof GuiScreenConfig gsc) {
|
||||||
|
if (gsc.isForBlock(pos.toBlock(), side))
|
||||||
|
gsc.updateResolution(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void screenUpdateRotationInGui(Vector3i pos, BlockSide side, Rotation rot) {
|
||||||
|
if (mc.screen != null && mc.screen instanceof GuiScreenConfig gsc) {
|
||||||
|
if (gsc.isForBlock(pos.toBlock(), side))
|
||||||
|
gsc.updateRotation(rot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void screenUpdateAutoVolumeInGui(Vector3i pos, BlockSide side, boolean av) {
|
||||||
|
if (mc.screen != null && mc.screen instanceof GuiScreenConfig gsc) {
|
||||||
|
if (gsc.isForBlock(pos.toBlock(), side))
|
||||||
|
gsc.updateAutoVolume(av);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displaySetPadURLGui(ItemStack is, String padURL) {
|
||||||
|
mc.setScreen(new GuiSetURL2(is, padURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void openMinePadGui(UUID padId) {
|
||||||
|
PadData pd = padMap.get(padId);
|
||||||
|
|
||||||
|
if (pd != null && pd.view != null)
|
||||||
|
mc.setScreen(new GuiMinePad(pd));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public HasAdvancement hasClientPlayerAdvancement(@Nonnull ResourceLocation rl) {
|
||||||
|
if (advancementToProgressField != null && mc.player != null && mc.player.connection != null) {
|
||||||
|
ClientAdvancements cam = mc.player.connection.getAdvancements();
|
||||||
|
AdvancementHolder adv = cam.get(rl);
|
||||||
|
|
||||||
|
if (adv == null)
|
||||||
|
return HasAdvancement.DONT_KNOW;
|
||||||
|
|
||||||
|
if (lastAdvMgr != cam) {
|
||||||
|
lastAdvMgr = cam;
|
||||||
|
|
||||||
|
try {
|
||||||
|
advancementToProgress = (Map) advancementToProgressField.get(cam);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Log.warningEx("Could not get ClientAdvancementManager.advancementToProgress field", t);
|
||||||
|
advancementToProgress = null;
|
||||||
|
return HasAdvancement.DONT_KNOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (advancementToProgress == null)
|
||||||
|
return HasAdvancement.DONT_KNOW;
|
||||||
|
|
||||||
|
Object progress = advancementToProgress.get(adv);
|
||||||
|
if (progress == null)
|
||||||
|
return HasAdvancement.NO;
|
||||||
|
|
||||||
|
if (!(progress instanceof AdvancementProgress)) {
|
||||||
|
Log.warning("The ClientAdvancementManager.advancementToProgress map does not contain AdvancementProgress instances");
|
||||||
|
advancementToProgress = null; //Invalidate this: it's wrong
|
||||||
|
return HasAdvancement.DONT_KNOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((AdvancementProgress) progress).isDone() ? HasAdvancement.YES : HasAdvancement.NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HasAdvancement.DONT_KNOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MinecraftServer getServer() {
|
||||||
|
return mc.getSingleplayerServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public void handleJSResponseSuccess(int reqId, JSServerRequest type, byte[] data) {
|
||||||
|
// JSQueryDispatcher.ServerQuery q = jsDispatcher.fulfillQuery(reqId);
|
||||||
|
//
|
||||||
|
// if (q == null)
|
||||||
|
// Log.warning("Received success response for invalid query ID %d of type %s", reqId, type.toString());
|
||||||
|
// else {
|
||||||
|
// if (type == JSServerRequest.CLEAR_REDSTONE || type == JSServerRequest.SET_REDSTONE_AT)
|
||||||
|
// q.success("{\"status\":\"success\"}");
|
||||||
|
// else
|
||||||
|
// Log.warning("Received success response for query ID %d, but type is invalid", reqId);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void handleJSResponseError(int reqId, JSServerRequest type, int errCode, String err) {
|
||||||
|
// JSQueryDispatcher.ServerQuery q = jsDispatcher.fulfillQuery(reqId);
|
||||||
|
//
|
||||||
|
// if (q == null)
|
||||||
|
// Log.warning("Received error response for invalid query ID %d of type %s", reqId, type.toString());
|
||||||
|
// else
|
||||||
|
// q.error(errCode, err);
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMiniservClientPort(int port) {
|
||||||
|
miniservPort = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startMiniservClient() {
|
||||||
|
if (miniservPort <= 0) {
|
||||||
|
Log.warning("Can't start miniserv client: miniserv is disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mc.player == null) {
|
||||||
|
Log.warning("Can't start miniserv client: player is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketAddress saddr = mc.player.connection.getConnection().channel().remoteAddress();
|
||||||
|
if (saddr == null || !(saddr instanceof InetSocketAddress)) {
|
||||||
|
Log.warning("Miniserv client: remote address is not inet, assuming local address");
|
||||||
|
saddr = new InetSocketAddress("127.0.0.1", 1234);
|
||||||
|
}
|
||||||
|
|
||||||
|
InetSocketAddress msAddr = new InetSocketAddress(((InetSocketAddress) saddr).getAddress(), miniservPort);
|
||||||
|
Client.getInstance().start(msAddr);
|
||||||
|
msClientStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMiniservDisabled() {
|
||||||
|
return miniservPort <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeGui(BlockPos bp, BlockSide bs) {
|
||||||
|
if (mc.screen instanceof WDScreen) {
|
||||||
|
WDScreen scr = (WDScreen) mc.screen;
|
||||||
|
|
||||||
|
if (scr.isForBlock(bp, bs))
|
||||||
|
mc.setScreen(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderRecipes() {
|
||||||
|
nextScreen = new RenderRecipe();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isShiftDown() {
|
||||||
|
return Screen.hasShiftDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************** RESOURCE MANAGER METHODS ****************************************/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResourceManagerReload(ResourceManager resourceManager) {
|
||||||
|
Log.info("Resource manager reload: clearing GUI cache...");
|
||||||
|
GuiLoader.clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************** JS HANDLER METHODS ****************************************/
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public boolean handleQuery(IBrowser browser, long queryId, String query, boolean persistent, IJSQueryCallback cb) {
|
||||||
|
// if (browser != null && persistent && query != null && cb != null) {
|
||||||
|
// query = query.toLowerCase();
|
||||||
|
//
|
||||||
|
// if (query.startsWith("webdisplays_")) {
|
||||||
|
// query = query.substring(12);
|
||||||
|
//
|
||||||
|
// String args;
|
||||||
|
// int parenthesis = query.indexOf('(');
|
||||||
|
// if (parenthesis < 0)
|
||||||
|
// args = null;
|
||||||
|
// else {
|
||||||
|
// if (query.indexOf(')') != query.length() - 1) {
|
||||||
|
// cb.failure(400, "Malformed request");
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// args = query.substring(parenthesis + 1, query.length() - 1);
|
||||||
|
// query = query.substring(0, parenthesis);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (jsDispatcher.canHandleQuery(query))
|
||||||
|
// jsDispatcher.enqueueQuery(browser, query, args, cb);
|
||||||
|
// else
|
||||||
|
// cb.failure(404, "Unknown WebDisplays query");
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void cancelQuery(IBrowser browser, long queryId) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**************************************** EVENT METHODS ****************************************/
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onLevelTick(LevelTickEvent.Post ev) {
|
||||||
|
if (!ev.getLevel().isClientSide()) return;
|
||||||
|
|
||||||
|
//Unload/load screens depending on client player distance
|
||||||
|
if (mc.player == null || screenTracking.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int id = lastTracked % screenTracking.size();
|
||||||
|
|
||||||
|
ScreenBlockEntity tes = screenTracking.get(id);
|
||||||
|
|
||||||
|
if (!tes.getLevel().equals(ev.getLevel()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
lastTracked++;
|
||||||
|
if (tes.getLevel() != mc.player.level()) {
|
||||||
|
// TODO: properly handle this
|
||||||
|
// probably gonna want a helper class for cross-dimensional distances
|
||||||
|
if (!tes.isLoaded())
|
||||||
|
tes.load();
|
||||||
|
} else {
|
||||||
|
Camera camera = mc.getEntityRenderDispatcher().camera;
|
||||||
|
Entity entity = null;
|
||||||
|
|
||||||
|
// ide inspection says this is a bunch of constant expressions
|
||||||
|
// THIS IS NOT THE CASE
|
||||||
|
// a crash HAS occurred because of this going unchecked, and I'm confused about it
|
||||||
|
|
||||||
|
//noinspection ConstantValue
|
||||||
|
if (camera != null) entity = camera.getEntity();
|
||||||
|
//noinspection ConstantValue
|
||||||
|
if (entity == null) entity = mc.player;
|
||||||
|
//noinspection ConstantValue
|
||||||
|
if (entity != null) {
|
||||||
|
double dist = distanceTo(tes, entity.getPosition(0));
|
||||||
|
|
||||||
|
if (tes.isLoaded()) {
|
||||||
|
if (dist > WebDisplays.INSTANCE.unloadDistance2 * 16)
|
||||||
|
tes.deactivate();
|
||||||
|
// else if (ClientConfig.AutoVolumeControl.enableAutoVolume)
|
||||||
|
// tes.updateTrackDistance(dist, 80); //ToDo find master volume
|
||||||
|
} else if (dist <= WebDisplays.INSTANCE.loadDistance2 * 16)
|
||||||
|
tes.activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onTick(ClientTickEvent.Post ev) {
|
||||||
|
|
||||||
|
//Help
|
||||||
|
if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), GLFW.GLFW_KEY_F1)) {
|
||||||
|
if (!isF1Down) {
|
||||||
|
isF1Down = true;
|
||||||
|
|
||||||
|
String wikiName = null;
|
||||||
|
if (mc.screen instanceof WDScreen)
|
||||||
|
wikiName = ((WDScreen) mc.screen).getWikiPageName();
|
||||||
|
else if (mc.screen instanceof AbstractContainerScreen) {
|
||||||
|
Slot slot = ((AbstractContainerScreen) mc.screen).getSlotUnderMouse();
|
||||||
|
|
||||||
|
if (slot != null && slot.hasItem() && slot.getItem().getItem() instanceof WDItem)
|
||||||
|
wikiName = ((WDItem) slot.getItem().getItem()).getWikiName(slot.getItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (wikiName != null)
|
||||||
|
// mcef.openExampleBrowser("https://montoyo.net/wdwiki/index.php/" + wikiName);
|
||||||
|
}
|
||||||
|
} else if (isF1Down)
|
||||||
|
isF1Down = false;
|
||||||
|
|
||||||
|
//Workaround cuz chat sux
|
||||||
|
if (nextScreen != null && mc.screen == null) {
|
||||||
|
mc.setScreen(nextScreen);
|
||||||
|
nextScreen = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle r button
|
||||||
|
if (KEY_MOUSE.isDown()) {
|
||||||
|
if (!rDown) {
|
||||||
|
rDown = true;
|
||||||
|
mouseOn = !mouseOn;
|
||||||
|
}
|
||||||
|
} else rDown = false;
|
||||||
|
if (
|
||||||
|
Minecraft.getInstance().player == null ||
|
||||||
|
!(Minecraft.getInstance().player.getItemInHand(InteractionHand.MAIN_HAND).getItem() instanceof ItemLaserPointer)
|
||||||
|
) mouseOn = false;
|
||||||
|
|
||||||
|
|
||||||
|
//Load/unload minePads depending on which item is in the player's hand
|
||||||
|
if (++minePadTickCounter >= 10) {
|
||||||
|
minePadTickCounter = 0;
|
||||||
|
Player ep = mc.player;
|
||||||
|
|
||||||
|
for (PadData pd : padList)
|
||||||
|
pd.isInHotbar = false;
|
||||||
|
|
||||||
|
if (ep != null) {
|
||||||
|
updateInventory(ep.getInventory().items, ep.getItemInHand(InteractionHand.MAIN_HAND), 9);
|
||||||
|
updateInventory(ep.getInventory().offhand, ep.getItemInHand(InteractionHand.OFF_HAND), 1); //Is this okay?
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Check for GuiContainer.draggedStack
|
||||||
|
|
||||||
|
for (int i = padList.size() - 1; i >= 0; i--) {
|
||||||
|
PadData pd = padList.get(i);
|
||||||
|
|
||||||
|
if (!pd.isInHotbar) {
|
||||||
|
pd.view.close(true);
|
||||||
|
pd.view = null; //This is for GuiMinePad, in case the player dies with the GUI open
|
||||||
|
padList.remove(i);
|
||||||
|
padMap.remove(pd.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Laser pointer raycast
|
||||||
|
if (LaserPointerRenderer.isOn()) {
|
||||||
|
ItemLaserPointer.tick(mc);
|
||||||
|
} else {
|
||||||
|
ItemLaserPointer.deselect(mc);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Miniserv
|
||||||
|
if (msClientStarted && mc.player == null) {
|
||||||
|
msClientStarted = false;
|
||||||
|
Client.getInstance().stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onRenderPlayerHand(RenderHandEvent ev) {
|
||||||
|
Item item = ev.getItemStack().getItem();
|
||||||
|
IItemRenderer renderer;
|
||||||
|
|
||||||
|
if (item == ItemRegistry.MINEPAD.get())
|
||||||
|
renderer = minePadRenderer;
|
||||||
|
else if (item == ItemRegistry.LASER_POINTER.get())
|
||||||
|
renderer = laserPointerRenderer;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
HumanoidArm handSide = mc.player.getMainArm();
|
||||||
|
if (ev.getHand() == InteractionHand.OFF_HAND)
|
||||||
|
handSide = handSide.getOpposite();
|
||||||
|
|
||||||
|
if (renderer.render(ev.getPoseStack(), ev.getItemStack(), (handSide == HumanoidArm.RIGHT) ? 1.0f : -1.0f, ev.getSwingProgress(), ev.getEquipProgress(), ev.getMultiBufferSource(), ev.getPackedLight())) {
|
||||||
|
ev.setCanceled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onWorldUnload(LevelEvent.Unload ev) {
|
||||||
|
Log.info("World unloaded; killing screens...");
|
||||||
|
if (ev.getLevel() instanceof Level level) {
|
||||||
|
ResourceLocation dim = level.dimension().location();
|
||||||
|
for (int i = screenTracking.size() - 1; i >= 0; i--) {
|
||||||
|
if (screenTracking.get(i).getLevel().dimension().location().equals(dim)) //Could be world == ev.getWorld()
|
||||||
|
screenTracking.remove(i).unload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockHitResult raycast(double dist) {
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
|
||||||
|
Vec3 start = mc.player.getEyePosition(1.0f);
|
||||||
|
Vec3 lookVec = mc.player.getLookAngle();
|
||||||
|
Vec3 end = start.add(lookVec.x * dist, lookVec.y * dist, lookVec.z * dist);
|
||||||
|
|
||||||
|
return mc.level.clip(new ClipContext(start, end, ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, mc.player));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateInventory(NonNullList<ItemStack> inv, ItemStack heldStack, int cnt) {
|
||||||
|
for (int i = 0; i < cnt; i++) {
|
||||||
|
ItemStack item = inv.get(i);
|
||||||
|
|
||||||
|
if (item.getItem() == ItemRegistry.MINEPAD.get()) {
|
||||||
|
if (item.has(WDDataComponents.PAD_ID.get())) {
|
||||||
|
UUID padId = item.get(WDDataComponents.PAD_ID.get());
|
||||||
|
updatePad(padId, item, item == heldStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePad(UUID id, ItemStack stack, boolean isSelected) {
|
||||||
|
PadData pd = padMap.get(id);
|
||||||
|
|
||||||
|
if (pd != null)
|
||||||
|
pd.isInHotbar = true;
|
||||||
|
else if (isSelected && stack.has(WDDataComponents.PAD_URL.get())) {
|
||||||
|
String url = stack.get(WDDataComponents.PAD_URL.get());
|
||||||
|
pd = new PadData(url, id);
|
||||||
|
padMap.put(id, pd);
|
||||||
|
padList.add(pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MinePadRenderer getMinePadRenderer() {
|
||||||
|
return minePadRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PadData getPadByID(UUID id) {
|
||||||
|
return padMap.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class ScreenSidePair {
|
||||||
|
|
||||||
|
public ScreenBlockEntity tes;
|
||||||
|
public BlockSide side;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean findScreenFromBrowser(CefBrowser browser, ScreenSidePair pair) {
|
||||||
|
for (ScreenBlockEntity tes : screenTracking) {
|
||||||
|
for (int i = 0; i < tes.screenCount(); i++) {
|
||||||
|
ScreenData scr = tes.getScreen(i);
|
||||||
|
|
||||||
|
if (scr.browser == browser) {
|
||||||
|
pair.tes = tes;
|
||||||
|
pair.side = scr.side;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Field findAdvancementToProgressField() {
|
||||||
|
Field[] fields = ClientAdvancements.class.getDeclaredFields();
|
||||||
|
Optional<Field> result = Arrays.stream(fields).filter(f -> f.getType() == Map.class).findAny();
|
||||||
|
|
||||||
|
if (result.isPresent()) {
|
||||||
|
try {
|
||||||
|
Field ret = result.get();
|
||||||
|
ret.setAccessible(true);
|
||||||
|
return ret;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.warning("ClientAdvancementManager.advancementToProgress field could not be found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockGetter getWorld(IPayloadContext context) {
|
||||||
|
BlockGetter senderLevel = super.getWorld(context);
|
||||||
|
if (senderLevel == null) return Minecraft.getInstance().level;
|
||||||
|
return senderLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onDrawSelection(RenderHighlightEvent.Block event) {
|
||||||
|
if (event.getTarget() instanceof BlockHitResult bhr) {
|
||||||
|
BlockState state = Minecraft.getInstance().level.getBlockState(bhr.getBlockPos());
|
||||||
|
if (state.getBlock() instanceof ScreenBlock screen) {
|
||||||
|
Vector3i vec = new Vector3i(bhr.getBlockPos().getX(), bhr.getBlockPos().getY(), bhr.getBlockPos().getZ());
|
||||||
|
BlockSide side = BlockSide.fromInt(bhr.getDirection().ordinal());
|
||||||
|
Multiblock.findOrigin(
|
||||||
|
Minecraft.getInstance().level, vec,
|
||||||
|
side, null
|
||||||
|
);
|
||||||
|
|
||||||
|
BlockPos pos = new BlockPos(vec.x, vec.y, vec.z);
|
||||||
|
BlockEntity be = Minecraft.getInstance().level.getBlockEntity(
|
||||||
|
pos
|
||||||
|
);
|
||||||
|
if (be instanceof ScreenBlockEntity tes) {
|
||||||
|
if (tes.getScreen(side) != null) {
|
||||||
|
event.setCanceled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KEYBINDS
|
||||||
|
**/
|
||||||
|
public static final KeyMapping KEY_MOUSE = new KeyMapping("webdisplays.key.toggle_mouse", GLFW.GLFW_KEY_R, "key.categories.misc");
|
||||||
|
static boolean rDown = false;
|
||||||
|
public static boolean mouseOn = false;
|
||||||
|
|
||||||
|
public static void onKeybindRegistry(RegisterKeyMappingsEvent event) {
|
||||||
|
event.register(KEY_MOUSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
370
src/main/java/net/montoyo/wd/client/JSQueryDispatcher.java
Normal file
370
src/main/java/net/montoyo/wd/client/JSQueryDispatcher.java
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
///*
|
||||||
|
// * Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//package net.montoyo.wd.client;
|
||||||
|
//
|
||||||
|
//import net.minecraft.client.Minecraft;
|
||||||
|
//import net.minecraft.core.BlockPos;
|
||||||
|
//import net.minecraft.core.Direction;
|
||||||
|
//import net.minecraft.world.item.ItemStack;
|
||||||
|
//import net.neoforged.api.distmarker.Dist;
|
||||||
|
//import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
//import net.montoyo.wd.block.BlockScreen;
|
||||||
|
//import net.montoyo.wd.core.DefaultUpgrade;
|
||||||
|
//import net.montoyo.wd.core.IScreenQueryHandler;
|
||||||
|
//import net.montoyo.wd.core.IUpgrade;
|
||||||
|
//import net.montoyo.wd.core.JSServerRequest;
|
||||||
|
//import net.montoyo.wd.entity.TileEntityScreen;
|
||||||
|
//import net.montoyo.wd.net.WDNetworkRegistry;
|
||||||
|
//import net.montoyo.wd.net.server_bound.C2SMessageScreenCtrl;
|
||||||
|
//import net.montoyo.wd.utilities.*;
|
||||||
|
//
|
||||||
|
//import java.util.*;
|
||||||
|
//
|
||||||
|
//@OnlyIn(Dist.CLIENT)
|
||||||
|
//public final class JSQueryDispatcher {
|
||||||
|
//
|
||||||
|
// private static final class QueryData {
|
||||||
|
//
|
||||||
|
// private final IBrowser browser;
|
||||||
|
// private final String query;
|
||||||
|
// private final String args;
|
||||||
|
// private final IJSQueryCallback callback;
|
||||||
|
//
|
||||||
|
// private QueryData(IBrowser b, String q, String a, IJSQueryCallback cb) {
|
||||||
|
// browser = b;
|
||||||
|
// query = q;
|
||||||
|
// args = a;
|
||||||
|
// callback = cb;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static final class ServerQuery {
|
||||||
|
//
|
||||||
|
// private static int lastId = 0;
|
||||||
|
//
|
||||||
|
// private final TileEntityScreen tes;
|
||||||
|
// private final BlockSide side;
|
||||||
|
// private final IJSQueryCallback callback;
|
||||||
|
// private final int id;
|
||||||
|
//
|
||||||
|
// private ServerQuery(TileEntityScreen t, BlockSide s, IJSQueryCallback cb) {
|
||||||
|
// tes = t;
|
||||||
|
// side = s;
|
||||||
|
// callback = cb;
|
||||||
|
// id = lastId++;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public TileEntityScreen getTileEntity() {
|
||||||
|
// return tes;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public BlockSide getSide() {
|
||||||
|
// return side;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public TileEntityScreen.Screen getScreen() {
|
||||||
|
// return tes.getScreen(side);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void success(String resp) {
|
||||||
|
// callback.success(resp);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void error(int errId, String errStr) {
|
||||||
|
// callback.failure(errId, errStr);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private final ClientProxy proxy;
|
||||||
|
// private final ArrayDeque<QueryData> queue = new ArrayDeque<>();
|
||||||
|
// private final ClientProxy.ScreenSidePair lookupResult = new ClientProxy.ScreenSidePair();
|
||||||
|
// private final HashMap<String, IScreenQueryHandler> handlers = new HashMap<>();
|
||||||
|
// private final ArrayList<ServerQuery> serverQueries = new ArrayList<>();
|
||||||
|
// private final Minecraft mc = Minecraft.getInstance();
|
||||||
|
//
|
||||||
|
// public JSQueryDispatcher(ClientProxy proxy) {
|
||||||
|
// this.proxy = proxy;
|
||||||
|
// registerDefaults();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void enqueueQuery(IBrowser b, String q, String a, IJSQueryCallback cb) {
|
||||||
|
// synchronized(queue) {
|
||||||
|
// queue.offer(new QueryData(b, q, a, cb));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void handleQueries() {
|
||||||
|
// while(true) {
|
||||||
|
// QueryData next;
|
||||||
|
// synchronized(queue) {
|
||||||
|
// next = queue.poll();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if(next == null)
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// if(proxy.findScreenFromBrowser(next.browser, lookupResult)) {
|
||||||
|
// Object[] args = (next.args == null) ? new Object[0] : parseArgs(next.args);
|
||||||
|
//
|
||||||
|
// if(args == null)
|
||||||
|
// next.callback.failure(400, "Malformed request parameters");
|
||||||
|
// else {
|
||||||
|
// try {
|
||||||
|
// handlers.get(next.query).handleQuery(next.callback, lookupResult.tes, lookupResult.side, args);
|
||||||
|
// } catch(Throwable t) {
|
||||||
|
// Log.warningEx("Could not execute JS query %s(%s)", t, next.query, (next.args == null) ? "" : next.args);
|
||||||
|
// next.callback.failure(500, "Internal error");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else
|
||||||
|
// next.callback.failure(403, "A screen is required");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public boolean canHandleQuery(String q) {
|
||||||
|
// return handlers.containsKey(q);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static Object[] parseArgs(String args) {
|
||||||
|
// ArrayList<String> array = new ArrayList<>();
|
||||||
|
// int lastIdx = 0;
|
||||||
|
// boolean inString = false;
|
||||||
|
// boolean escape = false;
|
||||||
|
// boolean hadString = false;
|
||||||
|
//
|
||||||
|
// for(int i = 0; i < args.length(); i++) {
|
||||||
|
// char chr = args.charAt(i);
|
||||||
|
//
|
||||||
|
// if(inString) {
|
||||||
|
// if(escape)
|
||||||
|
// escape = false;
|
||||||
|
// else {
|
||||||
|
// if(chr == '\"')
|
||||||
|
// inString = false;
|
||||||
|
// else if(chr == '\\')
|
||||||
|
// escape = true;
|
||||||
|
// }
|
||||||
|
// } else if(chr == '\"') {
|
||||||
|
// if(hadString)
|
||||||
|
// return null;
|
||||||
|
//
|
||||||
|
// inString = true;
|
||||||
|
// hadString = true;
|
||||||
|
// } else if(chr == ',') {
|
||||||
|
// array.add(args.substring(lastIdx, i).trim());
|
||||||
|
// lastIdx = i + 1;
|
||||||
|
// hadString = false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if(inString)
|
||||||
|
// return null; //Non terminated string
|
||||||
|
//
|
||||||
|
// array.add(args.substring(lastIdx).trim());
|
||||||
|
// Object[] ret = new Object[array.size()];
|
||||||
|
//
|
||||||
|
// for(int i = 0; i < ret.length; i++) {
|
||||||
|
// String str = array.get(i);
|
||||||
|
// if(str.isEmpty())
|
||||||
|
// return null; //Nah...
|
||||||
|
//
|
||||||
|
// if(str.charAt(0) == '\"') //String
|
||||||
|
// ret[i] = str.substring(1, str.length() - 1);
|
||||||
|
// else {
|
||||||
|
// try {
|
||||||
|
// ret[i] = Double.parseDouble(str);
|
||||||
|
// } catch(NumberFormatException ex) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return ret;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void register(String query, IScreenQueryHandler handler) {
|
||||||
|
// handlers.put(query.toLowerCase(), handler);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public ServerQuery fulfillQuery(int id) {
|
||||||
|
// int toRemove = -1;
|
||||||
|
//
|
||||||
|
// for(int i = 0; i < serverQueries.size(); i++) {
|
||||||
|
// ServerQuery sq = serverQueries.get(i);
|
||||||
|
//
|
||||||
|
// if(sq.id == id) {
|
||||||
|
// toRemove = i;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if(toRemove < 0)
|
||||||
|
// return null;
|
||||||
|
// else
|
||||||
|
// return serverQueries.remove(toRemove);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private void makeServerQuery(TileEntityScreen tes, BlockSide side, IJSQueryCallback cb, JSServerRequest type, Object ... data) {
|
||||||
|
// ServerQuery ret = new ServerQuery(tes, side, cb);
|
||||||
|
// serverQueries.add(ret);
|
||||||
|
//
|
||||||
|
// WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.jsRequest(tes, side, ret.id, type, data));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private void registerDefaults() {
|
||||||
|
// VideoType.registerQueries(this);
|
||||||
|
//
|
||||||
|
// register("GetSize", (cb, tes, side, args) -> {
|
||||||
|
// Vector2i size = tes.getScreen(side).size;
|
||||||
|
// cb.success("{\"x\":" + size.x + ",\"y\":" + size.y + "}");
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// register("GetRedstoneAt", (cb, tes, side, args) -> {
|
||||||
|
// if(!tes.hasUpgrade(side, DefaultUpgrade.REDINPUT)) {
|
||||||
|
// cb.failure(403, "Missing upgrade");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if(args.length == 2 && args[0] instanceof Double && args[1] instanceof Double) {
|
||||||
|
// TileEntityScreen.Screen scr = tes.getScreen(side);
|
||||||
|
// int x = ((Double) args[0]).intValue();
|
||||||
|
// int y = ((Double) args[1]).intValue();
|
||||||
|
//
|
||||||
|
// if(x < 0 || x >= scr.size.x || y < 0 || y >= scr.size.y)
|
||||||
|
// cb.failure(403, "Out of range");
|
||||||
|
// else {
|
||||||
|
// BlockPos bpos = (new Vector3i(tes.getBlockPos())).addMul(side.right, x).addMul(side.up, y).toBlock();
|
||||||
|
// int level = tes.getLevel().getBlockState(bpos).getValue(BlockScreen.emitting) ? 0 : tes.getLevel().getSignal(bpos, Direction.values()[side.reverse().ordinal()]);
|
||||||
|
// cb.success("{\"level\":" + level + "}");
|
||||||
|
// }
|
||||||
|
// } else
|
||||||
|
// cb.failure(400, "Wrong arguments");
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// register("GetRedstoneArray", (cb, tes, side, args) -> {
|
||||||
|
// if(tes.hasUpgrade(side, DefaultUpgrade.REDINPUT)) {
|
||||||
|
// final Direction facing = Direction.values()[side.reverse().ordinal()];
|
||||||
|
// final StringJoiner resp = new StringJoiner(",", "{\"levels\":[", "]}");
|
||||||
|
//
|
||||||
|
// tes.forEachScreenBlocks(side, bp -> {
|
||||||
|
// if(tes.getLevel().getBlockState(bp).getValue(BlockScreen.emitting))
|
||||||
|
// resp.add("0");
|
||||||
|
// else
|
||||||
|
// resp.add("" + tes.getLevel().getSignal(bp, facing));
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// cb.success(resp.toString());
|
||||||
|
// } else
|
||||||
|
// cb.failure(403, "Missing upgrade");
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// register("ClearRedstone", (cb, tes, side, args) -> {
|
||||||
|
// if(tes.hasUpgrade(side, DefaultUpgrade.REDOUTPUT)) {
|
||||||
|
// if(tes.getScreen(side).owner.uuid.equals(mc.player.getGameProfile().getId()))
|
||||||
|
// makeServerQuery(tes, side, cb, JSServerRequest.CLEAR_REDSTONE);
|
||||||
|
// else
|
||||||
|
// cb.success("{\"status\":\"notOwner\"}");
|
||||||
|
// } else
|
||||||
|
// cb.failure(403, "Missing upgrade");
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// register("SetRedstoneAt", (cb, tes, side, args) -> {
|
||||||
|
// if(args.length != 3 || !Arrays.stream(args).allMatch((obj) -> obj instanceof Double)) {
|
||||||
|
// cb.failure(400, "Wrong arguments");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if(!tes.hasUpgrade(side, DefaultUpgrade.REDOUTPUT)) {
|
||||||
|
// cb.failure(403, "Missing upgrade");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if(!tes.getScreen(side).owner.uuid.equals(mc.player.getGameProfile().getId())) {
|
||||||
|
// cb.success("{\"status\":\"notOwner\"}");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// int x = ((Double) args[0]).intValue();
|
||||||
|
// int y = ((Double) args[1]).intValue();
|
||||||
|
// boolean state = ((Double) args[2]) > 0.0;
|
||||||
|
//
|
||||||
|
// Vector2i size = tes.getScreen(side).size;
|
||||||
|
// if(x < 0 || x >= size.x || y < 0 || y >= size.y) {
|
||||||
|
// cb.failure(403, "Out of range");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// makeServerQuery(tes, side, cb, JSServerRequest.SET_REDSTONE_AT, x, y, state);
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// register("IsEmitting", (cb, tes, side, args) -> {
|
||||||
|
// if(!tes.hasUpgrade(side, DefaultUpgrade.REDOUTPUT)) {
|
||||||
|
// cb.failure(403, "Missing upgrade");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if(args.length == 2 && args[0] instanceof Double && args[1] instanceof Double) {
|
||||||
|
// TileEntityScreen.Screen scr = tes.getScreen(side);
|
||||||
|
// int x = ((Double) args[0]).intValue();
|
||||||
|
// int y = ((Double) args[1]).intValue();
|
||||||
|
//
|
||||||
|
// if(x < 0 || x >= scr.size.x || y < 0 || y >= scr.size.y)
|
||||||
|
// cb.failure(403, "Out of range");
|
||||||
|
// else {
|
||||||
|
// BlockPos bpos = (new Vector3i(tes.getBlockPos())).addMul(side.right, x).addMul(side.up, y).toBlock();
|
||||||
|
// boolean e = tes.getLevel().getBlockState(bpos).getValue(BlockScreen.emitting);
|
||||||
|
// cb.success("{\"emitting\":" + (e ? "true" : "false") + "}");
|
||||||
|
// }
|
||||||
|
// } else
|
||||||
|
// cb.failure(400, "Wrong arguments");
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// register("GetEmissionArray", (cb, tes, side, args) -> {
|
||||||
|
// if(tes.hasUpgrade(side, DefaultUpgrade.REDOUTPUT)) {
|
||||||
|
// final StringJoiner resp = new StringJoiner(",", "{\"emission\":[", "]}");
|
||||||
|
// tes.forEachScreenBlocks(side, bp -> resp.add(tes.getLevel().getBlockState(bp).getValue(BlockScreen.emitting) ? "1" : "0"));
|
||||||
|
// cb.success(resp.toString());
|
||||||
|
// } else
|
||||||
|
// cb.failure(403, "Missing upgrade");
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// register("GetLocation", (cb, tes, side, args) -> {
|
||||||
|
// if(!tes.hasUpgrade(side, DefaultUpgrade.GPS)) {
|
||||||
|
// cb.failure(403, "Missing upgrade");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// BlockPos bp = tes.getBlockPos();
|
||||||
|
// cb.success("{\"x\":" + bp.getX() + ",\"y\":" + bp.getY() + ",\"z\":" + bp.getZ() + ",\"side\":\"" + side + "\"}");
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// register("GetUpgrades", (cb, tes, side, args) -> {
|
||||||
|
// final StringBuilder sb = new StringBuilder("{\"upgrades\":[");
|
||||||
|
// final ArrayList<ItemStack> upgrades = tes.getScreen(side).upgrades;
|
||||||
|
//
|
||||||
|
// for(int i = 0; i < upgrades.size(); i++) {
|
||||||
|
// if(i > 0)
|
||||||
|
// sb.append(',');
|
||||||
|
//
|
||||||
|
// sb.append('\"');
|
||||||
|
// sb.append(Util.addSlashes(((IUpgrade) upgrades.get(i).getItem()).getJSName(upgrades.get(i))));
|
||||||
|
// sb.append('\"');
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// cb.success(sb.append("]}").toString());
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// register("IsOwner", (cb, tes, side, args) -> {
|
||||||
|
// boolean res = (tes.getScreen(side).owner != null && tes.getScreen(side).owner.uuid.equals(mc.player.getGameProfile().getId()));
|
||||||
|
// cb.success("{\"isOwner\":" + (res ? "true}" : "false}"));
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// register("GetRotation", (cb, tes, side, args) -> cb.success("{\"rotation\":" + tes.getScreen(side).rotation.ordinal() + "}"));
|
||||||
|
// register("GetSide", (cb, tes, side, args) -> cb.success("{\"side\":" + tes.getScreen(side).side.ordinal() + "}"));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//}
|
||||||
215
src/main/java/net/montoyo/wd/client/WDScheme.java
Normal file
215
src/main/java/net/montoyo/wd/client/WDScheme.java
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client;
|
||||||
|
|
||||||
|
import net.montoyo.wd.miniserv.Constants;
|
||||||
|
import net.montoyo.wd.miniserv.client.Client;
|
||||||
|
import net.montoyo.wd.miniserv.client.ClientTaskGetFile;
|
||||||
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
import net.montoyo.wd.utilities.serialization.Util;
|
||||||
|
import org.cef.callback.CefCallback;
|
||||||
|
import org.cef.handler.CefResourceHandler;
|
||||||
|
import org.cef.misc.IntRef;
|
||||||
|
import org.cef.misc.StringRef;
|
||||||
|
import org.cef.network.CefRequest;
|
||||||
|
import org.cef.network.CefResponse;
|
||||||
|
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class WDScheme implements CefResourceHandler {
|
||||||
|
|
||||||
|
private static final String ERROR_PAGE = "<!DOCTYPE html><html><head></head><body><h1>%d %s</h1><hr /><i>Miniserv powered by WebDisplays</i></body></html>";
|
||||||
|
private ClientTaskGetFile task;
|
||||||
|
private boolean isErrorPage;
|
||||||
|
|
||||||
|
String url;
|
||||||
|
boolean onlyError = false;
|
||||||
|
|
||||||
|
public WDScheme(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean processRequest(CefRequest cefRequest, CefCallback cefCallback) {
|
||||||
|
url = cefRequest.getURL();
|
||||||
|
|
||||||
|
url = url.substring("webdisplays://".length());
|
||||||
|
|
||||||
|
int pos = url.indexOf('/');
|
||||||
|
if (pos < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
String uuidStr = url.substring(0, pos);
|
||||||
|
String fileStr = url.substring(pos + 1);
|
||||||
|
|
||||||
|
fileStr = URLDecoder.decode(fileStr, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
if (uuidStr.isEmpty() || Util.isFileNameInvalid(fileStr)) {
|
||||||
|
// invalid URL or no UUID
|
||||||
|
onlyError = true;
|
||||||
|
cefCallback.Continue();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID uuid;
|
||||||
|
try {
|
||||||
|
uuid = UUID.fromString(uuidStr);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
// invalid UUID
|
||||||
|
onlyError = true;
|
||||||
|
cefCallback.Continue();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
task = new ClientTaskGetFile(uuid, fileStr);
|
||||||
|
boolean doContinue = Client.getInstance().addTask(task);
|
||||||
|
if (doContinue) cefCallback.Continue();
|
||||||
|
return doContinue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getResponseHeaders(CefResponse cefResponse, IntRef contentLength, StringRef redir) {
|
||||||
|
int status;
|
||||||
|
if (onlyError) {
|
||||||
|
status = Constants.GETF_STATUS_BAD_NAME;
|
||||||
|
} else {
|
||||||
|
Log.info("Waiting for response...");
|
||||||
|
status = task.waitForResponse();
|
||||||
|
Log.info("Got response %d", status);
|
||||||
|
|
||||||
|
if (status == 0) {
|
||||||
|
//OK
|
||||||
|
int extPos = task.getFileName().lastIndexOf('.');
|
||||||
|
if (extPos >= 0) {
|
||||||
|
String mime = mapMime(task.getFileName().substring(extPos + 1));
|
||||||
|
|
||||||
|
if (mime != null)
|
||||||
|
cefResponse.setMimeType(mime);
|
||||||
|
}
|
||||||
|
|
||||||
|
cefResponse.setStatus(200);
|
||||||
|
cefResponse.setStatusText("OK");
|
||||||
|
contentLength.set(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int errCode;
|
||||||
|
String errStr;
|
||||||
|
|
||||||
|
if (status == Constants.GETF_STATUS_NOT_FOUND) {
|
||||||
|
errCode = 404;
|
||||||
|
errStr = "Not Found";
|
||||||
|
} else if (status == Constants.GETF_STATUS_TIMED_OUT) {
|
||||||
|
errCode = 408;
|
||||||
|
errStr = "Timed Out";
|
||||||
|
} else if (status == Constants.GETF_STATUS_BAD_NAME) {
|
||||||
|
errCode = 418;
|
||||||
|
errStr = "I'm a teapot";
|
||||||
|
} else {
|
||||||
|
errCode = 500;
|
||||||
|
errStr = "Internal Server Error";
|
||||||
|
}
|
||||||
|
|
||||||
|
// reporting the actual status and text makes CEF not display the page
|
||||||
|
cefResponse.setStatus(200);
|
||||||
|
cefResponse.setStatusText("OK");
|
||||||
|
cefResponse.setMimeType("text/html");
|
||||||
|
|
||||||
|
dataToWrite = String.format(ERROR_PAGE, errCode, errStr).getBytes(StandardCharsets.UTF_8);
|
||||||
|
dataOffset = 0;
|
||||||
|
amountToWrite = dataToWrite.length;
|
||||||
|
isErrorPage = true;
|
||||||
|
contentLength.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] dataToWrite;
|
||||||
|
private int dataOffset;
|
||||||
|
private int amountToWrite;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean readResponse(byte[] output, int bytesToRead, IntRef bytesRead, CefCallback cefCallback) {
|
||||||
|
if (dataToWrite == null) {
|
||||||
|
if (isErrorPage) {
|
||||||
|
bytesRead.set(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataToWrite = task.waitForData();
|
||||||
|
dataOffset = 3; //packet ID + size
|
||||||
|
amountToWrite = task.getDataLength();
|
||||||
|
|
||||||
|
if (amountToWrite <= 0) {
|
||||||
|
dataToWrite = null;
|
||||||
|
bytesRead.set(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int toWrite = bytesToRead;
|
||||||
|
if (toWrite > amountToWrite)
|
||||||
|
toWrite = amountToWrite;
|
||||||
|
|
||||||
|
System.arraycopy(dataToWrite, dataOffset, output, 0, toWrite);
|
||||||
|
bytesRead.set(toWrite);
|
||||||
|
|
||||||
|
dataOffset += toWrite;
|
||||||
|
amountToWrite -= toWrite;
|
||||||
|
|
||||||
|
if (amountToWrite <= 0) {
|
||||||
|
if (!isErrorPage)
|
||||||
|
task.nextData();
|
||||||
|
|
||||||
|
dataToWrite = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
Log.info("Scheme query canceled or finished.");
|
||||||
|
if (!onlyError)
|
||||||
|
task.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String mapMime(String ext) {
|
||||||
|
switch (ext) {
|
||||||
|
case "htm":
|
||||||
|
case "html":
|
||||||
|
return "text/html";
|
||||||
|
|
||||||
|
case "css":
|
||||||
|
return "text/css";
|
||||||
|
|
||||||
|
case "js":
|
||||||
|
return "text/javascript";
|
||||||
|
|
||||||
|
case "png":
|
||||||
|
return "image/png";
|
||||||
|
|
||||||
|
case "jpg":
|
||||||
|
case "jpeg":
|
||||||
|
return "image/jpeg";
|
||||||
|
|
||||||
|
case "gif":
|
||||||
|
return "image/gif";
|
||||||
|
|
||||||
|
case "svg":
|
||||||
|
return "image/svg+xml";
|
||||||
|
|
||||||
|
case "xml":
|
||||||
|
return "text/xml";
|
||||||
|
|
||||||
|
case "txt":
|
||||||
|
return "text/plain";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
116
src/main/java/net/montoyo/wd/client/audio/WDAudioSource.java
Normal file
116
src/main/java/net/montoyo/wd/client/audio/WDAudioSource.java
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package net.montoyo.wd.client.audio;
|
||||||
|
|
||||||
|
import net.minecraft.client.resources.sounds.Sound;
|
||||||
|
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||||
|
import net.minecraft.client.sounds.AudioStream;
|
||||||
|
import net.minecraft.client.sounds.SoundBufferLibrary;
|
||||||
|
import net.minecraft.client.sounds.SoundManager;
|
||||||
|
import net.minecraft.client.sounds.WeighedSoundEvents;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.util.valueproviders.SampledFloat;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.ScreenData;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public class WDAudioSource implements SoundInstance {
|
||||||
|
private static final ResourceLocation location = ResourceLocation.fromNamespaceAndPath("webdisplays", "audio_source");
|
||||||
|
private static final WeighedSoundEvents events = new WeighedSoundEvents(
|
||||||
|
location, "webdisplays.browser"
|
||||||
|
);
|
||||||
|
private static final SampledFloat CONST_1 = new SampledFloat() {
|
||||||
|
@Override
|
||||||
|
public float sample(RandomSource pRandom) {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private final Sound sound = new Sound(
|
||||||
|
ResourceLocation.fromNamespaceAndPath("webdisplays", "unused"),
|
||||||
|
CONST_1,
|
||||||
|
CONST_1,
|
||||||
|
1, Sound.Type.SOUND_EVENT,
|
||||||
|
true, false,
|
||||||
|
100
|
||||||
|
);
|
||||||
|
ScreenBlockEntity blockEntity;
|
||||||
|
ScreenData data;
|
||||||
|
|
||||||
|
public WDAudioSource(ScreenBlockEntity blockEntity, ScreenData data) {
|
||||||
|
this.blockEntity = blockEntity;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public WeighedSoundEvents resolve(SoundManager pManager) {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<AudioStream> getStream(SoundBufferLibrary soundBuffers, Sound sound, boolean looping) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Sound getSound() {
|
||||||
|
return sound;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SoundSource getSource() {
|
||||||
|
return SoundSource.RECORDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLooping() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRelative() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDelay() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getVolume() {
|
||||||
|
return blockEntity.ytVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getPitch() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getX() {
|
||||||
|
return blockEntity.getBlockPos().getX();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getY() {
|
||||||
|
return blockEntity.getBlockPos().getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getZ() {
|
||||||
|
return blockEntity.getBlockPos().getZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Attenuation getAttenuation() {
|
||||||
|
return Attenuation.LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/java/net/montoyo/wd/client/gui/CommandHandler.java
Normal file
18
src/main/java/net/montoyo/wd/client/gui/CommandHandler.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface CommandHandler {
|
||||||
|
|
||||||
|
String value();
|
||||||
|
|
||||||
|
}
|
||||||
377
src/main/java/net/montoyo/wd/client/gui/GuiKeyboard.java
Normal file
377
src/main/java/net/montoyo/wd/client/gui/GuiKeyboard.java
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui;
|
||||||
|
|
||||||
|
import com.cinemamod.mcef.MCEFBrowser;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.math.Axis;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.fml.ModList;
|
||||||
|
import net.neoforged.fml.loading.FMLPaths;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.client.gui.camera.KeyboardCamera;
|
||||||
|
import net.montoyo.wd.client.gui.controls.Button;
|
||||||
|
import net.montoyo.wd.client.gui.controls.Control;
|
||||||
|
import net.montoyo.wd.client.gui.controls.Label;
|
||||||
|
import net.montoyo.wd.client.gui.loading.FillControl;
|
||||||
|
import net.montoyo.wd.controls.builtin.ClickControl;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.ScreenData;
|
||||||
|
import net.montoyo.wd.net.WDNetworkRegistry;
|
||||||
|
import net.montoyo.wd.net.server_bound.C2SMessageScreenCtrl;
|
||||||
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector2i;
|
||||||
|
import net.montoyo.wd.utilities.serialization.TypeData;
|
||||||
|
import net.montoyo.wd.utilities.serialization.Util;
|
||||||
|
import org.cef.browser.CefBrowser;
|
||||||
|
import org.cef.misc.CefCursorType;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.vivecraft.client_vr.gameplay.VRPlayer;
|
||||||
|
import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class GuiKeyboard extends WDScreen {
|
||||||
|
|
||||||
|
private static final String WARNING_FNAME = "wd_keyboard_warning.txt";
|
||||||
|
|
||||||
|
private ScreenBlockEntity tes;
|
||||||
|
private BlockSide side;
|
||||||
|
private ScreenData data;
|
||||||
|
private final ArrayList<TypeData> evStack = new ArrayList<>();
|
||||||
|
private BlockPos kbPos;
|
||||||
|
private boolean showWarning = true;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private Label lblInfo;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private Button btnOk;
|
||||||
|
|
||||||
|
public GuiKeyboard() {
|
||||||
|
super(Component.nullToEmpty(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiKeyboard(ScreenBlockEntity tes, BlockSide side, BlockPos kbPos) {
|
||||||
|
this();
|
||||||
|
this.tes = tes;
|
||||||
|
this.side = side;
|
||||||
|
this.kbPos = kbPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addLoadCustomVariables(Map<String, Double> vars) {
|
||||||
|
vars.put("showWarning", showWarning ? 1.0 : 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final boolean vivecraftPresent;
|
||||||
|
|
||||||
|
static {
|
||||||
|
boolean vivePres = false;
|
||||||
|
if (ModList.get().isLoaded("vivecraft")) vivePres = true;
|
||||||
|
// I believe the non-mixin version of vivecraft is not a proper mod, so
|
||||||
|
// detect the mod reflectively if the mod is not found
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName("org.vivecraft.gameplay.screenhandlers.KeyboardHandler");
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
if (clazz == null) vivePres = false;
|
||||||
|
else {
|
||||||
|
Method m = clazz.getMethod("setOverlayShowing", boolean.class);
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
vivePres = m != null;
|
||||||
|
}
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
vivePres = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vivecraftPresent = vivePres;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
super.init();
|
||||||
|
|
||||||
|
if (minecraft.getSingleplayerServer() != null && !minecraft.getSingleplayerServer().isPublished())
|
||||||
|
showWarning = false; //NO NEED
|
||||||
|
else
|
||||||
|
showWarning = !hasUserReadWarning();
|
||||||
|
|
||||||
|
loadFrom(ResourceLocation.fromNamespaceAndPath("webdisplays", "gui/kb_right.json"));
|
||||||
|
|
||||||
|
if (showWarning) {
|
||||||
|
int maxLabelW = 0;
|
||||||
|
int totalH = 0;
|
||||||
|
|
||||||
|
for (Control ctrl : controls) {
|
||||||
|
if (ctrl != lblInfo && ctrl instanceof Label) {
|
||||||
|
if (ctrl.getWidth() > maxLabelW)
|
||||||
|
maxLabelW = ctrl.getWidth();
|
||||||
|
|
||||||
|
totalH += ctrl.getHeight();
|
||||||
|
ctrl.setPos((width - ctrl.getWidth()) / 2, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btnOk.setWidth(maxLabelW);
|
||||||
|
btnOk.setPos((width - maxLabelW) / 2, 0);
|
||||||
|
totalH += btnOk.getHeight();
|
||||||
|
|
||||||
|
int y = (height - totalH) / 2;
|
||||||
|
for (Control ctrl : controls) {
|
||||||
|
if (ctrl != lblInfo) {
|
||||||
|
ctrl.setPos(ctrl.getX(), y);
|
||||||
|
y += ctrl.getHeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!minecraft.isWindowActive()) {
|
||||||
|
minecraft.setWindowActive(true);
|
||||||
|
minecraft.mouseHandler.grabMouse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultBackground = showWarning;
|
||||||
|
syncTicks = 5;
|
||||||
|
|
||||||
|
if (vivecraftPresent)
|
||||||
|
if (VRPlayer.get() != null)
|
||||||
|
KeyboardHandler.setOverlayShowing(true);
|
||||||
|
|
||||||
|
KeyboardCamera.focus(tes, side);
|
||||||
|
|
||||||
|
data = tes.getScreen(side);
|
||||||
|
CefBrowser browser = data.browser;
|
||||||
|
((MCEFBrowser) browser).setCursor(CefCursorType.fromId(data.mouseType));
|
||||||
|
((MCEFBrowser) browser).setCursorChangeListener((id) -> {
|
||||||
|
data.mouseType = id;
|
||||||
|
((MCEFBrowser) browser).setCursor(CefCursorType.fromId(id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removed() {
|
||||||
|
super.removed();
|
||||||
|
if (vivecraftPresent)
|
||||||
|
if (VRPlayer.get() != null)
|
||||||
|
KeyboardHandler.setOverlayShowing(false);
|
||||||
|
KeyboardCamera.focus(null, null);
|
||||||
|
CefBrowser browser = data.browser;
|
||||||
|
if (browser instanceof MCEFBrowser mcef) {
|
||||||
|
mcef.setCursor(CefCursorType.POINTER);
|
||||||
|
mcef.setCursorChangeListener((cursor) -> data.mouseType = cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
removed();
|
||||||
|
super.onClose();
|
||||||
|
this.minecraft.popGuiLayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
if (quitOnEscape && keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||||
|
onClose();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
addKey(new TypeData(TypeData.Action.PRESS, keyCode, modifiers, scanCode));
|
||||||
|
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean charTyped(char codePoint, int modifiers) {
|
||||||
|
addKey(new TypeData(TypeData.Action.TYPE, codePoint, modifiers, 0));
|
||||||
|
return super.charTyped(codePoint, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
|
||||||
|
addKey(new TypeData(TypeData.Action.RELEASE, keyCode, modifiers, scanCode));
|
||||||
|
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addKey(TypeData data) {
|
||||||
|
tes.type(side, "[" + WebDisplays.GSON.toJson(data) + "]", kbPos);
|
||||||
|
|
||||||
|
evStack.add(data);
|
||||||
|
if (!evStack.isEmpty() && !syncRequested())
|
||||||
|
requestSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void sync() {
|
||||||
|
if(!evStack.isEmpty()) {
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.type(tes, side, WebDisplays.GSON.toJson(evStack), kbPos));
|
||||||
|
evStack.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuiSubscribe
|
||||||
|
public void onClick(Button.ClickEvent ev) {
|
||||||
|
if(showWarning && ev.getSource() == btnOk) {
|
||||||
|
writeUserAcknowledge();
|
||||||
|
|
||||||
|
for(Control ctrl: controls) {
|
||||||
|
if(ctrl instanceof Label) {
|
||||||
|
Label lbl = (Label) ctrl;
|
||||||
|
lbl.setVisible(!lbl.isVisible());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btnOk.setDisabled(true);
|
||||||
|
btnOk.setVisible(false);
|
||||||
|
showWarning = false;
|
||||||
|
defaultBackground = false;
|
||||||
|
minecraft.setWindowActive(true);
|
||||||
|
minecraft.mouseHandler.grabMouse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasUserReadWarning() {
|
||||||
|
try {
|
||||||
|
File f = new File(FMLPaths.GAMEDIR.get().toString(), WARNING_FNAME);
|
||||||
|
|
||||||
|
if(f.exists()) {
|
||||||
|
BufferedReader br = new BufferedReader(new FileReader(f));
|
||||||
|
String str = br.readLine();
|
||||||
|
Util.silentClose(br);
|
||||||
|
|
||||||
|
return str != null && str.trim().equalsIgnoreCase("read");
|
||||||
|
}
|
||||||
|
} catch(Throwable t) {
|
||||||
|
Log.warningEx("Can't know if user has already read the warning", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeUserAcknowledge() {
|
||||||
|
try {
|
||||||
|
File f = new File(FMLPaths.GAMEDIR.get().toString(), WARNING_FNAME);
|
||||||
|
|
||||||
|
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
|
||||||
|
bw.write("read\n");
|
||||||
|
Util.silentClose(bw);
|
||||||
|
} catch(Throwable t) {
|
||||||
|
Log.warningEx("Can't write that the user read the warning", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||||
|
return bp.equals(kbPos) || (bp.equals(tes.getBlockPos()) && side == this.side);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void mouse(double mouseX, double mouseY, Consumer<Vector2i> func) {
|
||||||
|
float pct = this.lastPartialTick;
|
||||||
|
|
||||||
|
double fov = Minecraft.getInstance().options.fov().get().doubleValue();
|
||||||
|
|
||||||
|
mouseX /= width;
|
||||||
|
mouseY /= height;
|
||||||
|
|
||||||
|
mouseX -= 0.5;
|
||||||
|
mouseY -= 0.5;
|
||||||
|
mouseY = -mouseY;
|
||||||
|
|
||||||
|
Matrix4f proj = Minecraft.getInstance().gameRenderer.getProjectionMatrix(fov);
|
||||||
|
|
||||||
|
Entity e = Minecraft.getInstance().getEntityRenderDispatcher().camera.getEntity();
|
||||||
|
|
||||||
|
PoseStack camera = new PoseStack();
|
||||||
|
float[] angle = KeyboardCamera.getAngle(e, pct);
|
||||||
|
camera.mulPose(Axis.XP.rotationDegrees(angle[0]));
|
||||||
|
camera.mulPose(Axis.YP.rotationDegrees(angle[1] + 180.0F));
|
||||||
|
|
||||||
|
Vector4f coord = new Vector4f(2f * (float) mouseX, 2 * (float) mouseY, 0, 1f);
|
||||||
|
coord.add(proj.invert().transform(coord));
|
||||||
|
coord = camera.last().pose().invert().transform(coord);
|
||||||
|
|
||||||
|
Vec3 vec3 = e.getEyePosition(pct);
|
||||||
|
Vec3 vec31 = new Vec3(coord.x, coord.y, coord.z).normalize();
|
||||||
|
|
||||||
|
BlockHitResult result = tes.trace(side, vec3, vec31);
|
||||||
|
if (result.getType() != HitResult.Type.MISS) {
|
||||||
|
tes.interact(result, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
this.lastPartialTick = ptt;
|
||||||
|
super.render(poseStack, mouseX, mouseY, ptt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float lastPartialTick = 0f;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseMoved(double mouseX, double mouseY) {
|
||||||
|
mouse(mouseX, mouseY, (hit) -> {
|
||||||
|
tes.handleMouseEvent(side, ClickControl.ControlType.MOVE, hit, -1);
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.laserMove(tes, side, hit));
|
||||||
|
});
|
||||||
|
|
||||||
|
super.mouseMoved(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
mouse(mouseX, mouseY, (hit) -> {
|
||||||
|
tes.handleMouseEvent(side, ClickControl.ControlType.MOVE, hit, -1);
|
||||||
|
tes.handleMouseEvent(side, ClickControl.ControlType.DOWN, hit, button);
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.laserDown(tes, side, hit, button));
|
||||||
|
});
|
||||||
|
|
||||||
|
KeyboardCamera.setMouse(button, true);
|
||||||
|
|
||||||
|
return super.mouseClicked(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||||
|
mouse(mouseX, mouseY, (hit) -> {
|
||||||
|
tes.handleMouseEvent(side, ClickControl.ControlType.MOVE, hit, -1);
|
||||||
|
tes.handleMouseEvent(side, ClickControl.ControlType.UP, hit, button);
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.laserUp(tes, side, button));
|
||||||
|
});
|
||||||
|
|
||||||
|
KeyboardCamera.setMouse(button, false);
|
||||||
|
|
||||||
|
return super.mouseReleased(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
double mouseX = Minecraft.getInstance().mouseHandler.xpos() / Minecraft.getInstance().getWindow().getWidth();
|
||||||
|
double mouseY = Minecraft.getInstance().mouseHandler.ypos() / Minecraft.getInstance().getWindow().getHeight();
|
||||||
|
|
||||||
|
mouse(mouseX * width, mouseY * height, (hit) -> {
|
||||||
|
tes.handleMouseEvent(side, ClickControl.ControlType.MOVE, hit, -1);
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.laserMove(tes, side, hit));
|
||||||
|
});
|
||||||
|
|
||||||
|
super.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
356
src/main/java/net/montoyo/wd/client/gui/GuiMinePad.java
Normal file
356
src/main/java/net/montoyo/wd/client/gui/GuiMinePad.java
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui;
|
||||||
|
|
||||||
|
import com.cinemamod.mcef.MCEFBrowser;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.mojang.blaze3d.platform.InputConstants;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||||
|
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||||
|
import com.mojang.blaze3d.vertex.Tesselator;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.locale.Language;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.client.ClientProxy;
|
||||||
|
import net.montoyo.wd.utilities.browser.WDBrowser;
|
||||||
|
import net.montoyo.wd.utilities.browser.handlers.js.Scripts;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import org.cef.misc.CefCursorType;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static net.neoforged.api.distmarker.Dist.CLIENT;
|
||||||
|
|
||||||
|
@OnlyIn(CLIENT)
|
||||||
|
public class GuiMinePad extends WDScreen {
|
||||||
|
|
||||||
|
private ClientProxy.PadData pad;
|
||||||
|
private double vx;
|
||||||
|
private double vy;
|
||||||
|
private double vw;
|
||||||
|
private double vh;
|
||||||
|
|
||||||
|
public GuiMinePad() {
|
||||||
|
super(Component.nullToEmpty(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiMinePad(ClientProxy.PadData pad) {
|
||||||
|
this();
|
||||||
|
this.pad = pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
int trueWidth, trueHeight;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
vw = ((double) width) - 32.0f;
|
||||||
|
vh = vw / WebDisplays.PAD_RATIO;
|
||||||
|
vx = 16.0f;
|
||||||
|
vy = (((double) height) - vh) / 2.0f;
|
||||||
|
|
||||||
|
trueWidth = width;
|
||||||
|
trueHeight = height;
|
||||||
|
|
||||||
|
this.width = (int) vw;
|
||||||
|
this.height = (int) vh;
|
||||||
|
|
||||||
|
super.init();
|
||||||
|
|
||||||
|
((MCEFBrowser) pad.view).setCursor(CefCursorType.fromId(pad.activeCursor));
|
||||||
|
((MCEFBrowser) pad.view).setCursorChangeListener((id) -> {
|
||||||
|
pad.activeCursor = id;
|
||||||
|
((MCEFBrowser) pad.view).setCursor(CefCursorType.fromId(id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addRect(BufferBuilder bb, org.joml.Matrix4f pose, float x, float y, float w, float h) {
|
||||||
|
bb.addVertex(pose, x, y, 0.0f).setColor(255, 255, 255, 255);
|
||||||
|
bb.addVertex(pose, x + w, y, 0.0f).setColor(255, 255, 255, 255);
|
||||||
|
bb.addVertex(pose, x + w, y + h, 0.0f).setColor(255, 255, 255, 255);
|
||||||
|
bb.addVertex(pose, x, y + h, 0.0f).setColor(255, 255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(GuiGraphics graphics, int mouseX, int mouseY, float ptt) {
|
||||||
|
width = trueWidth;
|
||||||
|
height = trueHeight;
|
||||||
|
renderBackground(graphics, mouseX, mouseY, ptt);
|
||||||
|
width = (int) vw;
|
||||||
|
height = (int) vh;
|
||||||
|
|
||||||
|
RenderSystem.disableCull();
|
||||||
|
RenderSystem.setShaderColor(0.73f, 0.73f, 0.73f, 1.0f);
|
||||||
|
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||||
|
BufferBuilder bb = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
|
||||||
|
org.joml.Matrix4f pose = graphics.pose().last().pose();
|
||||||
|
addRect(bb, pose, (float) vx, (float) (vy - 16), (float) vw, 16f);
|
||||||
|
addRect(bb, pose, (float) vx, (float) (vy + vh), (float) vw, 16f);
|
||||||
|
addRect(bb, pose, (float) (vx - 16), (float) vy, 16f, (float) vh);
|
||||||
|
addRect(bb, pose, (float) (vx + vw), (float) vy, 16f, (float) vh);
|
||||||
|
BufferUploader.drawWithShader(bb.buildOrThrow());
|
||||||
|
|
||||||
|
if (pad.view != null) {
|
||||||
|
// pad.view.draw(poseStack, vx, vy + vh, vx + vw, vy);
|
||||||
|
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
RenderSystem.disableDepthTest();
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionTexColorShader);
|
||||||
|
RenderSystem.setShaderTexture(0, ((MCEFBrowser) pad.view).getRenderer().getTextureID());
|
||||||
|
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR);
|
||||||
|
double x1 = vx;
|
||||||
|
double y1 = vy;
|
||||||
|
double x2 = vx + vw;
|
||||||
|
double y2 = vy + vh;
|
||||||
|
buffer.addVertex(graphics.pose().last().pose(), (float) x1, (float) y1, 0.0f).setUv(0.0F, 0.0F).setColor(1f, 1f, 1f, 1f);
|
||||||
|
buffer.addVertex(graphics.pose().last().pose(), (float) x2, (float) y1, 0.0f).setUv(1.0F, 0.0F).setColor(1f, 1f, 1f, 1f);
|
||||||
|
buffer.addVertex(graphics.pose().last().pose(), (float) x2, (float) y2, 0.0f).setUv(1.0F, 1.0F).setColor(1f, 1f, 1f, 1f);
|
||||||
|
buffer.addVertex(graphics.pose().last().pose(), (float) x1, (float) y2, 0.0f).setUv(0.0F, 1.0F).setColor(1f, 1f, 1f, 1f);
|
||||||
|
BufferUploader.drawWithShader(buffer.buildOrThrow());
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSystem.enableCull();
|
||||||
|
|
||||||
|
graphics.drawString(
|
||||||
|
minecraft.font, Language.getInstance().getOrDefault(
|
||||||
|
"webdisplays.gui.minepad.close"
|
||||||
|
), (int) vx + 4, (int) vy - minecraft.font.lineHeight - 3, 16777215, true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
return this.keyChanged(keyCode, scanCode, modifiers, true) || super.keyPressed(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
|
||||||
|
return this.keyChanged(keyCode, scanCode, modifiers, false) || super.keyReleased(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean charTyped(char codePoint, int modifiers) {
|
||||||
|
if (pad.view != null) {
|
||||||
|
((MCEFBrowser) pad.view).sendKeyTyped(codePoint, modifiers);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return super.charTyped(codePoint, modifiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copied from MCEF */
|
||||||
|
public boolean keyChanged(int keyCode, int scanCode, int modifiers, boolean pressed) {
|
||||||
|
assert minecraft != null;
|
||||||
|
if ((modifiers & GLFW.GLFW_MOD_SHIFT) == GLFW.GLFW_MOD_SHIFT && keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||||
|
onClose();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputConstants.Key iuKey = InputConstants.getKey(keyCode, scanCode);
|
||||||
|
String keystr = iuKey.getDisplayName().getString();
|
||||||
|
// System.out.println("KEY STR " + keystr);
|
||||||
|
if (keystr.length() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char key = keystr.charAt(keystr.length() - 1);
|
||||||
|
|
||||||
|
if (keystr.equals("Enter")) {
|
||||||
|
keyCode = 10;
|
||||||
|
key = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pad.view != null) {
|
||||||
|
if (pressed)
|
||||||
|
((MCEFBrowser) pad.view).sendKeyPress(keyCode, scanCode, modifiers);
|
||||||
|
else
|
||||||
|
((MCEFBrowser) pad.view).sendKeyRelease(keyCode, scanCode, modifiers);
|
||||||
|
|
||||||
|
if (pressed && key == '\n')
|
||||||
|
if (modifiers != 0) ((MCEFBrowser) pad.view).sendKeyTyped('\r', modifiers);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseMoved(double mouseX, double mouseY) {
|
||||||
|
super.mouseMoved(mouseX, mouseY);
|
||||||
|
mouse(-1, false, (int) mouseX, (int) mouseY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
mouse(button, true, (int) mouseX, (int) mouseY, 0);
|
||||||
|
return super.mouseClicked(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||||
|
mouse(button, false, (int) mouseX, (int) mouseY, 0);
|
||||||
|
return super.mouseReleased(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
|
||||||
|
double mx = (mouseX - vx) / vw;
|
||||||
|
double my = (mouseY - vy) / vh;
|
||||||
|
int sx = (int) (mx * WebDisplays.INSTANCE.padResX);
|
||||||
|
int sy = (int) (my * WebDisplays.INSTANCE.padResY);
|
||||||
|
// TODO: this doesn't work, and I don't understand why?
|
||||||
|
((MCEFBrowser) pad.view).sendMouseWheel(sx, sy, scrollY, (hasControlDown() && !hasAltDown() && !hasShiftDown()) ? GLFW.GLFW_MOD_CONTROL : 0);
|
||||||
|
|
||||||
|
return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void capturedMouse(double scaledX, double scaledY, int sx, int sy) {
|
||||||
|
double centerX = (int) (0.5 * (double) this.minecraft.getWindow().getGuiScaledWidth());
|
||||||
|
double centerY = (int) (0.5 * (double) this.minecraft.getWindow().getGuiScaledHeight());
|
||||||
|
|
||||||
|
if (sx == (int) centerX && sy == (int) centerY) return;
|
||||||
|
|
||||||
|
double mx = (centerX - vx) / vw;
|
||||||
|
double my = (centerY - vy) / vh;
|
||||||
|
double scaledCentX = (mx * WebDisplays.INSTANCE.padResX);
|
||||||
|
double scaledCentY = (my * WebDisplays.INSTANCE.padResY);
|
||||||
|
|
||||||
|
double deltX = scaledX - scaledCentX;
|
||||||
|
double deltY = scaledY - scaledCentY;
|
||||||
|
|
||||||
|
String scr = Scripts.MOUSE_EVENT;
|
||||||
|
pad.view.executeJavaScript(
|
||||||
|
scr
|
||||||
|
.replace("%xCoord%", "" + (int) centerX)
|
||||||
|
.replace("%yCoord%", "" + (int) centerY)
|
||||||
|
.replace("%xDelta%", "" + (deltX))
|
||||||
|
.replace("%yDelta%", "" + (deltY)),
|
||||||
|
"WebDisplays", 0
|
||||||
|
);
|
||||||
|
|
||||||
|
// lock mouse
|
||||||
|
try {
|
||||||
|
double xpos = (this.minecraft.getWindow().getScreenWidth() / 2);
|
||||||
|
double ypos = (this.minecraft.getWindow().getScreenHeight() / 2);
|
||||||
|
GLFW.glfwSetCursorPos(minecraft.getWindow().getWindow(), xpos, ypos);
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouse(int btn, boolean pressed, int sx, int sy, double scrollAmount) {
|
||||||
|
double mx = (sx - vx) / vw;
|
||||||
|
double my = (sy - vy) / vh;
|
||||||
|
|
||||||
|
if (pad.view != null && mx >= 0 && mx <= 1) {
|
||||||
|
//Scale again according to the webview
|
||||||
|
int scaledX = (int) (mx * WebDisplays.INSTANCE.padResX);
|
||||||
|
int scaledY = (int) (my * WebDisplays.INSTANCE.padResY);
|
||||||
|
|
||||||
|
if (btn == -1) {
|
||||||
|
if (locked)
|
||||||
|
capturedMouse(mx * WebDisplays.INSTANCE.padResX, my * WebDisplays.INSTANCE.padResY, sx, sy);
|
||||||
|
else ((MCEFBrowser) pad.view).sendMouseMove(scaledX, scaledY);
|
||||||
|
} else if (pressed)
|
||||||
|
((MCEFBrowser) pad.view).sendMousePress(scaledX, scaledY, btn);
|
||||||
|
else ((MCEFBrowser) pad.view).sendMouseRelease(scaledX, scaledY, btn);
|
||||||
|
pad.view.setFocus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<Character> getChar(int keyCode, int scanCode) {
|
||||||
|
String keystr = GLFW.glfwGetKeyName(keyCode, scanCode);
|
||||||
|
if (keystr == null) {
|
||||||
|
keystr = "\0";
|
||||||
|
}
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_ENTER) {
|
||||||
|
keystr = "\n";
|
||||||
|
}
|
||||||
|
if (keystr.length() == 0) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.of(keystr.charAt(keystr.length() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (pad.view == null)
|
||||||
|
minecraft.setScreen(null); //In case the user dies with the pad in the hand
|
||||||
|
pollElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removed() {
|
||||||
|
super.removed();
|
||||||
|
InputConstants.updateRawMouseInput(
|
||||||
|
minecraft.getWindow().getWindow(),
|
||||||
|
Minecraft.getInstance().options.rawMouseInput().get()
|
||||||
|
);
|
||||||
|
if (pad.view instanceof MCEFBrowser browser) {
|
||||||
|
browser.setCursor(CefCursorType.POINTER);
|
||||||
|
browser.setCursorChangeListener((cursor) -> {
|
||||||
|
pad.activeCursor = cursor;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
super.onClose();
|
||||||
|
removed();
|
||||||
|
this.minecraft.popGuiLayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean locked = false;
|
||||||
|
double lockCenterX = -1;
|
||||||
|
double lockCenterY = -1;
|
||||||
|
|
||||||
|
protected void updateCrd(JsonObject obj) {
|
||||||
|
if (obj.getAsJsonPrimitive("exists").getAsBoolean()) {
|
||||||
|
locked = true;
|
||||||
|
RenderSystem.recordRenderCall(() -> {
|
||||||
|
InputConstants.updateRawMouseInput(
|
||||||
|
minecraft.getWindow().getWindow(),
|
||||||
|
obj.getAsJsonPrimitive("unadjust").getAsBoolean()
|
||||||
|
);
|
||||||
|
GLFW.glfwSetInputMode(Minecraft.getInstance().getWindow().getWindow(), 208897, GLFW.GLFW_CURSOR_DISABLED);
|
||||||
|
});
|
||||||
|
lockCenterX = obj.getAsJsonPrimitive("x").getAsDouble() + obj.getAsJsonPrimitive("w").getAsDouble() / 2;
|
||||||
|
lockCenterY = obj.getAsJsonPrimitive("y").getAsDouble() + obj.getAsJsonPrimitive("h").getAsDouble() / 2;
|
||||||
|
} else {
|
||||||
|
if (locked) {
|
||||||
|
locked = false;
|
||||||
|
RenderSystem.recordRenderCall(()->{
|
||||||
|
InputConstants.updateRawMouseInput(
|
||||||
|
minecraft.getWindow().getWindow(),
|
||||||
|
Minecraft.getInstance().options.rawMouseInput().get()
|
||||||
|
);
|
||||||
|
GLFW.glfwSetInputMode(Minecraft.getInstance().getWindow().getWindow(), 208897, GLFW.GLFW_CURSOR_NORMAL);
|
||||||
|
GLFW.glfwSetCursor(Minecraft.getInstance().getWindow().getWindow(), CefCursorType.fromId(pad.activeCursor).glfwId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void pollElement() {
|
||||||
|
if (pad.view instanceof WDBrowser browser) {
|
||||||
|
JsonObject object = browser.pointerLockElement().getObj();
|
||||||
|
if (object != null) updateCrd(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
src/main/java/net/montoyo/wd/client/gui/GuiRedstoneCtrl.java
Normal file
74
src/main/java/net/montoyo/wd/client/gui/GuiRedstoneCtrl.java
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.montoyo.wd.client.gui.controls.Button;
|
||||||
|
import net.montoyo.wd.client.gui.controls.TextField;
|
||||||
|
import net.montoyo.wd.client.gui.loading.FillControl;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class GuiRedstoneCtrl extends WDScreen {
|
||||||
|
|
||||||
|
private ResourceLocation dimension;
|
||||||
|
private Vector3i pos;
|
||||||
|
private String risingEdgeURL;
|
||||||
|
private String fallingEdgeURL;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private TextField tfRisingEdge;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private TextField tfFallingEdge;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private Button btnOk;
|
||||||
|
|
||||||
|
public GuiRedstoneCtrl(Component component, ResourceLocation d, Vector3i p, String r, String f) {
|
||||||
|
super(component);
|
||||||
|
dimension = d;
|
||||||
|
pos = p;
|
||||||
|
risingEdgeURL = r;
|
||||||
|
fallingEdgeURL = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
super.init();
|
||||||
|
loadFrom(ResourceLocation.fromNamespaceAndPath("webdisplays", "gui/redstonectrl.json"));
|
||||||
|
tfRisingEdge.setText(risingEdgeURL);
|
||||||
|
tfFallingEdge.setText(fallingEdgeURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @GuiSubscribe
|
||||||
|
// public void onClick(Button.ClickEvent ev) {
|
||||||
|
// if(ev.getSource() == btnOk) {
|
||||||
|
// API mcef = ((ClientProxy) WebDisplays.PROXY).getMCEF();
|
||||||
|
//
|
||||||
|
// String rising = mcef.punycode(Util.addProtocol(tfRisingEdge.getText()));
|
||||||
|
// String falling = mcef.punycode(Util.addProtocol(tfFallingEdge.getText()));
|
||||||
|
// WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageRedstoneCtrl(pos, rising, falling));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// minecraft.setScreen(null);
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||||
|
return pos.equalsBlockPos(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getWikiPageName() {
|
||||||
|
return "Redstone_Controller";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
523
src/main/java/net/montoyo/wd/client/gui/GuiScreenConfig.java
Normal file
523
src/main/java/net/montoyo/wd/client/gui/GuiScreenConfig.java
Normal file
@@ -0,0 +1,523 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.resources.language.I18n;
|
||||||
|
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.client.gui.controls.*;
|
||||||
|
import net.montoyo.wd.client.gui.loading.FillControl;
|
||||||
|
import net.montoyo.wd.core.ScreenRights;
|
||||||
|
import net.montoyo.wd.entity.ScreenData;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.item.WDItem;
|
||||||
|
import net.montoyo.wd.net.WDNetworkRegistry;
|
||||||
|
import net.montoyo.wd.net.server_bound.C2SMessageScreenCtrl;
|
||||||
|
import net.montoyo.wd.utilities.*;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector2i;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.data.Rotation;
|
||||||
|
import net.montoyo.wd.utilities.serialization.NameUUIDPair;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class GuiScreenConfig extends WDScreen {
|
||||||
|
|
||||||
|
//Screen data
|
||||||
|
private final ScreenBlockEntity tes;
|
||||||
|
private final BlockSide side;
|
||||||
|
private NameUUIDPair owner;
|
||||||
|
private NameUUIDPair[] friends;
|
||||||
|
private int friendRights;
|
||||||
|
private int otherRights;
|
||||||
|
private Rotation rotation = Rotation.ROT_0;
|
||||||
|
private float aspectRatio;
|
||||||
|
|
||||||
|
//Autocomplete handling
|
||||||
|
private boolean waitingAC;
|
||||||
|
private int acFailTicks = -1;
|
||||||
|
|
||||||
|
private final ArrayList<NameUUIDPair> acResults = new ArrayList<>();
|
||||||
|
private boolean adding;
|
||||||
|
|
||||||
|
//Controls
|
||||||
|
@FillControl
|
||||||
|
private Label lblOwner;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private List lstFriends;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private Button btnAdd;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private TextField tfFriend;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private TextField tfResX;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private TextField tfResY;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private ControlGroup grpFriends;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private ControlGroup grpOthers;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox boxFSetUrl;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox boxFClick;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox boxFFriends;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox boxFOthers;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox boxFUpgrades;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox boxFResolution;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox boxOSetUrl;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox boxOClick;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox boxOUpgrades;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox boxOResolution;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private Button btnSetRes;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private UpgradeGroup ugUpgrades;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private Button btnChangeRot;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox cbLockRatio;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private CheckBox cbAutoVolume;
|
||||||
|
|
||||||
|
private CheckBox[] friendBoxes;
|
||||||
|
private CheckBox[] otherBoxes;
|
||||||
|
|
||||||
|
public GuiScreenConfig(Component component, ScreenBlockEntity tes, BlockSide side, NameUUIDPair[] friends, int fr, int or) {
|
||||||
|
super(component);
|
||||||
|
this.tes = tes;
|
||||||
|
this.side = side;
|
||||||
|
this.friends = friends;
|
||||||
|
friendRights = fr;
|
||||||
|
otherRights = or;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
super.init();
|
||||||
|
loadFrom(ResourceLocation.fromNamespaceAndPath("webdisplays", "gui/screencfg.json"));
|
||||||
|
|
||||||
|
friendBoxes = new CheckBox[] { boxFResolution, boxFUpgrades, boxFOthers, boxFFriends, boxFClick, boxFSetUrl };
|
||||||
|
boxFResolution.setUserdata(ScreenRights.MODIFY_SCREEN);
|
||||||
|
boxFUpgrades.setUserdata(ScreenRights.MANAGE_UPGRADES);
|
||||||
|
boxFOthers.setUserdata(ScreenRights.MANAGE_OTHER_RIGHTS);
|
||||||
|
boxFFriends.setUserdata(ScreenRights.MANAGE_FRIEND_LIST);
|
||||||
|
boxFClick.setUserdata(ScreenRights.INTERACT);
|
||||||
|
boxFSetUrl.setUserdata(ScreenRights.CHANGE_URL);
|
||||||
|
|
||||||
|
otherBoxes = new CheckBox[] { boxOResolution, boxOUpgrades, boxOClick, boxOSetUrl };
|
||||||
|
boxOResolution.setUserdata(ScreenRights.MODIFY_SCREEN);
|
||||||
|
boxOUpgrades.setUserdata(ScreenRights.MANAGE_UPGRADES);
|
||||||
|
boxOClick.setUserdata(ScreenRights.INTERACT);
|
||||||
|
boxOSetUrl.setUserdata(ScreenRights.CHANGE_URL);
|
||||||
|
|
||||||
|
ScreenData scr = tes.getScreen(side);
|
||||||
|
if(scr != null) {
|
||||||
|
owner = scr.owner;
|
||||||
|
rotation = scr.rotation;
|
||||||
|
|
||||||
|
tfResX.setText("" + scr.resolution.x);
|
||||||
|
tfResY.setText("" + scr.resolution.y);
|
||||||
|
aspectRatio = ((float) scr.resolution.x) / ((float) scr.resolution.y);
|
||||||
|
|
||||||
|
//Hopefully upgrades have been synchronized...
|
||||||
|
ugUpgrades.setUpgrades(scr.upgrades);
|
||||||
|
cbAutoVolume.setChecked(scr.autoVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(owner == null)
|
||||||
|
owner = new NameUUIDPair("???", UUID.randomUUID());
|
||||||
|
|
||||||
|
lblOwner.setLabel(lblOwner.getLabel() + ' ' + owner.name);
|
||||||
|
for(NameUUIDPair f : friends)
|
||||||
|
lstFriends.addElementRaw(f.name, f);
|
||||||
|
|
||||||
|
lstFriends.updateContent();
|
||||||
|
updateRights(friendRights, friendRights, friendBoxes, true);
|
||||||
|
updateRights(otherRights, otherRights, otherBoxes, true);
|
||||||
|
updateMyRights();
|
||||||
|
updateRotationStr();
|
||||||
|
|
||||||
|
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI( WebDisplays.INSTANCE.soundScreenCfg, 1.0f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRotationStr() {
|
||||||
|
btnChangeRot.setLabel(I18n.get("webdisplays.gui.screencfg.rot" + rotation.getAngleAsInt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFriend(String name) {
|
||||||
|
if(!name.isEmpty()) {
|
||||||
|
requestAutocomplete(name, true);
|
||||||
|
tfFriend.setDisabled(true);
|
||||||
|
adding = true;
|
||||||
|
waitingAC = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clickSetRes() {
|
||||||
|
ScreenData scr = tes.getScreen(side);
|
||||||
|
if(scr == null)
|
||||||
|
return; //WHATDAFUQ?
|
||||||
|
|
||||||
|
try {
|
||||||
|
int x = Integer.parseInt(tfResX.getText());
|
||||||
|
int y = Integer.parseInt(tfResY.getText());
|
||||||
|
if(x < 1 || y < 1)
|
||||||
|
throw new NumberFormatException(); //I'm lazy
|
||||||
|
|
||||||
|
if(x != scr.resolution.x || y != scr.resolution.y)
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.resolution(tes, side, new Vector2i(x, y)));
|
||||||
|
} catch(NumberFormatException ex) {
|
||||||
|
//Roll back
|
||||||
|
tfResX.setText("" + scr.resolution.x);
|
||||||
|
tfResY.setText("" + scr.resolution.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
btnSetRes.setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuiSubscribe
|
||||||
|
public void onClick(Button.ClickEvent ev) {
|
||||||
|
if(ev.getSource() == btnAdd && !waitingAC)
|
||||||
|
addFriend(tfFriend.getText().trim());
|
||||||
|
else if(ev.getSource() == btnSetRes)
|
||||||
|
clickSetRes();
|
||||||
|
else if(ev.getSource() == btnChangeRot) {
|
||||||
|
Rotation[] rots = Rotation.values();
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageScreenCtrl(tes, side, rots[(rotation.ordinal() + 1) % rots.length]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuiSubscribe
|
||||||
|
public void onEnterPressed(TextField.EnterPressedEvent ev) {
|
||||||
|
if(ev.getSource() == tfFriend && !waitingAC)
|
||||||
|
addFriend(ev.getText().trim());
|
||||||
|
else if((ev.getSource() == tfResX || ev.getSource() == tfResY) && !btnSetRes.isDisabled())
|
||||||
|
clickSetRes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuiSubscribe
|
||||||
|
public void onAutocomplete(TextField.TabPressedEvent ev) {
|
||||||
|
if(ev.getSource() == tfFriend && !waitingAC && !ev.getBeginning().isEmpty()) {
|
||||||
|
if(acResults.isEmpty()) {
|
||||||
|
waitingAC = true;
|
||||||
|
requestAutocomplete(ev.getBeginning(), false);
|
||||||
|
} else {
|
||||||
|
NameUUIDPair pair = acResults.remove(0);
|
||||||
|
tfFriend.setText(pair.name);
|
||||||
|
}
|
||||||
|
} else if(ev.getSource() == tfResX) {
|
||||||
|
tfResX.setFocused(false);
|
||||||
|
tfResY.focus();
|
||||||
|
tfResY.getMcField().setCursorPosition(0);
|
||||||
|
tfResY.getMcField().setHighlightPos(tfResY.getText().length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuiSubscribe
|
||||||
|
public void onTextChanged(TextField.TextChangedEvent ev) {
|
||||||
|
if(ev.getSource() == tfResX || ev.getSource() == tfResY) {
|
||||||
|
for(int i = 0; i < ev.getNewContent().length(); i++) {
|
||||||
|
if(!Character.isDigit(ev.getNewContent().charAt(i))) {
|
||||||
|
ev.getSource().setText(ev.getOldContent());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cbLockRatio.isChecked()) {
|
||||||
|
if(ev.getSource() == tfResX) {
|
||||||
|
try {
|
||||||
|
float val = (float) Integer.parseInt(ev.getNewContent());
|
||||||
|
val /= aspectRatio;
|
||||||
|
tfResY.setText("" + ((int) val));
|
||||||
|
} catch(NumberFormatException ex) {}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
float val = (float) Integer.parseInt(ev.getNewContent());
|
||||||
|
val *= aspectRatio;
|
||||||
|
tfResX.setText("" + ((int) val));
|
||||||
|
} catch(NumberFormatException ex) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btnSetRes.setDisabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuiSubscribe
|
||||||
|
public void onRemovePlayer(List.EntryClick ev) {
|
||||||
|
if(ev.getSource() == lstFriends)
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageScreenCtrl(tes, side, (NameUUIDPair) ev.getUserdata(), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuiSubscribe
|
||||||
|
public void onCheckboxChanged(CheckBox.CheckedEvent ev) {
|
||||||
|
if(isFriendCheckbox(ev.getSource())) {
|
||||||
|
int flag = (Integer) ev.getSource().getUserdata();
|
||||||
|
if(ev.isChecked())
|
||||||
|
friendRights |= flag;
|
||||||
|
else
|
||||||
|
friendRights &= ~flag;
|
||||||
|
|
||||||
|
requestSync();
|
||||||
|
} else if(isOtherCheckbox(ev.getSource())) {
|
||||||
|
int flag = (Integer) ev.getSource().getUserdata();
|
||||||
|
if(ev.isChecked())
|
||||||
|
otherRights |= flag;
|
||||||
|
else
|
||||||
|
otherRights &= ~flag;
|
||||||
|
|
||||||
|
requestSync();
|
||||||
|
} else if(ev.getSource() == cbLockRatio && ev.isChecked()) {
|
||||||
|
try {
|
||||||
|
int x = Integer.parseInt(tfResX.getText());
|
||||||
|
int y = Integer.parseInt(tfResY.getText());
|
||||||
|
|
||||||
|
aspectRatio = ((float) x) / ((float) y);
|
||||||
|
} catch(NumberFormatException ex) {
|
||||||
|
cbLockRatio.setChecked(false);
|
||||||
|
}
|
||||||
|
} else if(ev.getSource() == cbAutoVolume) WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.autoVol(tes, side, ev.isChecked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuiSubscribe
|
||||||
|
public void onRemoveUpgrade(UpgradeGroup.ClickEvent ev) {
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageScreenCtrl(tes, side, ev.getMouseOverStack()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFriendCheckbox(CheckBox cb) {
|
||||||
|
return Arrays.stream(friendBoxes).anyMatch(fb -> cb == fb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOtherCheckbox(CheckBox cb) {
|
||||||
|
return Arrays.stream(otherBoxes).anyMatch(ob -> cb == ob);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasFriend(NameUUIDPair f) {
|
||||||
|
return Arrays.stream(friends).anyMatch(f::equals);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutocompleteResult(NameUUIDPair pairs[]) {
|
||||||
|
waitingAC = false;
|
||||||
|
|
||||||
|
if(adding) {
|
||||||
|
if(!hasFriend(pairs[0]))
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageScreenCtrl(tes, side, pairs[0], false));
|
||||||
|
|
||||||
|
tfFriend.setDisabled(false);
|
||||||
|
tfFriend.clear();
|
||||||
|
tfFriend.focus();
|
||||||
|
adding = false;
|
||||||
|
} else {
|
||||||
|
acResults.clear();
|
||||||
|
acResults.addAll(Arrays.asList(pairs));
|
||||||
|
|
||||||
|
NameUUIDPair pair = acResults.remove(0);
|
||||||
|
tfFriend.setText(pair.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutocompleteFailure() {
|
||||||
|
waitingAC = false;
|
||||||
|
acResults.clear();
|
||||||
|
acFailTicks = 0;
|
||||||
|
tfFriend.setTextColor(Control.COLOR_RED);
|
||||||
|
|
||||||
|
if(adding) {
|
||||||
|
tfFriend.setDisabled(false);
|
||||||
|
adding = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
|
||||||
|
if(acFailTicks >= 0) {
|
||||||
|
if(++acFailTicks >= 10) {
|
||||||
|
acFailTicks = -1;
|
||||||
|
tfFriend.setTextColor(TextField.DEFAULT_TEXT_COLOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateFriends(NameUUIDPair[] friends) {
|
||||||
|
boolean diff = false;
|
||||||
|
if(friends.length != this.friends.length)
|
||||||
|
diff = true;
|
||||||
|
else {
|
||||||
|
for(NameUUIDPair pair : friends) {
|
||||||
|
if(!hasFriend(pair)) {
|
||||||
|
diff = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(diff) {
|
||||||
|
this.friends = friends;
|
||||||
|
lstFriends.clearRaw();
|
||||||
|
for(NameUUIDPair pair : friends)
|
||||||
|
lstFriends.addElementRaw(pair.name, pair);
|
||||||
|
|
||||||
|
lstFriends.updateContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int updateRights(int current, int newVal, CheckBox[] boxes, boolean force) {
|
||||||
|
if(force || current != newVal) {
|
||||||
|
for(CheckBox box : boxes) {
|
||||||
|
int flag = (Integer) box.getUserdata();
|
||||||
|
box.setChecked((newVal & flag) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!force) {
|
||||||
|
Log.info("Screen check boxes were updated");
|
||||||
|
abortSync(); //Value changed by another user, abort modifications by local user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateFriendRights(int rights) {
|
||||||
|
friendRights = updateRights(friendRights, rights, friendBoxes, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateOtherRights(int rights) {
|
||||||
|
otherRights = updateRights(otherRights, rights, otherBoxes, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void sync() {
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageScreenCtrl(tes, side, friendRights, otherRights));
|
||||||
|
Log.info("Sent sync packet");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateMyRights() {
|
||||||
|
NameUUIDPair me = new NameUUIDPair(minecraft.player.getGameProfile());
|
||||||
|
int myRights;
|
||||||
|
boolean clientIsOwner = false;
|
||||||
|
|
||||||
|
if(me.equals(owner)) {
|
||||||
|
myRights = ScreenRights.ALL;
|
||||||
|
clientIsOwner = true;
|
||||||
|
} else if(hasFriend(me))
|
||||||
|
myRights = friendRights;
|
||||||
|
else
|
||||||
|
myRights = otherRights;
|
||||||
|
|
||||||
|
//Disable components according to client rights
|
||||||
|
grpFriends.setDisabled(!clientIsOwner);
|
||||||
|
|
||||||
|
boolean flag = (myRights & ScreenRights.MANAGE_FRIEND_LIST) == 0;
|
||||||
|
lstFriends.setDisabled(flag);
|
||||||
|
tfFriend.setDisabled(flag);
|
||||||
|
btnAdd.setDisabled(flag);
|
||||||
|
|
||||||
|
flag = (myRights & ScreenRights.MANAGE_OTHER_RIGHTS) == 0;
|
||||||
|
grpOthers.setDisabled(flag);
|
||||||
|
|
||||||
|
flag = (myRights & ScreenRights.MODIFY_SCREEN) == 0;
|
||||||
|
tfResX.setDisabled(flag);
|
||||||
|
tfResY.setDisabled(flag);
|
||||||
|
btnChangeRot.setDisabled(flag);
|
||||||
|
|
||||||
|
if(flag)
|
||||||
|
btnSetRes.setDisabled(true);
|
||||||
|
|
||||||
|
flag = (myRights & ScreenRights.MANAGE_UPGRADES) == 0;
|
||||||
|
ugUpgrades.setDisabled(flag);
|
||||||
|
cbAutoVolume.setDisabled(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateResolution(Vector2i res) {
|
||||||
|
aspectRatio = ((float) res.x) / ((float) res.y);
|
||||||
|
tfResX.setText("" + res.x);
|
||||||
|
tfResY.setText("" + res.y);
|
||||||
|
btnSetRes.setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateRotation(Rotation rot) {
|
||||||
|
rotation = rot;
|
||||||
|
updateRotationStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateAutoVolume(boolean av) {
|
||||||
|
cbAutoVolume.setChecked(av);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||||
|
return bp.equals(tes.getBlockPos()) && side == this.side;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getWikiPageName() {
|
||||||
|
ItemStack is = ugUpgrades.getMouseOverUpgrade();
|
||||||
|
if(is != null) {
|
||||||
|
if(is.getItem() instanceof WDItem)
|
||||||
|
return ((WDItem) is.getItem()).getWikiName(is);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Screen_Configurator";
|
||||||
|
}
|
||||||
|
|
||||||
|
// reason: allow closing the UI, lol
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||||
|
Minecraft.getInstance().setScreen(null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
810
src/main/java/net/montoyo/wd/client/gui/GuiServer.java
Normal file
810
src/main/java/net/montoyo/wd/client/gui/GuiServer.java
Normal file
@@ -0,0 +1,810 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.*;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.client.resources.language.I18n;
|
||||||
|
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
||||||
|
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.miniserv.Constants;
|
||||||
|
import net.montoyo.wd.miniserv.client.*;
|
||||||
|
import net.montoyo.wd.net.WDNetworkRegistry;
|
||||||
|
import net.montoyo.wd.utilities.*;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.serialization.NameUUIDPair;
|
||||||
|
import net.montoyo.wd.utilities.serialization.Util;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.swing.filechooser.FileSystemView;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.text.Collator;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static net.montoyo.wd.client.gui.GuiMinePad.getChar;
|
||||||
|
|
||||||
|
public class GuiServer extends WDScreen {
|
||||||
|
|
||||||
|
private static final ResourceLocation BG_IMAGE = ResourceLocation.fromNamespaceAndPath("webdisplays", "textures/gui/server_bg.png");
|
||||||
|
private static final ResourceLocation FG_IMAGE = ResourceLocation.fromNamespaceAndPath("webdisplays", "textures/gui/server_fg.png");
|
||||||
|
private static final HashMap<String, Method> COMMAND_MAP = new HashMap<>();
|
||||||
|
private static final int MAX_LINE_LEN = 32;
|
||||||
|
private static final int MAX_LINES = 12;
|
||||||
|
|
||||||
|
private final Vector3i serverPos;
|
||||||
|
private final NameUUIDPair owner;
|
||||||
|
private final ArrayList<String> lines = new ArrayList<>();
|
||||||
|
private String prompt = "";
|
||||||
|
private String userPrompt;
|
||||||
|
private int blinkTime;
|
||||||
|
private String lastCmd;
|
||||||
|
private boolean promptLocked;
|
||||||
|
private volatile long queryTime;
|
||||||
|
private ClientTask<?> currentTask;
|
||||||
|
private int selectedLine = -1;
|
||||||
|
|
||||||
|
//Access command
|
||||||
|
private int accessTrials;
|
||||||
|
private int accessTime;
|
||||||
|
private int accessState = -1;
|
||||||
|
private SimpleSoundInstance accessSound;
|
||||||
|
|
||||||
|
//Upload wizard
|
||||||
|
private boolean uploadWizard;
|
||||||
|
private File uploadDir;
|
||||||
|
private final ArrayList<File> uploadFiles = new ArrayList<>();
|
||||||
|
private int uploadOffset;
|
||||||
|
private boolean uploadFirstIsParent;
|
||||||
|
private String uploadFilter = "";
|
||||||
|
private long uploadFilterTime;
|
||||||
|
|
||||||
|
public GuiServer(Vector3i vec, NameUUIDPair owner) {
|
||||||
|
super(Component.nullToEmpty(null));
|
||||||
|
serverPos = vec;
|
||||||
|
this.owner = owner;
|
||||||
|
userPrompt = "> ";
|
||||||
|
|
||||||
|
if (COMMAND_MAP.isEmpty())
|
||||||
|
buildCommandMap();
|
||||||
|
|
||||||
|
lines.add("MiniServ 1.0");
|
||||||
|
lines.add(tr("info"));
|
||||||
|
uploadCD(FileSystemView.getFileSystemView().getDefaultDirectory());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String tr(String key, Object... args) {
|
||||||
|
return I18n.get("webdisplays.server." + key, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(GuiGraphics graphics, int mouseX, int mouseY, float ptt) {
|
||||||
|
super.render(graphics, mouseX, mouseY, ptt);
|
||||||
|
|
||||||
|
int x = (width - 256) / 2;
|
||||||
|
int y = (height - 176) / 2;
|
||||||
|
|
||||||
|
// RenderSystem.enableTexture();
|
||||||
|
RenderSystem.setShaderTexture(0, BG_IMAGE);
|
||||||
|
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
graphics.blit(BG_IMAGE, x, y, 0, 0, 256, 256);
|
||||||
|
|
||||||
|
x += 18;
|
||||||
|
y += 18;
|
||||||
|
|
||||||
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
if (selectedLine == i) {
|
||||||
|
drawWhiteQuad(x - 1, y - 2, font.width(lines.get(i)) + 1, 12);
|
||||||
|
graphics.drawString(Minecraft.getInstance().font, lines.get(i), x, y, 0xFF129700, false);
|
||||||
|
} else
|
||||||
|
graphics.drawString(Minecraft.getInstance().font, lines.get(i), x, y, 0xFFFFFFFF, false);
|
||||||
|
|
||||||
|
y += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!promptLocked) {
|
||||||
|
if (queue.isEmpty()) {
|
||||||
|
x = graphics.drawString(Minecraft.getInstance().font, userPrompt, x, y, 0xFFFFFFFF, false);
|
||||||
|
x = graphics.drawString(Minecraft.getInstance().font, prompt, x, y, 0xFFFFFFFF, false);
|
||||||
|
} else {
|
||||||
|
x = graphics.drawString(Minecraft.getInstance().font, tr("press_for_more"), x, y, 0xFFFFFFFF, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uploadWizard && blinkTime < 5)
|
||||||
|
drawWhiteQuad(x + 1, y, 6, 8);
|
||||||
|
|
||||||
|
// RenderSystem.enableTexture();
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
RenderSystem.setShaderTexture(0, FG_IMAGE);
|
||||||
|
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
// blit(graphics,(width - 256) / 2, (height - 176) / 2, 0, 0, 256, 176);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawWhiteQuad(int x, int y, int w, int h) {
|
||||||
|
float xd = (float) x;
|
||||||
|
float xd2 = (float) (x + w);
|
||||||
|
float yd = (float) y;
|
||||||
|
float yd2 = (float) (y + h);
|
||||||
|
float zd = (float) getBlitOffset();
|
||||||
|
|
||||||
|
// RenderSystem.disableTexture();
|
||||||
|
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionShader);
|
||||||
|
BufferBuilder bb = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION);
|
||||||
|
bb.addVertex(xd, yd2, zd);
|
||||||
|
bb.addVertex(xd2, yd2, zd);
|
||||||
|
bb.addVertex(xd2, yd, zd);
|
||||||
|
bb.addVertex(xd, yd, zd);
|
||||||
|
BufferUploader.drawWithShader(bb.buildOrThrow());
|
||||||
|
// RenderSystem.enableTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getBlitOffset() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
|
||||||
|
if (accessState >= 0) {
|
||||||
|
if (--accessTime <= 0) {
|
||||||
|
accessState++;
|
||||||
|
|
||||||
|
if (accessState == 1) {
|
||||||
|
if (lines.size() > 0)
|
||||||
|
lines.remove(lines.size() - 1);
|
||||||
|
|
||||||
|
lines.add("access: PERMISSION DENIED....and...");
|
||||||
|
accessTime = 20;
|
||||||
|
} else {
|
||||||
|
if (accessSound == null) {
|
||||||
|
accessSound = new SimpleSoundInstance(WebDisplays.INSTANCE.soundServer.getLocation(), SoundSource.MASTER, 1.0f, 1.0f, RandomSource.create(), true, 0, SoundInstance.Attenuation.NONE, 0.0f, 0.0f, 0.0f, false);
|
||||||
|
minecraft.getSoundManager().play(accessSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeLine("YOU DIDN'T SAY THE MAGIC WORD!");
|
||||||
|
accessTime = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
blinkTime = (blinkTime + 1) % 10;
|
||||||
|
|
||||||
|
if (currentTask != null) {
|
||||||
|
long queryTime;
|
||||||
|
synchronized (this) {
|
||||||
|
queryTime = this.queryTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.currentTimeMillis() - queryTime >= 10000) {
|
||||||
|
writeLine(tr("timeout"));
|
||||||
|
currentTask.cancel();
|
||||||
|
clearTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uploadFilter.isEmpty() && System.currentTimeMillis() - uploadFilterTime >= 1000) {
|
||||||
|
Log.info("Upload filter cleared");
|
||||||
|
uploadFilter = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final int maxl = uploadWizard ? MAX_LINES : (MAX_LINES - 1); //Cuz prompt is hidden
|
||||||
|
if (!queue.isEmpty()) {
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
if (lines.size() >= maxl)
|
||||||
|
break;
|
||||||
|
writeLine(queue.remove(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (lines.size() > maxl)
|
||||||
|
lines.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
|
||||||
|
Supplier<Boolean> predicate = () -> super.keyReleased(keyCode, scanCode, modifiers);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return handleKeyboardInput(keyCode, false, predicate);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_ESCAPE && !uploadWizard) {
|
||||||
|
Minecraft.getInstance().setScreen(null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getChar(keyCode, scanCode).ifPresent(c -> {
|
||||||
|
try {
|
||||||
|
keyTyped(c, keyCode, modifiers);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
return handleKeyboardInput(keyCode, true, () -> true);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean handleKeyboardInput(int keyCode, boolean keyState, Supplier<Boolean> booleanSupplier) throws IOException {
|
||||||
|
if (!queue.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (uploadWizard) {
|
||||||
|
if (keyState) {
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_UP) {
|
||||||
|
if (selectedLine > 3)
|
||||||
|
selectedLine--;
|
||||||
|
else if (uploadOffset > 0) {
|
||||||
|
uploadOffset--;
|
||||||
|
updateUploadScreen();
|
||||||
|
}
|
||||||
|
} else if (keyCode == GLFW.GLFW_KEY_DOWN) {
|
||||||
|
if (selectedLine < MAX_LINES - 1)
|
||||||
|
selectedLine++;
|
||||||
|
else if (uploadOffset + selectedLine - 2 < uploadFiles.size()) {
|
||||||
|
uploadOffset++;
|
||||||
|
updateUploadScreen();
|
||||||
|
}
|
||||||
|
} else if (keyCode == GLFW.GLFW_KEY_PAGE_DOWN) {
|
||||||
|
selectedLine = 3;
|
||||||
|
int dst = uploadOffset - (MAX_LINES - 3);
|
||||||
|
if (dst < 0)
|
||||||
|
dst = 0;
|
||||||
|
|
||||||
|
selectFile(dst);
|
||||||
|
} else if (keyCode == GLFW.GLFW_KEY_PAGE_UP) {
|
||||||
|
selectedLine = 3;
|
||||||
|
int dst = uploadOffset + (MAX_LINES - 3);
|
||||||
|
if (dst >= uploadFiles.size())
|
||||||
|
dst = uploadFiles.size() - 1;
|
||||||
|
|
||||||
|
selectFile(dst);
|
||||||
|
} else if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) {
|
||||||
|
File file = uploadFiles.get(uploadOffset + selectedLine - 3);
|
||||||
|
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
uploadCD(file);
|
||||||
|
updateUploadScreen();
|
||||||
|
} else
|
||||||
|
startFileUpload(file, true);
|
||||||
|
} else if (keyCode == GLFW.GLFW_KEY_F5) {
|
||||||
|
uploadCD(uploadDir);
|
||||||
|
updateUploadScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||||
|
quitUploadWizard();
|
||||||
|
return true; //Don't let the screen handle this
|
||||||
|
}
|
||||||
|
|
||||||
|
return booleanSupplier.get();
|
||||||
|
} else {
|
||||||
|
boolean value = booleanSupplier.get();
|
||||||
|
|
||||||
|
if (keyState) {
|
||||||
|
boolean ctrl = Screen.hasControlDown();
|
||||||
|
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_L && ctrl)
|
||||||
|
lines.clear();
|
||||||
|
else if (keyCode == GLFW.GLFW_KEY_V && ctrl) {
|
||||||
|
prompt += Minecraft.getInstance().keyboardHandler.getClipboard();
|
||||||
|
|
||||||
|
if (prompt.length() > MAX_LINE_LEN)
|
||||||
|
prompt = prompt.substring(0, MAX_LINE_LEN);
|
||||||
|
} else if (keyCode == GLFW.GLFW_KEY_UP) {
|
||||||
|
if (lastCmd != null) {
|
||||||
|
String tmp = prompt;
|
||||||
|
prompt = lastCmd;
|
||||||
|
lastCmd = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean charTyped(char codePoint, int modifiers) {
|
||||||
|
return super.charTyped(codePoint, modifiers);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void keyTyped(char typedChar, int keyCode, int modifier) throws IOException {
|
||||||
|
//this.charTyped(typedChar, modifier);
|
||||||
|
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_DOWN) {
|
||||||
|
if (!queue.isEmpty()) {
|
||||||
|
writeLine(queue.remove(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!queue.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (uploadWizard) {
|
||||||
|
boolean found = false;
|
||||||
|
uploadFilter += Character.toLowerCase(typedChar);
|
||||||
|
uploadFilterTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
for (int i = uploadFirstIsParent ? 1 : 0; i < uploadFiles.size(); i++) {
|
||||||
|
if (uploadFiles.get(i).getName().toLowerCase().startsWith(uploadFilter)) {
|
||||||
|
selectFile(i);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found && uploadFilter.length() == 1)
|
||||||
|
uploadFilter = "";
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else if (promptLocked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_SPACE)
|
||||||
|
typedChar = ' ';
|
||||||
|
if (
|
||||||
|
(typedChar == 'v' || typedChar == 'V') &&
|
||||||
|
(modifier & 2) == 2
|
||||||
|
) return;
|
||||||
|
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
|
||||||
|
if (prompt.length() > 0)
|
||||||
|
prompt = prompt.substring(0, prompt.length() - 1);
|
||||||
|
} else if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) {
|
||||||
|
if (prompt.length() > 0) {
|
||||||
|
writeLine(userPrompt + prompt);
|
||||||
|
evaluateCommand(prompt);
|
||||||
|
lastCmd = prompt;
|
||||||
|
prompt = "";
|
||||||
|
} else
|
||||||
|
writeLine(userPrompt);
|
||||||
|
} else if (prompt.length() + 1 < MAX_LINE_LEN && typedChar >= 32 && typedChar <= 126)
|
||||||
|
prompt = prompt + typedChar;
|
||||||
|
|
||||||
|
blinkTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void evaluateCommand(String str) {
|
||||||
|
String[] args = str.trim().split("\\s+");
|
||||||
|
Method handler = COMMAND_MAP.get(args[0].toLowerCase());
|
||||||
|
|
||||||
|
if (handler == null) {
|
||||||
|
writeLine(tr("unknowncmd"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object[] params;
|
||||||
|
if (handler.getParameterCount() == 0)
|
||||||
|
params = new Object[0];
|
||||||
|
else {
|
||||||
|
String[] args2 = new String[args.length - 1];
|
||||||
|
System.arraycopy(args, 1, args2, 0, args2.length);
|
||||||
|
params = new Object[]{args2};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
handler.invoke(this, params);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
Log.errorEx("Caught exception while running command \"%s\"", e, str);
|
||||||
|
writeLine(tr("error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeLine(String line) {
|
||||||
|
final int maxl = uploadWizard ? MAX_LINES : (MAX_LINES - 1); //Cuz prompt is hidden
|
||||||
|
while (lines.size() >= maxl)
|
||||||
|
lines.remove(0);
|
||||||
|
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void buildCommandMap() {
|
||||||
|
COMMAND_MAP.clear();
|
||||||
|
|
||||||
|
Method[] methods = GuiServer.class.getMethods();
|
||||||
|
for (Method m : methods) {
|
||||||
|
CommandHandler cmd = m.getAnnotation(CommandHandler.class);
|
||||||
|
|
||||||
|
if (cmd != null && Modifier.isPublic(m.getModifiers())) {
|
||||||
|
if (m.getParameterCount() == 0 || (m.getParameterCount() == 1 && m.getParameterTypes()[0] == String[].class))
|
||||||
|
COMMAND_MAP.put(cmd.value().toLowerCase(), m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void quitUploadWizard() {
|
||||||
|
lines.clear();
|
||||||
|
promptLocked = false;
|
||||||
|
uploadWizard = false;
|
||||||
|
selectedLine = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
super.onClose();
|
||||||
|
|
||||||
|
if (accessSound != null)
|
||||||
|
Minecraft.getInstance().getSoundManager().stop(accessSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean queueTask(ClientTask<?> task) {
|
||||||
|
if (Client.getInstance().addTask(task)) {
|
||||||
|
promptLocked = true;
|
||||||
|
queryTime = System.currentTimeMillis(); //No task is running so it's okay to have an unsynchronized access here
|
||||||
|
currentTask = task;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
writeLine(tr("queryerr"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearTask() {
|
||||||
|
promptLocked = false;
|
||||||
|
currentTask = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String trimStringL(String str) {
|
||||||
|
int delta = str.length() - MAX_LINE_LEN;
|
||||||
|
if (delta <= 0)
|
||||||
|
return str;
|
||||||
|
|
||||||
|
return "..." + str.substring(delta + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String trimStringR(String str) {
|
||||||
|
return (str.length() <= MAX_LINE_LEN) ? str : (str.substring(0, MAX_LINE_LEN - 3) + "...");
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("clear")
|
||||||
|
public void commandClear() {
|
||||||
|
lines.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("help")
|
||||||
|
public void commandHelp(String[] args) {
|
||||||
|
queueRead = lines.size();
|
||||||
|
|
||||||
|
if (args.length > 0) {
|
||||||
|
String cmd = args[0].toLowerCase();
|
||||||
|
|
||||||
|
if (COMMAND_MAP.containsKey(cmd))
|
||||||
|
queueLine(tr("help." + cmd));
|
||||||
|
else
|
||||||
|
queueLine(tr("unknowncmd"));
|
||||||
|
} else {
|
||||||
|
for (String c : COMMAND_MAP.keySet())
|
||||||
|
queueLine(c + " - " + tr("help." + c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("exit")
|
||||||
|
public void commandExit() {
|
||||||
|
minecraft.setScreen(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("access")
|
||||||
|
public void commandAccess(String[] args) {
|
||||||
|
boolean handled = false;
|
||||||
|
|
||||||
|
if (args.length >= 1 && args[0].equalsIgnoreCase("security")) {
|
||||||
|
if (args.length == 1 || (args.length == 2 && args[1].equalsIgnoreCase("grid")))
|
||||||
|
handled = true;
|
||||||
|
} else if (args.length == 3 && args[0].equalsIgnoreCase("main") && args[1].equalsIgnoreCase("security") && args[2].equalsIgnoreCase("grid"))
|
||||||
|
handled = true;
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
|
writeLine("access: PERMISSION DENIED.");
|
||||||
|
|
||||||
|
if (++accessTrials >= 3) {
|
||||||
|
promptLocked = true;
|
||||||
|
accessState = 0;
|
||||||
|
accessTime = 20;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
writeLine(tr("argerror"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("owner")
|
||||||
|
public void commandOwner() {
|
||||||
|
writeLine(tr("ownername", owner.name));
|
||||||
|
writeLine(tr("owneruuid"));
|
||||||
|
writeLine(owner.uuid.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("quota")
|
||||||
|
public void commandQuota() {
|
||||||
|
if (!minecraft.player.getGameProfile().getId().equals(owner.uuid)) {
|
||||||
|
writeLine(tr("errowner"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientTaskGetQuota task = new ClientTaskGetQuota();
|
||||||
|
task.setFinishCallback((t) -> {
|
||||||
|
writeLine(tr("quota", Util.sizeString(t.getQuota()), Util.sizeString(t.getMaxQuota())));
|
||||||
|
clearTask();
|
||||||
|
});
|
||||||
|
|
||||||
|
queueTask(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("ls")
|
||||||
|
public void commandList() {
|
||||||
|
ClientTaskGetFileList task = new ClientTaskGetFileList(owner.uuid);
|
||||||
|
task.setFinishCallback((t) -> {
|
||||||
|
String[] files = t.getFileList();
|
||||||
|
if (files != null)
|
||||||
|
Arrays.stream(files).forEach(this::writeLine);
|
||||||
|
|
||||||
|
clearTask();
|
||||||
|
});
|
||||||
|
|
||||||
|
queueTask(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("url")
|
||||||
|
public void commandURL(String[] args) {
|
||||||
|
if (args.length < 1) {
|
||||||
|
writeLine(tr("fnamearg"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fname = Util.join(args, " ");
|
||||||
|
if (Util.isFileNameInvalid(fname)) {
|
||||||
|
writeLine(tr("nameerr"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientTaskCheckFile task = new ClientTaskCheckFile(owner.uuid, fname);
|
||||||
|
task.setFinishCallback((t) -> {
|
||||||
|
int status = t.getStatus();
|
||||||
|
if (status == 0) {
|
||||||
|
writeLine(tr("urlcopied"));
|
||||||
|
Minecraft.getInstance().keyboardHandler.setClipboard(t.getURL());
|
||||||
|
} else if (status == Constants.GETF_STATUS_NOT_FOUND)
|
||||||
|
writeLine(tr("notfound"));
|
||||||
|
else
|
||||||
|
writeLine(tr("error2", status));
|
||||||
|
|
||||||
|
clearTask();
|
||||||
|
});
|
||||||
|
|
||||||
|
queueTask(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void uploadCD(File newDir) {
|
||||||
|
try {
|
||||||
|
uploadDir = newDir.getCanonicalFile();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
uploadDir = newDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadFiles.clear();
|
||||||
|
File parent = uploadDir.getParentFile();
|
||||||
|
|
||||||
|
if (parent != null && parent.exists()) {
|
||||||
|
uploadFiles.add(parent);
|
||||||
|
uploadFirstIsParent = true;
|
||||||
|
} else
|
||||||
|
uploadFirstIsParent = false;
|
||||||
|
|
||||||
|
File[] children = uploadDir.listFiles();
|
||||||
|
if (children != null) {
|
||||||
|
Collator c = Collator.getInstance();
|
||||||
|
c.setStrength(Collator.SECONDARY);
|
||||||
|
c.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
|
||||||
|
|
||||||
|
Arrays.stream(children).filter(f -> !f.isHidden() && (f.isDirectory() || f.isFile())).sorted((a, b) -> c.compare(a.getName(), b.getName())).forEach(uploadFiles::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadOffset = 0;
|
||||||
|
uploadFilter = "";
|
||||||
|
|
||||||
|
if (uploadWizard)
|
||||||
|
selectedLine = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateUploadScreen() {
|
||||||
|
lines.clear();
|
||||||
|
|
||||||
|
lines.add(tr("upload.info"));
|
||||||
|
lines.add(trimStringL(uploadDir.getPath()));
|
||||||
|
lines.add("");
|
||||||
|
|
||||||
|
for (int i = uploadOffset; i < uploadFiles.size() && lines.size() < MAX_LINES; i++) {
|
||||||
|
if (i == 0 && uploadFirstIsParent)
|
||||||
|
lines.add(tr("upload.parent"));
|
||||||
|
else
|
||||||
|
lines.add(trimStringR(uploadFiles.get(i).getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectFile(int i) {
|
||||||
|
int pos = 3 + i - uploadOffset;
|
||||||
|
if (pos >= 3 && pos < MAX_LINES) {
|
||||||
|
selectedLine = pos;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadOffset = i;
|
||||||
|
if (uploadOffset + MAX_LINES - 3 > uploadFiles.size())
|
||||||
|
uploadOffset = uploadFiles.size() - MAX_LINES + 3;
|
||||||
|
|
||||||
|
updateUploadScreen();
|
||||||
|
selectedLine = 3 + i - uploadOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("upload")
|
||||||
|
public void commandUpload(String[] args) {
|
||||||
|
if (!minecraft.player.getGameProfile().getId().equals(owner.uuid)) {
|
||||||
|
writeLine(tr("errowner"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length > 0) {
|
||||||
|
File fle = new File(Util.join(args, " "));
|
||||||
|
if (!fle.exists()) {
|
||||||
|
writeLine(tr("notfound"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fle.isDirectory())
|
||||||
|
uploadCD(fle);
|
||||||
|
else if (fle.isFile()) {
|
||||||
|
startFileUpload(fle, false);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
writeLine(tr("notfound"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadWizard = true;
|
||||||
|
promptLocked = true;
|
||||||
|
uploadOffset = 0;
|
||||||
|
selectedLine = 3;
|
||||||
|
updateUploadScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("rm")
|
||||||
|
public void commandDelete(String[] args) {
|
||||||
|
if (!minecraft.player.getGameProfile().getId().equals(owner.uuid)) {
|
||||||
|
writeLine(tr("errowner"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 1) {
|
||||||
|
writeLine(tr("fnamearg"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fname = Util.join(args, " ");
|
||||||
|
if (Util.isFileNameInvalid(fname)) {
|
||||||
|
writeLine(tr("nameerr"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientTaskDeleteFile task = new ClientTaskDeleteFile(fname);
|
||||||
|
task.setFinishCallback((t) -> {
|
||||||
|
int status = t.getStatus();
|
||||||
|
if (status == 1)
|
||||||
|
writeLine(tr("notfound"));
|
||||||
|
else if (status != 0)
|
||||||
|
writeLine(tr("error"));
|
||||||
|
|
||||||
|
clearTask();
|
||||||
|
});
|
||||||
|
|
||||||
|
queueTask(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandHandler("reconnect")
|
||||||
|
public void commandReconnect() {
|
||||||
|
Client.getInstance().stop();
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(Client.getInstance().beginConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startFileUpload(File f, boolean quit) {
|
||||||
|
if (quit)
|
||||||
|
quitUploadWizard();
|
||||||
|
|
||||||
|
if (Util.isFileNameInvalid(f.getName()) || f.getName().length() >= MAX_LINE_LEN - 3) {
|
||||||
|
writeLine(tr("nameerr"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientTaskUploadFile task;
|
||||||
|
try {
|
||||||
|
task = new ClientTaskUploadFile(f);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
writeLine(tr("error"));
|
||||||
|
ex.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
task.setProgressCallback((cur, total) -> {
|
||||||
|
synchronized (GuiServer.this) {
|
||||||
|
queryTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
task.setFinishCallback(t -> {
|
||||||
|
int status = t.getUploadStatus();
|
||||||
|
if (status == 0)
|
||||||
|
writeLine(tr("upload.done"));
|
||||||
|
else if (status == Constants.FUPA_STATUS_FILE_EXISTS)
|
||||||
|
writeLine(tr("upload.exists"));
|
||||||
|
else if (status == Constants.FUPA_STATUS_EXCEEDS_QUOTA)
|
||||||
|
writeLine(tr("upload.quota"));
|
||||||
|
else
|
||||||
|
writeLine(tr("error2", status));
|
||||||
|
|
||||||
|
clearTask();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (queueTask(task))
|
||||||
|
writeLine(tr("upload.uploading"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||||
|
return serverPos.equalsBlockPos(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getWikiPageName() {
|
||||||
|
return "Server";
|
||||||
|
}
|
||||||
|
|
||||||
|
int queueRead = 0;
|
||||||
|
ArrayList<String> queue = new ArrayList<>();
|
||||||
|
|
||||||
|
private void queueLine(String line) {
|
||||||
|
final int maxl = uploadWizard ? MAX_LINES : (MAX_LINES - 1); //Cuz prompt is hidden
|
||||||
|
if (lines.size() < maxl)
|
||||||
|
writeLine(line);
|
||||||
|
else if (queueRead > 1) {
|
||||||
|
writeLine(line);
|
||||||
|
queueRead -= 1;
|
||||||
|
} else queue.add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
155
src/main/java/net/montoyo/wd/client/gui/GuiSetURL2.java
Normal file
155
src/main/java/net/montoyo/wd/client/gui/GuiSetURL2.java
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.client.ClientProxy;
|
||||||
|
import net.montoyo.wd.client.gui.controls.Button;
|
||||||
|
import net.montoyo.wd.client.gui.controls.TextField;
|
||||||
|
import net.montoyo.wd.client.gui.loading.FillControl;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.item.ItemMinePad2;
|
||||||
|
import net.montoyo.wd.net.WDNetworkRegistry;
|
||||||
|
import net.montoyo.wd.net.server_bound.C2SMessageMinepadUrl;
|
||||||
|
import net.montoyo.wd.net.server_bound.C2SMessageScreenCtrl;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.serialization.Util;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
import net.montoyo.wd.data.WDDataComponents;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class GuiSetURL2 extends WDScreen {
|
||||||
|
|
||||||
|
//Screen data
|
||||||
|
private ScreenBlockEntity tileEntity;
|
||||||
|
private BlockSide screenSide;
|
||||||
|
private Vector3i remoteLocation;
|
||||||
|
|
||||||
|
//Pad data
|
||||||
|
private ItemStack stack;
|
||||||
|
private final boolean isPad;
|
||||||
|
|
||||||
|
//Common
|
||||||
|
private final String screenURL;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private TextField tfURL;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private Button btnShutDown;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private Button btnCancel;
|
||||||
|
|
||||||
|
@FillControl
|
||||||
|
private Button btnOk;
|
||||||
|
|
||||||
|
public GuiSetURL2(ScreenBlockEntity tes, BlockSide side, String url, Vector3i rl) {
|
||||||
|
super(Component.nullToEmpty(null));
|
||||||
|
tileEntity = tes;
|
||||||
|
screenSide = side;
|
||||||
|
remoteLocation = rl;
|
||||||
|
isPad = false;
|
||||||
|
screenURL = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiSetURL2(ItemStack is, String url) {
|
||||||
|
super(Component.nullToEmpty(null));
|
||||||
|
isPad = true;
|
||||||
|
stack = is;
|
||||||
|
screenURL = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
super.init();
|
||||||
|
loadFrom(ResourceLocation.fromNamespaceAndPath("webdisplays", "gui/seturl.json"));
|
||||||
|
// Guard against null URL to avoid UI NPEs
|
||||||
|
tfURL.setText(screenURL == null ? "" : screenURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addLoadCustomVariables(Map<String, Double> vars) {
|
||||||
|
vars.put("isPad", isPad ? 1.0 : 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected UUID getUUID() {
|
||||||
|
if (stack == null || !(stack.getItem() instanceof ItemMinePad2))
|
||||||
|
throw new RuntimeException("Get UUID is being called for a non-minepad UI");
|
||||||
|
if (!stack.has(WDDataComponents.PAD_ID.get())) {
|
||||||
|
UUID newUUID = UUID.randomUUID();
|
||||||
|
stack.set(WDDataComponents.PAD_ID.get(), newUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack.get(WDDataComponents.PAD_ID.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuiSubscribe
|
||||||
|
public void onButtonClicked(Button.ClickEvent ev) {
|
||||||
|
if (ev.getSource() == btnCancel)
|
||||||
|
minecraft.setScreen(null);
|
||||||
|
else if (ev.getSource() == btnOk)
|
||||||
|
validate(tfURL.getText());
|
||||||
|
else if (ev.getSource() == btnShutDown) {
|
||||||
|
if (isPad) {
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageMinepadUrl(
|
||||||
|
getUUID(),
|
||||||
|
""
|
||||||
|
));
|
||||||
|
stack.remove(WDDataComponents.PAD_ID.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
minecraft.setScreen(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuiSubscribe
|
||||||
|
public void onEnterPressed(TextField.EnterPressedEvent ev) {
|
||||||
|
validate(ev.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validate(String url) {
|
||||||
|
if (!url.isEmpty()) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
ScreenBlockEntity.url(url);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
url = Util.addProtocol(url);
|
||||||
|
// url = ((ClientProxy) WebDisplays.PROXY).getMCEF().punycode(url);
|
||||||
|
|
||||||
|
if (isPad) {
|
||||||
|
UUID uuid = getUUID();
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageMinepadUrl(uuid, url));
|
||||||
|
stack.set(WDDataComponents.PAD_URL.get(), url);
|
||||||
|
|
||||||
|
ClientProxy.PadData pd = ((ClientProxy) WebDisplays.PROXY).getPadByID(uuid);
|
||||||
|
|
||||||
|
if (pd != null && pd.view != null) {
|
||||||
|
pd.view.loadURL(WebDisplays.applyBlacklist(url));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(C2SMessageScreenCtrl.setURL(tileEntity, screenSide, url, remoteLocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
minecraft.setScreen(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isForBlock(BlockPos bp, BlockSide side) {
|
||||||
|
return (remoteLocation != null && remoteLocation.equalsBlockPos(bp)) || (bp.equals(tileEntity.getBlockPos()) && side == screenSide);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
15
src/main/java/net/montoyo/wd/client/gui/GuiSubscribe.java
Normal file
15
src/main/java/net/montoyo/wd/client/gui/GuiSubscribe.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface GuiSubscribe {
|
||||||
|
}
|
||||||
205
src/main/java/net/montoyo/wd/client/gui/RenderRecipe.java
Normal file
205
src/main/java/net/montoyo/wd/client/gui/RenderRecipe.java
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.Lighting;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||||
|
import net.minecraft.client.resources.language.I18n;
|
||||||
|
import net.minecraft.core.NonNullList;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.crafting.Ingredient;
|
||||||
|
import net.minecraft.world.item.crafting.Recipe;
|
||||||
|
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||||
|
import net.minecraft.world.item.crafting.ShapedRecipe;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import static net.neoforged.api.distmarker.Dist.CLIENT;
|
||||||
|
|
||||||
|
@OnlyIn(CLIENT)
|
||||||
|
public class RenderRecipe extends Screen {
|
||||||
|
public RenderRecipe() {
|
||||||
|
super(Component.nullToEmpty(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NameRecipePair {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final ShapedRecipe recipe;
|
||||||
|
|
||||||
|
private NameRecipePair(String n, ShapedRecipe r) {
|
||||||
|
this.name = n;
|
||||||
|
this.recipe = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ResourceLocation CRAFTING_TABLE_GUI_TEXTURES = ResourceLocation.fromNamespaceAndPath("minecraft", "textures/gui/container/crafting_table.png");
|
||||||
|
private static final int SIZE_X = 176;
|
||||||
|
private static final int SIZE_Y = 166;
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
private ItemRenderer renderItem;
|
||||||
|
private final ItemStack[] recipe = new ItemStack[3 * 3];
|
||||||
|
private ItemStack recipeResult;
|
||||||
|
private String recipeName;
|
||||||
|
private final ArrayList<NameRecipePair> recipes = new ArrayList<>();
|
||||||
|
private ByteBuffer buffer;
|
||||||
|
private int[] array;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
x = (width - SIZE_X) / 2;
|
||||||
|
y = (height - SIZE_Y) / 2;
|
||||||
|
renderItem = minecraft.getItemRenderer();
|
||||||
|
|
||||||
|
for (RecipeHolder<?> holder : minecraft.level.getRecipeManager().getRecipes()) {
|
||||||
|
ResourceLocation regName = holder.id();
|
||||||
|
Recipe<?> rec = holder.value();
|
||||||
|
|
||||||
|
if (regName != null && regName.getNamespace().equals("webdisplays")) {
|
||||||
|
if (rec instanceof ShapedRecipe shaped)
|
||||||
|
recipes.add(new NameRecipePair(regName.getPath(), shaped));
|
||||||
|
else
|
||||||
|
Log.warning("Found non-shaped recipe %s", regName.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.info("Loaded %d recipes", recipes.size());
|
||||||
|
nextRecipe();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(GuiGraphics context, int mouseX, int mouseY, float partialTick) {
|
||||||
|
renderBackground(context, mouseX, mouseY, partialTick);
|
||||||
|
|
||||||
|
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
RenderSystem.setShaderTexture(0, CRAFTING_TABLE_GUI_TEXTURES);
|
||||||
|
// context.blit(x, y, 0, 0, SIZE_X, SIZE_Y);
|
||||||
|
// font.draw(poseStack, I18n.get("container.crafting"), x + 28, y + 6, 0x404040);
|
||||||
|
|
||||||
|
Lighting.setupForFlatItems();
|
||||||
|
// RenderSystem.disableLighting(); //TODO: Need this?
|
||||||
|
|
||||||
|
for(int sy = 0; sy < 3; sy++) {
|
||||||
|
for(int sx = 0; sx < 3; sx++) {
|
||||||
|
ItemStack is = recipe[sy * 3 + sx];
|
||||||
|
|
||||||
|
if(is != null) {
|
||||||
|
int x = this.x + 30 + sx * 18;
|
||||||
|
int y = this.y + 17 + sy * 18;
|
||||||
|
|
||||||
|
context.renderItem(is, x, y);
|
||||||
|
context.renderItemDecorations(font, is, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(recipeResult != null) {
|
||||||
|
context.renderItem(recipeResult, x, y);
|
||||||
|
context.renderItemDecorations(font, recipeResult, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlStateManager.enableLighting();
|
||||||
|
Lighting.setupFor3DItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRecipe(ShapedRecipe recipe) {
|
||||||
|
IntStream.range(0, this.recipe.length).forEach(i -> this.recipe[i] = null);
|
||||||
|
NonNullList<Ingredient> ingredients = recipe.getIngredients();
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
for(int y = 0; y < recipe.getHeight(); y++) {
|
||||||
|
for(int x = 0; x < recipe.getWidth(); x++) {
|
||||||
|
ItemStack[] stacks = ingredients.get(pos++).getItems();
|
||||||
|
|
||||||
|
if(stacks.length > 0)
|
||||||
|
this.recipe[y * 3 + x] = stacks[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recipeResult = recipe.getResultItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nextRecipe() {
|
||||||
|
if(recipes.isEmpty())
|
||||||
|
minecraft.setScreen(null);
|
||||||
|
else {
|
||||||
|
NameRecipePair pair = recipes.remove(0);
|
||||||
|
setRecipe(pair.recipe);
|
||||||
|
recipeName = pair.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int screen2DisplayX(int x) {
|
||||||
|
double ret = ((double) x) / ((double) width) * ((double) minecraft.getWindow().getWidth());
|
||||||
|
return (int) ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int screen2DisplayY(int y) {
|
||||||
|
double ret = ((double) y) / ((double) height) * ((double) minecraft.getWindow().getHeight());
|
||||||
|
return (int) ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void takeScreenshot() throws Throwable { //TODO: Figure out how to do this.
|
||||||
|
/*
|
||||||
|
int x = screen2DisplayX(this.x + 27);
|
||||||
|
int y = minecraft.getWindow().getHeight() - screen2DisplayY(this.y + 4);
|
||||||
|
int w = screen2DisplayX(120);
|
||||||
|
int h = screen2DisplayY(68);
|
||||||
|
y -= h;
|
||||||
|
|
||||||
|
if(buffer == null)
|
||||||
|
buffer = BufferUtils.createByteBuffer(w * h);
|
||||||
|
|
||||||
|
int oldPack = glGetInteger(GL_PACK_ALIGNMENT);
|
||||||
|
RenderSystem.pixelStore(GL_PACK_ALIGNMENT, 1);
|
||||||
|
buffer.clear();
|
||||||
|
RenderSystem.readPixels(x, y, w, h, EXTBGRA.GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer);
|
||||||
|
RenderSystem.pixelStore(GL_PACK_ALIGNMENT, oldPack);
|
||||||
|
|
||||||
|
if(array == null)
|
||||||
|
array = new int[w * h];
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
buffer.asIntBuffer().get(array);
|
||||||
|
TextureUtil.processPixelValues(array, w, h);
|
||||||
|
|
||||||
|
File f = new File(minecraft.gameDirectory, "wd_recipes");
|
||||||
|
if(!f.exists())
|
||||||
|
f.mkdir();
|
||||||
|
|
||||||
|
f = new File(f, recipeName + ".png");
|
||||||
|
|
||||||
|
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
|
||||||
|
bi.setRGB(0, 0, w, h, array, 0, w);
|
||||||
|
ImageIO.write(bi, "PNG", f);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if(recipeName != null) {
|
||||||
|
try {
|
||||||
|
takeScreenshot();
|
||||||
|
nextRecipe();
|
||||||
|
} catch(Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
minecraft.setScreen(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
410
src/main/java/net/montoyo/wd/client/gui/WDScreen.java
Normal file
410
src/main/java/net/montoyo/wd/client/gui/WDScreen.java
Normal file
@@ -0,0 +1,410 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.Style;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.FormattedCharSequence;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.montoyo.wd.client.gui.controls.Container;
|
||||||
|
import net.montoyo.wd.client.gui.controls.Control;
|
||||||
|
import net.montoyo.wd.client.gui.controls.Event;
|
||||||
|
import net.montoyo.wd.client.gui.loading.FillControl;
|
||||||
|
import net.montoyo.wd.client.gui.loading.GuiLoader;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
import net.montoyo.wd.net.WDNetworkRegistry;
|
||||||
|
import net.montoyo.wd.net.server_bound.C2SMessageACQuery;
|
||||||
|
import net.montoyo.wd.utilities.*;
|
||||||
|
import net.montoyo.wd.utilities.data.Bounds;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.serialization.NameUUIDPair;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public abstract class WDScreen extends Screen {
|
||||||
|
|
||||||
|
public static WDScreen CURRENT_SCREEN = null;
|
||||||
|
|
||||||
|
protected final ArrayList<Control> controls = new ArrayList<>();
|
||||||
|
protected final ArrayList<Control> postDrawList = new ArrayList<>();
|
||||||
|
private final HashMap<Class<? extends Event>, Method> eventMap = new HashMap<>();
|
||||||
|
protected boolean quitOnEscape = true;
|
||||||
|
protected boolean defaultBackground = true;
|
||||||
|
protected int syncTicks = 40;
|
||||||
|
private int syncTicksLeft = -1;
|
||||||
|
|
||||||
|
public WDScreen(Component component) {
|
||||||
|
super(component);
|
||||||
|
Method[] methods = getClass().getMethods();
|
||||||
|
|
||||||
|
for(Method m : methods) {
|
||||||
|
if(m.getAnnotation(GuiSubscribe.class) != null) {
|
||||||
|
if(!Modifier.isPublic(m.getModifiers()))
|
||||||
|
throw new RuntimeException("Found non public @GuiSubscribe");
|
||||||
|
|
||||||
|
Class<?> params[] = m.getParameterTypes();
|
||||||
|
if(params.length != 1 || !Event.class.isAssignableFrom(params[0]))
|
||||||
|
throw new RuntimeException("Invalid parameters for @GuiSubscribe");
|
||||||
|
|
||||||
|
eventMap.put((Class<? extends Event>) params[0], m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <T extends Control> T addControl(T ctrl) {
|
||||||
|
controls.add(ctrl);
|
||||||
|
return ctrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int screen2DisplayX(int x) {
|
||||||
|
double ret = ((double) x) / ((double) width) * ((double) minecraft.getWindow().getWidth());
|
||||||
|
return (int) ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int screen2DisplayY(int y) {
|
||||||
|
double ret = ((double) y) / ((double) height) * ((double) minecraft.getWindow().getHeight());
|
||||||
|
return (int) ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int display2ScreenX(int x) {
|
||||||
|
double ret = ((double) x) / ((double) minecraft.getWindow().getWidth()) * ((double) width);
|
||||||
|
return (int) ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int display2ScreenY(int y) {
|
||||||
|
double ret = ((double) y) / ((double) minecraft.getWindow().getHeight()) * ((double) height);
|
||||||
|
return (int) ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void centerControls() {
|
||||||
|
//Determine bounding box
|
||||||
|
Bounds bounds = Control.findBounds(controls);
|
||||||
|
|
||||||
|
//Translation vector
|
||||||
|
int diffX = (width - bounds.maxX - bounds.minX) / 2;
|
||||||
|
int diffY = (height - bounds.maxY - bounds.minY) / 2;
|
||||||
|
|
||||||
|
//Translate controls
|
||||||
|
for(Control ctrl : controls) {
|
||||||
|
int x = ctrl.getX();
|
||||||
|
int y = ctrl.getY();
|
||||||
|
|
||||||
|
ctrl.setPos(x + diffX, y + diffY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
if(defaultBackground)
|
||||||
|
renderBackground(poseStack, mouseX, mouseY, ptt);
|
||||||
|
|
||||||
|
RenderSystem.setShaderColor(1.f, 1.f, 1.f, 1.f);
|
||||||
|
|
||||||
|
for(Control ctrl: controls)
|
||||||
|
ctrl.draw(poseStack, mouseX, mouseY, ptt);
|
||||||
|
|
||||||
|
for(Control ctrl: postDrawList)
|
||||||
|
ctrl.postDraw(poseStack, mouseX, mouseY, ptt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean charTyped(char codePoint, int modifiers) {
|
||||||
|
boolean typed = false;
|
||||||
|
|
||||||
|
for(Control ctrl: controls)
|
||||||
|
typed = typed || ctrl.keyTyped(codePoint, modifiers);
|
||||||
|
|
||||||
|
return typed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
boolean clicked = false;
|
||||||
|
|
||||||
|
Control clickedEl = null;
|
||||||
|
for(Control ctrl: controls) {
|
||||||
|
clicked = ctrl.mouseClicked(mouseX, mouseY, button);
|
||||||
|
if (clicked) {
|
||||||
|
clickedEl = ctrl;
|
||||||
|
break; // don't assume the compiler will optimize stuff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clicked) {
|
||||||
|
for (Control control : controls) {
|
||||||
|
if (control != clickedEl)
|
||||||
|
control.unfocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clicked;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||||
|
boolean mouseReleased = false;
|
||||||
|
|
||||||
|
for(Control ctrl: controls)
|
||||||
|
mouseReleased = mouseReleased || ctrl.mouseReleased(mouseX, mouseY, button);
|
||||||
|
|
||||||
|
return mouseReleased;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) {
|
||||||
|
boolean dragged = false;
|
||||||
|
|
||||||
|
for(Control ctrl: controls)
|
||||||
|
dragged = dragged || ctrl.mouseClickMove(mouseX, mouseY, button, dragX, dragY);
|
||||||
|
|
||||||
|
return dragged;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
CURRENT_SCREEN = this;
|
||||||
|
// minecraft.keyboardHandler.setSendRepeatsToGui(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
if(syncTicksLeft >= 0) {
|
||||||
|
sync();
|
||||||
|
syncTicksLeft = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Control ctrl : controls)
|
||||||
|
ctrl.destroy();
|
||||||
|
|
||||||
|
// Minecraft.getInstance().keyboardHandler.setSendRepeatsToGui(false);
|
||||||
|
CURRENT_SCREEN = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
|
||||||
|
boolean scrolled = false;
|
||||||
|
|
||||||
|
for(Control ctrl : controls)
|
||||||
|
scrolled = scrolled || ctrl.mouseScroll(mouseX, mouseY, scrollY);
|
||||||
|
|
||||||
|
return scrolled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseMoved(double mouseX, double mouseY) {
|
||||||
|
boolean moved = false;
|
||||||
|
|
||||||
|
for(Control ctrl : controls)
|
||||||
|
moved = moved || ctrl.mouseMove(mouseX, mouseY);
|
||||||
|
|
||||||
|
super.mouseMoved(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
boolean down = false;
|
||||||
|
|
||||||
|
for (Control ctrl : controls)
|
||||||
|
down = down || ctrl.keyDown(keyCode, scanCode, modifiers);
|
||||||
|
|
||||||
|
if (this instanceof GuiKeyboard) {
|
||||||
|
return down;
|
||||||
|
} else {
|
||||||
|
return new GuiServer(new Vector3i(), new NameUUIDPair()).keyPressed(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
|
||||||
|
boolean up = false;
|
||||||
|
|
||||||
|
for(Control ctrl : controls)
|
||||||
|
up = up || ctrl.keyUp(keyCode, scanCode, modifiers);
|
||||||
|
|
||||||
|
return up || super.keyReleased(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object actionPerformed(Event ev) {
|
||||||
|
Method m = eventMap.get(ev.getClass());
|
||||||
|
|
||||||
|
if(m != null) {
|
||||||
|
try {
|
||||||
|
return m.invoke(this, ev);
|
||||||
|
} catch(IllegalAccessException e) {
|
||||||
|
Log.errorEx("Access to event %s of screen %s is denied", e, ev.getClass().getSimpleName(), getClass().getSimpleName());
|
||||||
|
} catch(InvocationTargetException e) {
|
||||||
|
Log.errorEx("Event %s of screen %s failed", e, ev.getClass().getSimpleName(), getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Control> T getControlByName(String name) {
|
||||||
|
for(Control ctrl : controls) {
|
||||||
|
if(name.equals(ctrl.getName()))
|
||||||
|
return (T) ctrl;
|
||||||
|
|
||||||
|
if(ctrl instanceof Container) {
|
||||||
|
Control ret = ((Container) ctrl).getByName(name);
|
||||||
|
|
||||||
|
if(ret != null)
|
||||||
|
return (T) ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addLoadCustomVariables(Map<String, Double> vars) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadFrom(ResourceLocation resLoc) {
|
||||||
|
try {
|
||||||
|
JsonObject root = GuiLoader.getJson(resLoc);
|
||||||
|
|
||||||
|
if(root == null)
|
||||||
|
throw new RuntimeException("Could not load GUI file " + resLoc.toString());
|
||||||
|
|
||||||
|
if(!root.has("controls") || !root.get("controls").isJsonArray())
|
||||||
|
throw new RuntimeException("In GUI file " + resLoc.toString() + ": missing root 'controls' object.");
|
||||||
|
|
||||||
|
HashMap<String, Double> vars = new HashMap<>();
|
||||||
|
vars.put("width", (double) width);
|
||||||
|
vars.put("height", (double) height);
|
||||||
|
vars.put("displayWidth", (double) minecraft.getWindow().getWidth());
|
||||||
|
vars.put("displayHeight", (double) minecraft.getWindow().getHeight());
|
||||||
|
addLoadCustomVariables(vars);
|
||||||
|
|
||||||
|
JsonArray content = root.get("controls").getAsJsonArray();
|
||||||
|
for(JsonElement elem: content)
|
||||||
|
controls.add(GuiLoader.create(new JsonOWrapper(elem.getAsJsonObject(), vars)));
|
||||||
|
|
||||||
|
Field[] fields = getClass().getDeclaredFields();
|
||||||
|
for(Field f: fields) {
|
||||||
|
f.setAccessible(true);
|
||||||
|
FillControl fc = f.getAnnotation(FillControl.class);
|
||||||
|
|
||||||
|
if(fc != null) {
|
||||||
|
String name = fc.name().isEmpty() ? f.getName() : fc.name();
|
||||||
|
Control ctrl = getControlByName(name);
|
||||||
|
|
||||||
|
if(ctrl == null) {
|
||||||
|
if(fc.required())
|
||||||
|
throw new RuntimeException("In GUI file " + resLoc.toString() + ": missing required control " + name);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!f.getType().isAssignableFrom(ctrl.getClass()))
|
||||||
|
throw new RuntimeException("In GUI file " + resLoc.toString() + ": invalid type for control " + name);
|
||||||
|
|
||||||
|
try {
|
||||||
|
f.set(this, ctrl);
|
||||||
|
} catch(IllegalAccessException e) {
|
||||||
|
if(fc.required())
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(root.has("center") && root.get("center").getAsBoolean())
|
||||||
|
centerControls();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resize(Minecraft minecraft, int width, int height) {
|
||||||
|
for(Control ctrl : controls)
|
||||||
|
ctrl.destroy();
|
||||||
|
|
||||||
|
controls.clear();
|
||||||
|
super.resize(minecraft, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void requestAutocomplete(String beginning, boolean matchExact) {
|
||||||
|
WDNetworkRegistry.INSTANCE.sendToServer(new C2SMessageACQuery(beginning, matchExact));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAutocompleteResult(NameUUIDPair pairs[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAutocompleteFailure() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void requestSync() {
|
||||||
|
syncTicksLeft = syncTicks - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean syncRequested() {
|
||||||
|
return syncTicksLeft >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void abortSync() {
|
||||||
|
syncTicksLeft = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sync() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if(syncTicksLeft >= 0) {
|
||||||
|
if(--syncTicksLeft < 0)
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawItemStackTooltip(GuiGraphics poseStack, ItemStack is, int x, int y) {
|
||||||
|
poseStack.renderTooltip(Minecraft.getInstance().font, is, x, y); //Since it's protected...
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawTooltip(GuiGraphics poseStack, List<String> lines, int x, int y) {
|
||||||
|
poseStack.renderTooltip(Minecraft.getInstance().font, lines.stream().map(a -> FormattedCharSequence.forward(a, Style.EMPTY)).collect(Collectors.toList()), x, y); //This is also protected...
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requirePostDraw(Control ctrl) {
|
||||||
|
if(!postDrawList.contains(ctrl))
|
||||||
|
postDrawList.add(ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPauseScreen() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean isForBlock(BlockPos bp, BlockSide side);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getWikiPageName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Bypass for needing to use Components
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,271 @@
|
|||||||
|
package net.montoyo.wd.client.gui.camera;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.commands.arguments.EntityAnchorArgument;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.phys.Vec2;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.neoforged.neoforge.client.event.ViewportEvent;
|
||||||
|
import net.neoforged.neoforge.client.event.ClientTickEvent;
|
||||||
|
import net.montoyo.wd.client.gui.GuiKeyboard;
|
||||||
|
import net.montoyo.wd.config.ClientConfig;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.ScreenData;
|
||||||
|
import net.montoyo.wd.utilities.browser.WDBrowser;
|
||||||
|
import net.montoyo.wd.utilities.browser.handlers.js.queries.ElementCenterQuery;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
|
||||||
|
public class KeyboardCamera {
|
||||||
|
private static ScreenBlockEntity tes;
|
||||||
|
private static BlockSide side;
|
||||||
|
|
||||||
|
private static double oxCrd = -1;
|
||||||
|
private static double xCrd = -1;
|
||||||
|
private static double nxCrd = -1;
|
||||||
|
private static double oyCrd = -1;
|
||||||
|
private static double yCrd = -1;
|
||||||
|
private static double nyCrd = -1;
|
||||||
|
|
||||||
|
private static double nextX = -1;
|
||||||
|
private static double nextY = -1;
|
||||||
|
private static double focalX = -1;
|
||||||
|
private static double focalY = -1;
|
||||||
|
|
||||||
|
private static final boolean[] mouseStatus = new boolean[2];
|
||||||
|
|
||||||
|
protected static Vec2 pxToHit(ScreenData scr, Vec2 dst) {
|
||||||
|
float cx, cy;
|
||||||
|
if (scr.rotation.isVertical) {
|
||||||
|
cy = dst.x;
|
||||||
|
cx = dst.y;
|
||||||
|
} else {
|
||||||
|
cx = dst.x;
|
||||||
|
cy = dst.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
cx /= (float) scr.resolution.x;
|
||||||
|
cy /= (float) scr.resolution.y;
|
||||||
|
|
||||||
|
switch (scr.rotation) {
|
||||||
|
case ROT_270:
|
||||||
|
cx = 1.0f - cx;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROT_180:
|
||||||
|
cx = 1.0f - cx;
|
||||||
|
cy = 1.0f - cy;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ROT_90:
|
||||||
|
cy = 1.0f - cy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (side != BlockSide.BOTTOM)
|
||||||
|
cy = 1.0f - cy;
|
||||||
|
|
||||||
|
float swInverse = (((float) scr.size.x) - 4.f / 16.f);
|
||||||
|
float shInverse = (((float) scr.size.y) - 4.f / 16.f);
|
||||||
|
|
||||||
|
cx *= swInverse;
|
||||||
|
cy *= shInverse;
|
||||||
|
|
||||||
|
if (side.right.x > 0 || side.right.z > 0)
|
||||||
|
cx += 1.f;
|
||||||
|
|
||||||
|
if (side == BlockSide.TOP || side == BlockSide.BOTTOM)
|
||||||
|
cy -= 1.f;
|
||||||
|
|
||||||
|
return new Vec2(cx + (2 / 16f), cy + (2 / 16f));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void updateCrd(ElementCenterQuery lock) {
|
||||||
|
ScreenData scr = tes.getScreen(side);
|
||||||
|
if (scr != null) {
|
||||||
|
Vec2 c;
|
||||||
|
|
||||||
|
if (!mouseStatus[0] && !mouseStatus[1]) {
|
||||||
|
if (lock.hasFocused()) {
|
||||||
|
if (ClientConfig.Input.keyboardCamera) {
|
||||||
|
nextX = lock.getX();
|
||||||
|
nextY = lock.getY();
|
||||||
|
|
||||||
|
c = pxToHit(scr, new Vec2((float) nextX, (float) nextY));
|
||||||
|
} else c = new Vec2(scr.size.x / 2f, scr.size.y / 2f);
|
||||||
|
} else c = new Vec2(scr.size.x / 2f, scr.size.y / 2f);
|
||||||
|
// } else c = new Vec2((float) focalX, (float) focalY);
|
||||||
|
} else return;
|
||||||
|
|
||||||
|
focalX = c.x;
|
||||||
|
focalY = c.y;
|
||||||
|
|
||||||
|
nextX = c.x;
|
||||||
|
nextY = c.y;
|
||||||
|
|
||||||
|
if (nextX < 0) nextX = 0;
|
||||||
|
else if (nextX > scr.size.x) nextX = scr.size.x;
|
||||||
|
if (nextY < 0) nextY = 0;
|
||||||
|
else if (nextY > scr.size.y) nextY = scr.size.y;
|
||||||
|
|
||||||
|
float scl = Math.max(scr.size.x, scr.size.y);
|
||||||
|
|
||||||
|
double mx = Minecraft.getInstance().mouseHandler.xpos();
|
||||||
|
mx /= Minecraft.getInstance().getWindow().getWidth();
|
||||||
|
|
||||||
|
double my = Minecraft.getInstance().mouseHandler.ypos();
|
||||||
|
my /= Minecraft.getInstance().getWindow().getHeight();
|
||||||
|
|
||||||
|
Vec2 v2 = new Vec2((float) mx, (float) my).add(-0.5f);
|
||||||
|
|
||||||
|
nextX += v2.x * scl;
|
||||||
|
nextY -= v2.y * scl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void pollElement() {
|
||||||
|
ScreenBlockEntity teTmp = tes;
|
||||||
|
BlockSide sdTmp = side;
|
||||||
|
|
||||||
|
// async nonsense can occur here
|
||||||
|
if (teTmp == null || sdTmp == null) return;
|
||||||
|
|
||||||
|
ScreenData scr = teTmp.getScreen(sdTmp);
|
||||||
|
if (scr != null) {
|
||||||
|
if (scr.browser instanceof WDBrowser wdBrowser) {
|
||||||
|
wdBrowser.focusedElement().dispatch(scr.browser);
|
||||||
|
updateCrd(((WDBrowser) scr.browser).focusedElement());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float[] getAngle(Entity e, double pct) {
|
||||||
|
BlockEntity tes = KeyboardCamera.tes;
|
||||||
|
BlockSide side = KeyboardCamera.side;
|
||||||
|
if (tes == null) return new float[]{Float.NaN, 0};
|
||||||
|
if (side == null) return new float[]{Float.NaN, 0};
|
||||||
|
|
||||||
|
double coxCrd = Mth.lerp(0.5 * pct, oxCrd, xCrd);
|
||||||
|
double coyCrd = Mth.lerp(0.5 * pct, oyCrd, yCrd);
|
||||||
|
|
||||||
|
double focalX = tes.getBlockPos().getX() +
|
||||||
|
side.right.x * (coxCrd - 1) + side.up.x * coyCrd + Math.abs(side.forward.x) * 0.5;
|
||||||
|
double focalY = tes.getBlockPos().getY() +
|
||||||
|
side.right.y * (coxCrd - 1) + side.up.y * coyCrd + Math.abs(side.forward.y) * 0.5;
|
||||||
|
double focalZ = tes.getBlockPos().getZ() +
|
||||||
|
side.right.z * (coxCrd - 1) + side.up.z * coyCrd + Math.abs(side.forward.z) * 0.5;
|
||||||
|
|
||||||
|
focalX += side.forward.x * 0.5f;
|
||||||
|
focalY += side.forward.y * 0.5f;
|
||||||
|
focalZ += side.forward.z * 0.5f;
|
||||||
|
|
||||||
|
float[] angle = lookAt(
|
||||||
|
e, EntityAnchorArgument.Anchor.EYES,
|
||||||
|
new Vec3(focalX, focalY, focalZ)
|
||||||
|
);
|
||||||
|
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setMouse(int side, boolean pressed) {
|
||||||
|
mouseStatus[side] = pressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateCamera(ViewportEvent.ComputeCameraAngles event) {
|
||||||
|
if (tes == null) {
|
||||||
|
xCrd = -1;
|
||||||
|
yCrd = -1;
|
||||||
|
return; // nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xCrd == -1) return;
|
||||||
|
if (yCrd == -1) return;
|
||||||
|
|
||||||
|
float[] angle = getAngle(event.getCamera().getEntity(), event.getPartialTick());
|
||||||
|
|
||||||
|
if (Float.isNaN(angle[0])) return;
|
||||||
|
|
||||||
|
// float xRot = event.getYaw(); // left right
|
||||||
|
// float yRot = event.getPitch(); // up down
|
||||||
|
|
||||||
|
// TODO: smooth in/out
|
||||||
|
event.setYaw(angle[1]);
|
||||||
|
event.setPitch(angle[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void focus(ScreenBlockEntity screen, BlockSide side) {
|
||||||
|
KeyboardCamera.tes = screen;
|
||||||
|
KeyboardCamera.side = side;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float[] lookAt(Entity entity, EntityAnchorArgument.Anchor pAnchor, Vec3 pTarget) {
|
||||||
|
Vec3 vec3 = pAnchor.apply(entity);
|
||||||
|
double d0 = pTarget.x - vec3.x;
|
||||||
|
double d1 = pTarget.y - vec3.y;
|
||||||
|
double d2 = pTarget.z - vec3.z;
|
||||||
|
double d3 = Math.sqrt(d0 * d0 + d2 * d2);
|
||||||
|
float xr = (Mth.wrapDegrees((float) (-(Mth.atan2(d1, d3) * (double) (180F / (float) Math.PI)))));
|
||||||
|
float yr = (Mth.wrapDegrees((float) (Mth.atan2(d2, d0) * (double) (180F / (float) Math.PI)) - 90.0F));
|
||||||
|
return new float[]{xr, yr};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int delay = 8;
|
||||||
|
|
||||||
|
public static void gameTick(ClientTickEvent.Post event) {
|
||||||
|
if (mouseStatus[0] || mouseStatus[1]) {
|
||||||
|
oxCrd = Mth.lerp(0.5, oxCrd, xCrd);
|
||||||
|
oyCrd = Mth.lerp(0.5, oyCrd, yCrd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (side == null) {
|
||||||
|
delay = 1;
|
||||||
|
oxCrd = -1;
|
||||||
|
oyCrd = -1;
|
||||||
|
xCrd = -1;
|
||||||
|
yCrd = -1;
|
||||||
|
nxCrd = -1;
|
||||||
|
nyCrd = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Minecraft.getInstance().screen instanceof GuiKeyboard)) {
|
||||||
|
tes = null;
|
||||||
|
side = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pollElement();
|
||||||
|
|
||||||
|
double anxx = nextX;
|
||||||
|
double anxy = nextY;
|
||||||
|
|
||||||
|
if (
|
||||||
|
anxx == -1 || anxy == -1 ||
|
||||||
|
nxCrd == -1 || nyCrd == -1 ||
|
||||||
|
oxCrd == -1 || oyCrd == -1 ||
|
||||||
|
xCrd == -1 || yCrd == -1
|
||||||
|
) {
|
||||||
|
ScreenData data = tes.getScreen(side);
|
||||||
|
if (data == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
anxx = data.size.x / 2.0;
|
||||||
|
anxy = data.size.y / 2.0;
|
||||||
|
|
||||||
|
if (nxCrd == -1) {
|
||||||
|
oxCrd = xCrd = anxx;
|
||||||
|
oyCrd = yCrd = anxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nxCrd = anxx;
|
||||||
|
nyCrd = anxy;
|
||||||
|
|
||||||
|
oxCrd = Mth.lerp(0.5, oxCrd, xCrd);
|
||||||
|
xCrd = Mth.lerp(0.15, xCrd, nxCrd);
|
||||||
|
|
||||||
|
oyCrd = Mth.lerp(0.5, oyCrd, yCrd);
|
||||||
|
yCrd = Mth.lerp(0.15, yCrd, nyCrd);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
|
||||||
|
public abstract class BasicControl extends Control {
|
||||||
|
|
||||||
|
protected int x;
|
||||||
|
protected int y;
|
||||||
|
protected boolean visible = true;
|
||||||
|
protected boolean disabled = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPos(int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDisabled() {
|
||||||
|
return disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisabled(boolean disabled) {
|
||||||
|
this.disabled = disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enable() {
|
||||||
|
disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable() {
|
||||||
|
disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(boolean visible) {
|
||||||
|
this.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hide() {
|
||||||
|
visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
x = json.getInt("x", 0);
|
||||||
|
y = json.getInt("y", 0);
|
||||||
|
disabled = json.getBool("disabled", false);
|
||||||
|
visible = json.getBool("visible", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
238
src/main/java/net/montoyo/wd/client/gui/controls/Button.java
Normal file
238
src/main/java/net/montoyo/wd/client/gui/controls/Button.java
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.ComponentContents;
|
||||||
|
import net.minecraft.network.chat.MutableComponent;
|
||||||
|
import net.minecraft.network.chat.Style;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class Button extends Control {
|
||||||
|
|
||||||
|
protected final net.minecraft.client.gui.components.Button btn;
|
||||||
|
protected boolean selected = false;
|
||||||
|
protected boolean shiftDown = false;
|
||||||
|
protected int originalColor = 0;
|
||||||
|
protected int shiftColor = 0;
|
||||||
|
|
||||||
|
public static class ClickEvent extends Event<Button> {
|
||||||
|
|
||||||
|
private final boolean shiftDown;
|
||||||
|
|
||||||
|
public ClickEvent(Button btn) {
|
||||||
|
source = btn;
|
||||||
|
shiftDown = btn.shiftDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShiftDown() {
|
||||||
|
return shiftDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Button() {
|
||||||
|
btn = net.minecraft.client.gui.components.Button.builder(Component.nullToEmpty(""), a -> {})
|
||||||
|
.bounds(0, 0, 0, 0)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Button(String text, int x, int y, int width) {
|
||||||
|
btn = net.minecraft.client.gui.components.Button.builder(Component.nullToEmpty(text), a -> {})
|
||||||
|
.bounds(x, y, width, 20)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Button(String text, int x, int y) {
|
||||||
|
btn = net.minecraft.client.gui.components.Button.builder(Component.nullToEmpty(text), a -> {})
|
||||||
|
.bounds(0, 0, x, y)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
|
||||||
|
if(mouseButton == 0 && btn.mouseClicked(mouseX, mouseY, mouseButton)) {
|
||||||
|
selected = true;
|
||||||
|
btn.playDownSound(mc.getSoundManager());
|
||||||
|
|
||||||
|
if(!onClick())
|
||||||
|
parent.actionPerformed(new ClickEvent(this));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int state) {
|
||||||
|
if(selected && state == 0) {
|
||||||
|
btn.mouseReleased(mouseX, mouseY,state);
|
||||||
|
selected = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
btn.setFGColor(16777215);
|
||||||
|
btn.render(poseStack, mouseX, mouseY, ptt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
btn.setMessage(Component.nullToEmpty(label));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return btn.getMessage().getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(int width) {
|
||||||
|
btn.setWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(int height) {
|
||||||
|
btn.setHeight(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return btn.getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return btn.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPos(int x, int y) {
|
||||||
|
btn.setPosition(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return btn.getX();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getY() {
|
||||||
|
return btn.getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public net.minecraft.client.gui.components.Button getMcButton() {
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisabled(boolean dis) {
|
||||||
|
btn.active = !dis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDisabled() {
|
||||||
|
return !btn.active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enable() {
|
||||||
|
btn.active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable() {
|
||||||
|
btn.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(boolean visible) {
|
||||||
|
btn.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return btn.visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
btn.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hide() {
|
||||||
|
btn.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShiftDown() {
|
||||||
|
return shiftDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyUp(int key, int scanCode, int modifiers) {
|
||||||
|
if(key == GLFW.GLFW_KEY_LEFT_SHIFT || key == GLFW.GLFW_KEY_RIGHT_SHIFT) {
|
||||||
|
shiftDown = false;
|
||||||
|
btn.setFGColor(originalColor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyDown(int key, int scanCode, int modifiers) {
|
||||||
|
if(key == GLFW.GLFW_KEY_LEFT_SHIFT || key == GLFW.GLFW_KEY_RIGHT_SHIFT) {
|
||||||
|
shiftDown = true;
|
||||||
|
btn.setFGColor(shiftColor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTextColor(int color) {
|
||||||
|
originalColor = color;
|
||||||
|
if(!shiftDown)
|
||||||
|
btn.setFGColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTextColor() {
|
||||||
|
return btn.getFGColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShiftTextColor(int shiftColor) {
|
||||||
|
this.shiftColor = shiftColor;
|
||||||
|
if(shiftDown)
|
||||||
|
btn.setFGColor(shiftColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getShiftTextColor() {
|
||||||
|
return shiftColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
btn.setPosition(
|
||||||
|
json.getInt("x", 0),
|
||||||
|
json.getInt("y", 0)
|
||||||
|
);
|
||||||
|
btn.setWidth(json.getInt("width", 200));
|
||||||
|
btn.setHeight(json.getInt("height", 20));
|
||||||
|
btn.setMessage(Component.nullToEmpty(tr(json.getString("label", btn.getMessage().getContents().toString()))));
|
||||||
|
btn.active = json.getBool("active", btn.active);
|
||||||
|
btn.visible = json.getBool("visible", btn.visible);
|
||||||
|
|
||||||
|
originalColor = json.getColor("color", originalColor);
|
||||||
|
shiftColor = json.getColor("shiftColor", shiftColor);
|
||||||
|
btn.setFGColor(originalColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean onClick() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
144
src/main/java/net/montoyo/wd/client/gui/controls/CheckBox.java
Normal file
144
src/main/java/net/montoyo/wd/client/gui/controls/CheckBox.java
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
|
||||||
|
public class CheckBox extends BasicControl {
|
||||||
|
|
||||||
|
private static final ResourceLocation texUnchecked = ResourceLocation.fromNamespaceAndPath("webdisplays", "textures/gui/checkbox.png");
|
||||||
|
private static final ResourceLocation texChecked = ResourceLocation.fromNamespaceAndPath("webdisplays", "textures/gui/checkbox_checked.png");
|
||||||
|
public static final int WIDTH = 16;
|
||||||
|
public static final int HEIGHT = 16;
|
||||||
|
|
||||||
|
public static class CheckedEvent extends Event<CheckBox> {
|
||||||
|
|
||||||
|
private final boolean checked;
|
||||||
|
|
||||||
|
public CheckedEvent(CheckBox cb) {
|
||||||
|
source = cb;
|
||||||
|
checked = cb.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isChecked() {
|
||||||
|
return checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
private int labelW;
|
||||||
|
private boolean checked;
|
||||||
|
private java.util.List<String> tooltip;
|
||||||
|
|
||||||
|
public CheckBox() {
|
||||||
|
label = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckBox(int x, int y, String label) {
|
||||||
|
this.label = label;
|
||||||
|
labelW = font.width(label);
|
||||||
|
checked = false;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckBox(int x, int y, String label, boolean val) {
|
||||||
|
this.label = label;
|
||||||
|
labelW = font.width(label);
|
||||||
|
checked = val;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
|
||||||
|
if(mouseButton == 0 && !disabled) {
|
||||||
|
if(mouseX >= x && mouseX <= x + WIDTH + 2 + labelW && mouseY >= y && mouseY < y + HEIGHT) {
|
||||||
|
checked = !checked;
|
||||||
|
mc.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
|
||||||
|
parent.actionPerformed(new CheckedEvent(this));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
if(visible) {
|
||||||
|
// GlStateManager.disableAlpha();
|
||||||
|
poseStack.pose().pushPose();
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
poseStack.blit(
|
||||||
|
checked ? texChecked : texUnchecked, x, y, 0, 0, 0, WIDTH, HEIGHT, WIDTH, HEIGHT
|
||||||
|
);
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
|
||||||
|
poseStack.pose().popPose();
|
||||||
|
boolean inside = (!disabled && mouseX >= x && mouseX <= x + WIDTH + 2 + labelW && mouseY >= y && mouseY < y + HEIGHT);
|
||||||
|
poseStack.drawString(Minecraft.getInstance().font, label, x + WIDTH + 2, y + 4, inside ? 0xFF0080FF : COLOR_WHITE, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
labelW = font.width(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isChecked() {
|
||||||
|
return checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChecked(boolean checked) {
|
||||||
|
this.checked = checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return WIDTH + 2 + labelW;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
label = tr(json.getString("label", ""));
|
||||||
|
labelW = font.width(label);
|
||||||
|
checked = json.getBool("checked", false);
|
||||||
|
|
||||||
|
String tt = tr(json.getString("tooltip", ""));
|
||||||
|
if(!tt.isEmpty()) {
|
||||||
|
tooltip = Lists.newArrayList(tt.split("\\\\n"));
|
||||||
|
parent.requirePostDraw(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postDraw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
if(tooltip != null && !disabled && mouseX >= x && mouseX <= x + WIDTH + 2 + labelW && mouseY >= y && mouseY < y + HEIGHT)
|
||||||
|
parent.drawTooltip(poseStack, tooltip, mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
198
src/main/java/net/montoyo/wd/client/gui/controls/Container.java
Normal file
198
src/main/java/net/montoyo/wd/client/gui/controls/Container.java
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.montoyo.wd.client.gui.loading.GuiLoader;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonAWrapper;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public abstract class Container extends BasicControl {
|
||||||
|
|
||||||
|
protected int paddingX = 0;
|
||||||
|
protected int paddingY = 0;
|
||||||
|
protected final ArrayList<Control> childs = new ArrayList<>();
|
||||||
|
|
||||||
|
public <T extends Control> T addControl(T ctrl) {
|
||||||
|
childs.add(ctrl);
|
||||||
|
return ctrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyTyped(int keyCode, int modifiers) {
|
||||||
|
boolean typed = false;
|
||||||
|
|
||||||
|
if(!disabled) {
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
typed = typed || ctrl.keyTyped(keyCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return typed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyUp(int key, int scanCode, int modifiers) {
|
||||||
|
boolean up = false;
|
||||||
|
|
||||||
|
if(!disabled) {
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
up = up || ctrl.keyUp(key, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return up;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyDown(int key, int scanCode, int modifiers) {
|
||||||
|
boolean down = false;
|
||||||
|
|
||||||
|
if(!disabled) {
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
down = down || ctrl.keyDown(key, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return down;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
|
||||||
|
boolean clicked = false;
|
||||||
|
|
||||||
|
if(!disabled) {
|
||||||
|
mouseX -= x + paddingX;
|
||||||
|
mouseY -= y + paddingY;
|
||||||
|
|
||||||
|
for(Control ctrl : childs) {
|
||||||
|
clicked = ctrl.mouseClicked(mouseX, mouseY, mouseButton);
|
||||||
|
if (clicked) break; // don't assume compiler optimizations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clicked;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int state) {
|
||||||
|
boolean released = false;
|
||||||
|
|
||||||
|
if(!disabled) {
|
||||||
|
mouseX -= x + paddingX;
|
||||||
|
mouseY -= y + paddingY;
|
||||||
|
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
released = released || ctrl.mouseReleased(mouseX, mouseY, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return released;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClickMove(double mouseX, double mouseY, int button, double dragX, double dragY) {
|
||||||
|
boolean clicked = false;
|
||||||
|
|
||||||
|
if(!disabled) {
|
||||||
|
mouseX -= x + paddingX;
|
||||||
|
mouseY -= y + paddingY;
|
||||||
|
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
clicked = clicked || ctrl.mouseClickMove(mouseX, mouseY, button, dragX, dragY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clicked;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseMove(double mouseX, double mouseY) {
|
||||||
|
boolean clicked = false;
|
||||||
|
|
||||||
|
if(!disabled) {
|
||||||
|
mouseX -= x + paddingX;
|
||||||
|
mouseY -= y + paddingY;
|
||||||
|
|
||||||
|
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
clicked = clicked || ctrl.mouseMove(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clicked;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseScroll(double mouseX, double mouseY, double amount) {
|
||||||
|
boolean scrolled = false;
|
||||||
|
|
||||||
|
if(!disabled) {
|
||||||
|
mouseX -= x + paddingX;
|
||||||
|
mouseY -= y + paddingY;
|
||||||
|
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
scrolled = scrolled || ctrl.mouseScroll(mouseX, mouseY, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return scrolled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
if(visible) {
|
||||||
|
mouseX -= x + paddingX;
|
||||||
|
mouseY -= y + paddingY;
|
||||||
|
|
||||||
|
poseStack.pose().pushPose();
|
||||||
|
poseStack.pose().translate(x + paddingX, y + paddingY, 0.0);
|
||||||
|
|
||||||
|
if(disabled) {
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
ctrl.draw(poseStack, -1, -1, ptt);
|
||||||
|
} else {
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
ctrl.draw(poseStack, mouseX, mouseY, ptt);
|
||||||
|
}
|
||||||
|
|
||||||
|
poseStack.pose().popPose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
ctrl.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
|
||||||
|
JsonAWrapper objs = json.getArray("childs");
|
||||||
|
for(int i = 0; i < objs.size(); i++)
|
||||||
|
childs.add(GuiLoader.create(objs.getObject(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Control getByName(String name) {
|
||||||
|
for(Control ctrl : childs) {
|
||||||
|
if(name.equals(ctrl.name))
|
||||||
|
return ctrl;
|
||||||
|
|
||||||
|
if(ctrl instanceof Container) {
|
||||||
|
Control ret = ((Container) ctrl).getByName(name);
|
||||||
|
|
||||||
|
if(ret != null)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unfocus() {
|
||||||
|
for (Control control : childs) {
|
||||||
|
control.unfocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
319
src/main/java/net/montoyo/wd/client/gui/controls/Control.java
Normal file
319
src/main/java/net/montoyo/wd/client/gui/controls/Control.java
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderTarget;
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.*;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.Font;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.resources.language.I18n;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.montoyo.wd.client.gui.WDScreen;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
import net.montoyo.wd.utilities.data.Bounds;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static com.mojang.math.Axis.XP;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public abstract class Control {
|
||||||
|
|
||||||
|
public static final int COLOR_BLACK = 0xFF000000;
|
||||||
|
public static final int COLOR_WHITE = 0xFFFFFFFF;
|
||||||
|
public static final int COLOR_RED = 0xFFFF0000;
|
||||||
|
public static final int COLOR_GREEN = 0xFF00FF00;
|
||||||
|
public static final int COLOR_BLUE = 0xFF0000FF;
|
||||||
|
public static final int COLOR_CYAN = 0xFF00FFFF;
|
||||||
|
public static final int COLOR_MANGENTA = 0xFFFF00FF;
|
||||||
|
public static final int COLOR_YELLOW = 0xFFFFFF00;
|
||||||
|
|
||||||
|
protected final Minecraft mc;
|
||||||
|
protected final Font font;
|
||||||
|
protected final Tesselator tessellator;
|
||||||
|
protected static WDScreen parent;
|
||||||
|
protected String name;
|
||||||
|
protected Object userdata;
|
||||||
|
|
||||||
|
public Control() {
|
||||||
|
mc = Minecraft.getInstance();
|
||||||
|
font = mc.font;
|
||||||
|
tessellator = Tesselator.getInstance();
|
||||||
|
parent = WDScreen.CURRENT_SCREEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getUserdata() {
|
||||||
|
return userdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserdata(Object userdata) {
|
||||||
|
this.userdata = userdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean keyTyped(int keyCode, int modifier) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean keyUp(int key, int scanCode, int modifiers) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean keyDown(int key, int scanCode, int modifiers) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unfocus() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int state) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mouseClickMove(double mouseX, double mouseY, int button, double dragX, double dragY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mouseMove(double mouseX, double mouseY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mouseScroll(double mouseX, double mouseY, double amount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postDraw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public WDScreen getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int getX();
|
||||||
|
public abstract int getY();
|
||||||
|
public abstract int getWidth();
|
||||||
|
public abstract int getHeight();
|
||||||
|
public abstract void setPos(int x, int y);
|
||||||
|
|
||||||
|
public void fillRect(MultiBufferSource.BufferSource source, int x, double y, int w, int h, int color) {
|
||||||
|
float x1 = (float) x;
|
||||||
|
float y1 = (float) y;
|
||||||
|
float x2 = (float) (x + w);
|
||||||
|
float y2 = (float) (y + h);
|
||||||
|
int a = (color >> 24) & 0xFF;
|
||||||
|
int r = (color >> 16) & 0xFF;
|
||||||
|
int g = (color >> 8 ) & 0xFF;
|
||||||
|
int b = color & 0xFF;
|
||||||
|
|
||||||
|
float[] sdrCol = Arrays.copyOf(RenderSystem.getShaderColor(), 4);
|
||||||
|
RenderSystem.setShaderColor(1, 1, 1, 1f);
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
VertexConsumer consumer = source.getBuffer(RenderType.gui());
|
||||||
|
consumer.addVertex(x1, y2, 0.0f).setColor(r, g, b, a);
|
||||||
|
consumer.addVertex(x2, y2, 0.0f).setColor(r, g, b, a);
|
||||||
|
consumer.addVertex(x2, y1, 0.0f).setColor(r, g, b, a);
|
||||||
|
consumer.addVertex(x1, y1, 0.0f).setColor(r, g, b, a);
|
||||||
|
|
||||||
|
RenderSystem.setShaderColor(sdrCol[0], sdrCol[1], sdrCol[2], sdrCol[3]);
|
||||||
|
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillTexturedRect(PoseStack poseStack, int x, int y, int w, int h, double u1, double v1, double u2, double v2) {
|
||||||
|
float x1 = x;
|
||||||
|
float y1 = y;
|
||||||
|
float x2 = (x + w);
|
||||||
|
float y2 = (y + h);
|
||||||
|
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionTexColorShader);
|
||||||
|
Matrix4f p = poseStack.last().pose();
|
||||||
|
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR);
|
||||||
|
buffer.addVertex(p, x1, y2, 0.0f).setColor(1f, 1f, 1f, 1f).setUv((float) u1, (float) v2);
|
||||||
|
buffer.addVertex(p, x2, y2, 0.0f).setColor(1f, 1f, 1f, 1f).setUv((float) u2, (float) v2);
|
||||||
|
buffer.addVertex(p, x2, y1, 0.0f).setColor(1f, 1f, 1f, 1f).setUv((float) u2, (float) v1);
|
||||||
|
buffer.addVertex(p, x1, y1, 0.0f).setColor(1f, 1f, 1f, 1f).setUv((float) u1, (float) v1);
|
||||||
|
BufferUploader.drawWithShader(buffer.buildOrThrow());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void blend(boolean enable) {
|
||||||
|
if(enable) {
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_CONSTANT_ALPHA);
|
||||||
|
} else
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindTexture(ResourceLocation resLoc) {
|
||||||
|
if(resLoc == null)
|
||||||
|
RenderSystem.setShaderTexture(0, 0); //Damn state manager
|
||||||
|
else
|
||||||
|
RenderSystem.setShaderTexture(0, resLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawBorder(GuiGraphics poseStack, int x, int y, int w, int h, int color) {
|
||||||
|
drawBorder(poseStack, x, y, w, h, color, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawBorder(GuiGraphics poseStack, int x, int y, int w, int h, int color, double sz) {
|
||||||
|
double x1 = (double) x;
|
||||||
|
double y1 = (double) y;
|
||||||
|
double x2 = (double) (x + w);
|
||||||
|
double y2 = (double) (y + h);
|
||||||
|
int a = (color >> 24) & 0xFF;
|
||||||
|
int r = (color >> 16) & 0xFF;
|
||||||
|
int g = (color >> 8 ) & 0xFF;
|
||||||
|
int b = color & 0xFF;
|
||||||
|
|
||||||
|
float[] sdrCol = Arrays.copyOf(RenderSystem.getShaderColor(), 4);
|
||||||
|
RenderSystem.setShaderColor(((float) r) / 255.f, ((float) g) / 255.f, ((float) b) / 255.f, ((float) a) / 255.f);
|
||||||
|
// RenderSystem.enableTexture();
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionShader);
|
||||||
|
Matrix4f matrix = poseStack.pose().last().pose();
|
||||||
|
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION);
|
||||||
|
//Top edge (y = y1)
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)(y1 + sz), 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)(y1 + sz), 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)y1, 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)y1, 0.0f);
|
||||||
|
|
||||||
|
//Bottom edge (y = y2)
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)y2, 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)y2, 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)(y2 - sz), 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)(y2 - sz), 0.0f);
|
||||||
|
|
||||||
|
//Left edge (x = x1)
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)y2, 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)(x1 + sz), (float)y2, 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)(x1 + sz), (float)y1, 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)y1, 0.0f);
|
||||||
|
|
||||||
|
//Right edge (x = x2)
|
||||||
|
buffer.addVertex(matrix, (float)(x2 - sz), (float)y2, 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)y2, 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)y1, 0.0f);
|
||||||
|
buffer.addVertex(matrix, (float)(x2 - sz), (float)y1, 0.0f);
|
||||||
|
BufferUploader.drawWithShader(buffer.buildOrThrow());
|
||||||
|
|
||||||
|
RenderSystem.setShaderColor(sdrCol[0], sdrCol[1], sdrCol[2], sdrCol[3]);
|
||||||
|
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
// RenderSystem.enableTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiGraphics beginFramebuffer(RenderTarget fbo, float vpW, float vpH) {
|
||||||
|
GuiGraphics tmpGraphics = new GuiGraphics(Minecraft.getInstance(), Minecraft.getInstance().renderBuffers().bufferSource());
|
||||||
|
|
||||||
|
fbo.bindWrite(true);
|
||||||
|
|
||||||
|
RenderSystem.backupProjectionMatrix();
|
||||||
|
RenderSystem.setProjectionMatrix(new Matrix4f().ortho(0.0f, vpW, vpH, 0.0f, -1.0f, 1.0f), VertexSorting.ORTHOGRAPHIC_Z);
|
||||||
|
|
||||||
|
PoseStack ps = tmpGraphics.pose();
|
||||||
|
ps.pushPose();
|
||||||
|
ps.setIdentity();
|
||||||
|
ps.mulPose(XP.rotationDegrees(180.0f));
|
||||||
|
|
||||||
|
org.joml.Matrix4fStack mv = RenderSystem.getModelViewStack();
|
||||||
|
mv.pushMatrix();
|
||||||
|
mv.set(ps.last().pose());
|
||||||
|
RenderSystem.applyModelViewMatrix();
|
||||||
|
|
||||||
|
if (!fbo.useDepth)
|
||||||
|
RenderSystem.disableDepthTest();
|
||||||
|
|
||||||
|
return tmpGraphics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endFramebuffer(GuiGraphics poseStack, RenderTarget fbo) {
|
||||||
|
if (!fbo.useDepth)
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
|
||||||
|
RenderSystem.colorMask(true, true, true, true);
|
||||||
|
RenderSystem.restoreProjectionMatrix();
|
||||||
|
|
||||||
|
poseStack.pose().popPose();
|
||||||
|
org.joml.Matrix4fStack mv = RenderSystem.getModelViewStack();
|
||||||
|
mv.popMatrix();
|
||||||
|
RenderSystem.applyModelViewMatrix();
|
||||||
|
|
||||||
|
fbo.unbindWrite();
|
||||||
|
mc.getMainRenderTarget().bindWrite(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String tr(String text) {
|
||||||
|
if(text.length() >= 2 && text.charAt(0) == '$') {
|
||||||
|
if(text.charAt(1) == '$')
|
||||||
|
return text.substring(1);
|
||||||
|
else
|
||||||
|
return I18n.get(text.substring(1));
|
||||||
|
} else
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
name = json.getString("name", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bounds findBounds(java.util.List<Control> controlList) {
|
||||||
|
int minX = Integer.MAX_VALUE;
|
||||||
|
int minY = Integer.MAX_VALUE;
|
||||||
|
int maxX = Integer.MIN_VALUE;
|
||||||
|
int maxY = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
for(Control ctrl : controlList) {
|
||||||
|
int x = ctrl.getX();
|
||||||
|
int y = ctrl.getY();
|
||||||
|
if(x < minX)
|
||||||
|
minX = x;
|
||||||
|
|
||||||
|
if(y < minY)
|
||||||
|
minY = y;
|
||||||
|
|
||||||
|
x += ctrl.getWidth();
|
||||||
|
y += ctrl.getHeight();
|
||||||
|
|
||||||
|
if(x > maxX)
|
||||||
|
maxX = x;
|
||||||
|
|
||||||
|
if(y >= maxY)
|
||||||
|
maxY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Bounds(minX, minY, maxX, maxY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
import com.mojang.blaze3d.vertex.Tesselator;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
import net.montoyo.wd.utilities.data.Bounds;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
|
public class ControlGroup extends Container {
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
private String label;
|
||||||
|
private int labelW;
|
||||||
|
private int labelColor = COLOR_WHITE;
|
||||||
|
private boolean labelShadowed = true;
|
||||||
|
|
||||||
|
public ControlGroup() {
|
||||||
|
width = 100;
|
||||||
|
height = 100;
|
||||||
|
label = "";
|
||||||
|
paddingX = 8;
|
||||||
|
paddingY = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControlGroup(int x, int y, int w, int h) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
paddingX = 8;
|
||||||
|
paddingY = 8;
|
||||||
|
label = "";
|
||||||
|
labelW = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControlGroup(int x, int y, int w, int h, String label) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
this.label = label;
|
||||||
|
this.labelW = font.width(label);
|
||||||
|
paddingX = 8;
|
||||||
|
paddingY = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(int w, int h) {
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
labelW = font.width(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLabelColor() {
|
||||||
|
return labelColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabelColor(int labelColor) {
|
||||||
|
this.labelColor = labelColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLabelShadowed() {
|
||||||
|
return labelShadowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabelShadowed(boolean labelShadowed) {
|
||||||
|
this.labelShadowed = labelShadowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
super.draw(poseStack, mouseX, mouseY, ptt);
|
||||||
|
|
||||||
|
if(visible) {
|
||||||
|
poseStack.pose().pushPose();
|
||||||
|
float[] sdrCol = Arrays.copyOf(RenderSystem.getShaderColor(), 4);
|
||||||
|
RenderSystem.setShaderColor(0.5f, 0.5f, 0.5f, 1.f);
|
||||||
|
// RenderSystem.disableTexture();
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
double x1 = x;
|
||||||
|
double y1 = y;
|
||||||
|
double x2 = (x + width);
|
||||||
|
double y2 = (y + height);
|
||||||
|
double bp = 4.0;
|
||||||
|
double lw = labelW;
|
||||||
|
|
||||||
|
x1 += bp;
|
||||||
|
y1 += bp;
|
||||||
|
x2 -= bp;
|
||||||
|
y2 -= bp;
|
||||||
|
lw += 12.0;
|
||||||
|
|
||||||
|
Matrix4f matrix = poseStack.pose().last().pose();
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||||
|
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
|
||||||
|
|
||||||
|
//Top edge (y = y1)
|
||||||
|
if(labelW == 0) {
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)(y1 + 1.0), 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)(y1 + 1.0), 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)y1, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)y1, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
} else {
|
||||||
|
//Left
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)(y1 + 1.0), 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)(x1 + 8.0), (float)(y1 + 1.0), 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)(x1 + 8.0), (float)y1, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)y1, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
|
||||||
|
//Right
|
||||||
|
buffer.addVertex(matrix, (float)(x1 + lw), (float)(y1 + 1.0), 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)(y1 + 1.0), 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)y1, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)(x1 + lw), (float)y1, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Bottom edge (y = y2)
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)y2, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)y2, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)(y2 - 1.0), 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)(y2 - 1.0), 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
|
||||||
|
//Left edge (x = x1)
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)y2, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)(x1 + 1.0), (float)y2, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)(x1 + 1.0), (float)y1, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x1, (float)y1, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
|
||||||
|
//Right edge (x = x2)
|
||||||
|
buffer.addVertex(matrix, (float)(x2 - 1.0), (float)y2, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)y2, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)x2, (float)y1, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
buffer.addVertex(matrix, (float)(x2 - 1.0), (float)y1, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
BufferUploader.drawWithShader(buffer.buildOrThrow());
|
||||||
|
|
||||||
|
RenderSystem.setShaderColor(sdrCol[0], sdrCol[1], sdrCol[2], sdrCol[3]);
|
||||||
|
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
// RenderSystem.enableTexture();
|
||||||
|
poseStack.pose().popPose();
|
||||||
|
|
||||||
|
if(labelW != 0)
|
||||||
|
poseStack.drawString(Minecraft.getInstance().font, label, x + 10 + ((int) bp), y, labelColor, labelShadowed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pack() {
|
||||||
|
Bounds bounds = findBounds(childs);
|
||||||
|
for(Control ctrl : childs)
|
||||||
|
ctrl.setPos(ctrl.getX() - bounds.minX, ctrl.getY() - bounds.minY);
|
||||||
|
|
||||||
|
width = bounds.getWidth() + paddingX * 2;
|
||||||
|
height = bounds.getHeight() + paddingY * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unfocus() {
|
||||||
|
for (Control control : childs) {
|
||||||
|
control.unfocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
width = json.getInt("width", 100);
|
||||||
|
height = json.getInt("height", 100);
|
||||||
|
label = tr(json.getString("label", ""));
|
||||||
|
labelW = font.width(label);
|
||||||
|
labelColor = json.getColor("labelColor", COLOR_WHITE);
|
||||||
|
labelShadowed = json.getBool("labelShadowed", true);
|
||||||
|
|
||||||
|
if(json.getBool("pack", false))
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
14
src/main/java/net/montoyo/wd/client/gui/controls/Event.java
Normal file
14
src/main/java/net/montoyo/wd/client/gui/controls/Event.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
public abstract class Event<T extends Control> {
|
||||||
|
|
||||||
|
protected T source;
|
||||||
|
|
||||||
|
public T getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
}
|
||||||
98
src/main/java/net/montoyo/wd/client/gui/controls/Icon.java
Normal file
98
src/main/java/net/montoyo/wd/client/gui/controls/Icon.java
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
import org.lwjgl.opengl.GL;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
public class Icon extends BasicControl {
|
||||||
|
|
||||||
|
protected int width;
|
||||||
|
protected int height;
|
||||||
|
protected double u1;
|
||||||
|
protected double v1;
|
||||||
|
protected double u2;
|
||||||
|
protected double v2;
|
||||||
|
protected ResourceLocation texture;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
|
||||||
|
width = json.getInt("width", 16);
|
||||||
|
height = json.getInt("height", 16);
|
||||||
|
u1 = json.getDouble("u1", 0.0);
|
||||||
|
v1 = json.getDouble("v1", 0.0);
|
||||||
|
u2 = json.getDouble("u2", 1.0);
|
||||||
|
v2 = json.getDouble("v2", 1.0);
|
||||||
|
texture = ResourceLocation.tryParse(json.getString("resourceLocation", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
if(texture != null) {
|
||||||
|
poseStack.pose().pushPose();
|
||||||
|
// RenderSystem.enableTexture();
|
||||||
|
RenderSystem.setShaderTexture(1, texture);
|
||||||
|
RenderSystem.bindTexture(1);
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
fillTexturedRect(poseStack.pose(), x, y, width, height, u1, v1, u2, v2);
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
RenderSystem.bindTexture(-1);
|
||||||
|
poseStack.pose().popPose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(int width) {
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(int height) {
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTextureCoordinates(double u1, double v1, double u2, double v2) {
|
||||||
|
this.u1 = u1;
|
||||||
|
this.v1 = v1;
|
||||||
|
this.u2 = u2;
|
||||||
|
this.v2 = v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTexture(ResourceLocation texture) {
|
||||||
|
this.texture = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getU1() {
|
||||||
|
return u1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getV1() {
|
||||||
|
return v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getU2() {
|
||||||
|
return u2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getV2() {
|
||||||
|
return v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
104
src/main/java/net/montoyo/wd/client/gui/controls/Label.java
Normal file
104
src/main/java/net/montoyo/wd/client/gui/controls/Label.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
|
||||||
|
public class Label extends BasicControl {
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
private int labelW;
|
||||||
|
private int color;
|
||||||
|
private boolean shadowed;
|
||||||
|
|
||||||
|
public Label() {
|
||||||
|
label = "";
|
||||||
|
color = COLOR_WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Label(int x, int y, String str) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
label = str;
|
||||||
|
labelW = font.width(str);
|
||||||
|
color = COLOR_WHITE;
|
||||||
|
shadowed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Label(int x, int y, String str, int color) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
label = str;
|
||||||
|
labelW = font.width(str);
|
||||||
|
this.color = color;
|
||||||
|
shadowed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Label(int x, int y, String str, int color, boolean shadowed) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
label = str;
|
||||||
|
labelW = font.width(str);
|
||||||
|
this.color = color;
|
||||||
|
this.shadowed = shadowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
labelW = font.width(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(int color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShadowed(boolean shadowed) {
|
||||||
|
this.shadowed = shadowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShadowed() {
|
||||||
|
return shadowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
if(visible)
|
||||||
|
poseStack.drawString(
|
||||||
|
Minecraft.getInstance().font,
|
||||||
|
label, x, y, color, shadowed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return labelW;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
label = tr(json.getString("label", ""));
|
||||||
|
labelW = font.width(label);
|
||||||
|
color = json.getColor("color", COLOR_WHITE);
|
||||||
|
shadowed = json.getBool("shadowed", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
421
src/main/java/net/montoyo/wd/client/gui/controls/List.java
Normal file
421
src/main/java/net/montoyo/wd/client/gui/controls/List.java
Normal file
@@ -0,0 +1,421 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderTarget;
|
||||||
|
import com.mojang.blaze3d.pipeline.TextureTarget;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
import org.lwjgl.opengl.GL;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL20;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
|
|
||||||
|
public class List extends BasicControl {
|
||||||
|
|
||||||
|
private static class Entry {
|
||||||
|
public final String text;
|
||||||
|
public final Object userdata;
|
||||||
|
|
||||||
|
public Entry(String t, Object o) {
|
||||||
|
text = t;
|
||||||
|
userdata = o;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EntryClick extends Event<List> {
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
private final Entry entry;
|
||||||
|
|
||||||
|
public EntryClick(List lst) {
|
||||||
|
source = lst;
|
||||||
|
id = lst.selected;
|
||||||
|
entry = lst.content.get(lst.selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return entry.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getUserdata() {
|
||||||
|
return entry.userdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
private final ArrayList<Entry> content = new ArrayList<>();
|
||||||
|
private RenderTarget fbo;
|
||||||
|
private int selected = -1;
|
||||||
|
private boolean update;
|
||||||
|
private int selColor = 0xFF0080FF;
|
||||||
|
|
||||||
|
//Scroll handling
|
||||||
|
private int contentH = 0;
|
||||||
|
private int scrollSize;
|
||||||
|
private double scrollPos = 0;
|
||||||
|
private boolean scrolling = false;
|
||||||
|
private double scrollGrab;
|
||||||
|
|
||||||
|
public List() {
|
||||||
|
content.add(new Entry("", null));
|
||||||
|
selected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List(int x, int y, int w, int h) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
scrollSize = h - 2;
|
||||||
|
createFBO();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getYOffset() {
|
||||||
|
double amount = ((double) scrollPos) / ((double) (height - 2 - scrollSize)) * ((double) (contentH - height));
|
||||||
|
return (int) amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInScrollbar(double mouseX, double mouseY) {
|
||||||
|
return mouseX >= x + width - 5 && mouseX <= x + width - 1 && mouseY >= y + 1 + scrollPos && mouseY <= y + 1 + scrollPos + scrollSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createFBO() {
|
||||||
|
if(fbo != null)
|
||||||
|
fbo.destroyBuffers();
|
||||||
|
|
||||||
|
fbo = new TextureTarget(parent.screen2DisplayX(width), parent.screen2DisplayY(height), true, Minecraft.ON_OSX);
|
||||||
|
fbo.setFilterMode(GL_NEAREST);
|
||||||
|
fbo.bindWrite(true);
|
||||||
|
RenderSystem.clearColor(0.0f, 0.0f, 0.0f, 1.f); //Set alpha to 1
|
||||||
|
RenderSystem.clearDepth(GL_COLOR_BUFFER_BIT);
|
||||||
|
fbo.unbindWrite();
|
||||||
|
mc.getMainRenderTarget().bindWrite(true);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderToFBO(MultiBufferSource.BufferSource source) {
|
||||||
|
GuiGraphics graphics = beginFramebuffer(fbo, width, height);
|
||||||
|
GL11.glColorMask(true, true, true, true);
|
||||||
|
RenderSystem.applyModelViewMatrix();
|
||||||
|
graphics.fill(0, 0, width, height, COLOR_BLACK);
|
||||||
|
RenderSystem.setShaderColor(1.f, 1.f, 1.f, 1.f);
|
||||||
|
|
||||||
|
int offset = 4 - getYOffset();
|
||||||
|
for(int i = 0; i < content.size(); i++) {
|
||||||
|
int pos = i * 12 + offset;
|
||||||
|
|
||||||
|
if(pos + 12 >= 1) {
|
||||||
|
if(pos >= height - 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int color = (i == selected) ? selColor : COLOR_WHITE;
|
||||||
|
graphics.drawString(font, content.get(i).text, 4, i * 12 + offset, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
graphics.renderOutline(0, 0, width, height, 0xFF808080);
|
||||||
|
graphics.flush();
|
||||||
|
endFramebuffer(graphics, fbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
if(fbo != null)
|
||||||
|
fbo.destroyBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(int w, int h) {
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
createFBO();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(int width) {
|
||||||
|
this.width = width;
|
||||||
|
createFBO();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(int height) {
|
||||||
|
this.height = height;
|
||||||
|
createFBO();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateContent() {
|
||||||
|
contentH = content.size() * 12 + 4;
|
||||||
|
|
||||||
|
int h2 = height - 2;
|
||||||
|
if(contentH <= h2) {
|
||||||
|
scrollSize = h2;
|
||||||
|
scrollPos = 0;
|
||||||
|
} else {
|
||||||
|
scrollSize = h2 * h2 / contentH;
|
||||||
|
|
||||||
|
if(scrollSize < 4)
|
||||||
|
scrollSize = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int addElement(String str) {
|
||||||
|
return addElement(str, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int addElement(String str, Object ud) {
|
||||||
|
content.add(new Entry(str, ud));
|
||||||
|
updateContent();
|
||||||
|
return content.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int addElementRaw(String str) {
|
||||||
|
return addElement(str, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int addElementRaw(String str, Object ud) {
|
||||||
|
content.add(new Entry(str, ud));
|
||||||
|
return content.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDisabled(boolean dis) {
|
||||||
|
disabled = dis;
|
||||||
|
|
||||||
|
if(dis) {
|
||||||
|
selected = -1;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disable() {
|
||||||
|
disabled = true;
|
||||||
|
selected = -1;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseMove(double mouseX, double mouseY) {
|
||||||
|
int sel = -1;
|
||||||
|
if(!disabled && mouseX >= x + 1 && mouseX <= x + width - 6 && mouseY >= y + 2 && mouseY <= y + height - 2) {
|
||||||
|
int offset = y + 4 - getYOffset();
|
||||||
|
sel = (int) ((mouseY - offset) / 12);
|
||||||
|
|
||||||
|
if(sel < 0 || sel >= content.size())
|
||||||
|
sel = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selected != sel) {
|
||||||
|
selected = sel;
|
||||||
|
update = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
|
||||||
|
if(!disabled && mouseButton == 0) {
|
||||||
|
if(isInScrollbar(mouseX, mouseY)) {
|
||||||
|
scrolling = true;
|
||||||
|
scrollGrab = mouseY - (y + 1 + scrollPos);
|
||||||
|
return true;
|
||||||
|
} else if(selected >= 0) {
|
||||||
|
System.out.println(parent.actionPerformed(new EntryClick(this)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int state) {
|
||||||
|
if(!disabled && scrolling) {
|
||||||
|
scrolling = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseScroll(double mouseX, double mouseY, double amount) {
|
||||||
|
if(!disabled && !scrolling && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height) {
|
||||||
|
double disp = 12.d * ((double) (height - 2 - scrollSize)) / ((double) (contentH - height));
|
||||||
|
double sp = scrollPos;
|
||||||
|
|
||||||
|
if(amount < 0)
|
||||||
|
sp += (int) disp;
|
||||||
|
else
|
||||||
|
sp -= (int) disp;
|
||||||
|
|
||||||
|
if(sp < 0)
|
||||||
|
sp = 0;
|
||||||
|
else if(sp > height - 2 - scrollSize)
|
||||||
|
sp = height - 2 - scrollSize;
|
||||||
|
|
||||||
|
if(sp != scrollPos) {
|
||||||
|
scrollPos = sp;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClickMove(double mouseX, double mouseY, int button, double dragX, double dragY) {
|
||||||
|
if(!disabled && scrolling) {
|
||||||
|
double sp = mouseY - scrollGrab - y - 1;
|
||||||
|
if(sp < 0)
|
||||||
|
sp = 0;
|
||||||
|
else if(sp > height - 2 - scrollSize)
|
||||||
|
sp = height - 2 - scrollSize;
|
||||||
|
|
||||||
|
if(scrollPos != sp) {
|
||||||
|
scrollPos = sp;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(GuiGraphics graphics, int mouseX, int mouseY, float ptt) {
|
||||||
|
if(visible) {
|
||||||
|
if(update) {
|
||||||
|
renderToFBO(graphics.bufferSource());
|
||||||
|
update = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSystem.setShaderTexture(0, fbo.getColorTextureId());
|
||||||
|
RenderSystem.setShaderColor(1.f, 1.f, 1.f, 1.f);
|
||||||
|
fillTexturedRect(graphics.pose(), x, y, width, height, 0.0, 1.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
fillRect(graphics.bufferSource(), x + width - 5, y + 1 + scrollPos, 4, scrollSize, (scrolling || isInScrollbar(mouseX, mouseY)) ? 0xFF202020 : 0xFF404040);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEntryLabel(int id) {
|
||||||
|
return content.get(id).text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getEntryUserdata(int id) {
|
||||||
|
return content.get(id).userdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int findEntryByLabel(String label) {
|
||||||
|
for(int i = 0; i < content.size(); i++) {
|
||||||
|
if(content.get(i).text.equals(label))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int findEntryByUserdata(Object o) {
|
||||||
|
if(o == null) {
|
||||||
|
for(int i = 0; i < content.size(); i++) {
|
||||||
|
if(content.get(i).userdata == null)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < content.size(); i++) {
|
||||||
|
if(content.get(i).userdata != null && content.get(i).userdata.equals(o))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectionColor(int selColor) {
|
||||||
|
this.selColor = selColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSelectionColor() {
|
||||||
|
return selColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getElementCount() {
|
||||||
|
return content.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeElement(int id) {
|
||||||
|
if(selected != -1 && id == content.size() - 1)
|
||||||
|
selected = -1;
|
||||||
|
|
||||||
|
content.remove(id);
|
||||||
|
updateContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeElementRaw(int id) {
|
||||||
|
if(selected != -1 && id == content.size() - 1)
|
||||||
|
selected = -1;
|
||||||
|
|
||||||
|
content.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
content.clear();
|
||||||
|
scrollPos = 0;
|
||||||
|
scrolling = false;
|
||||||
|
scrollSize = height - 2;
|
||||||
|
selected = -1;
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearRaw() {
|
||||||
|
content.clear();
|
||||||
|
scrollPos = 0;
|
||||||
|
scrolling = false;
|
||||||
|
selected = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
width = json.getInt("width", 100);
|
||||||
|
height = json.getInt("height", 100);
|
||||||
|
selColor = json.getColor("selectionColor", 0xFF0080FF);
|
||||||
|
createFBO();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
373
src/main/java/net/montoyo/wd/client/gui/controls/TextField.java
Normal file
373
src/main/java/net/montoyo/wd/client/gui/controls/TextField.java
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.gui.components.EditBox;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
import org.cef.browser.CefBrowserOsr;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static java.awt.event.KeyEvent.VK_ENTER;
|
||||||
|
import static org.lwjgl.glfw.GLFW.*;
|
||||||
|
|
||||||
|
public class TextField extends Control {
|
||||||
|
|
||||||
|
public static class EnterPressedEvent extends Event<TextField> {
|
||||||
|
|
||||||
|
private final String text;
|
||||||
|
|
||||||
|
public EnterPressedEvent(TextField field) {
|
||||||
|
source = field;
|
||||||
|
text = field.field.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TabPressedEvent extends Event<TextField> {
|
||||||
|
|
||||||
|
private final String beginning;
|
||||||
|
|
||||||
|
public TabPressedEvent(TextField field) {
|
||||||
|
source = field;
|
||||||
|
|
||||||
|
String text = field.field.getValue();
|
||||||
|
int max = field.field.getCursorPosition();
|
||||||
|
int spacePos = 0;
|
||||||
|
|
||||||
|
for(int i = max - 1; i >= 0; i--) {
|
||||||
|
if(Character.isSpaceChar(text.charAt(i))) {
|
||||||
|
spacePos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
beginning = text.substring(spacePos, max).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBeginning() {
|
||||||
|
return beginning;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TextChangedEvent extends Event<TextField> {
|
||||||
|
|
||||||
|
private final String oldContent;
|
||||||
|
private final String newContent;
|
||||||
|
|
||||||
|
public TextChangedEvent(TextField tf, String old) {
|
||||||
|
source = tf;
|
||||||
|
oldContent = old;
|
||||||
|
newContent = tf.field.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOldContent() {
|
||||||
|
return oldContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNewContent() {
|
||||||
|
return newContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TextChangeListener {
|
||||||
|
|
||||||
|
void onTextChange(TextField tf, String oldContent, String newContent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int DEFAULT_TEXT_COLOR = 14737632;
|
||||||
|
public static final int DEFAULT_DISABLED_COLOR = 7368816;
|
||||||
|
|
||||||
|
private final EditBox field;
|
||||||
|
private boolean enabled = true;
|
||||||
|
private int textColor = DEFAULT_TEXT_COLOR;
|
||||||
|
private int disabledColor = DEFAULT_DISABLED_COLOR;
|
||||||
|
private final ArrayList<TextChangeListener> listeners = new ArrayList<>();
|
||||||
|
|
||||||
|
public TextField() {
|
||||||
|
field = new EditBox(font, 1, 1, 198, 20, Component.nullToEmpty(""));
|
||||||
|
setFocused(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextField(int x, int y, int width, int height) {
|
||||||
|
field = new EditBox(font, x + 1, y + 1, width - 2, height - 2, Component.nullToEmpty(""));
|
||||||
|
setFocused(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextField(int x, int y, int width, int height, String text) {
|
||||||
|
field = new EditBox(font, x + 1, y + 1, width - 2, height - 2, Component.nullToEmpty(""));
|
||||||
|
field.setValue(text);
|
||||||
|
setFocused(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make this public static in CefBrowserOSR
|
||||||
|
private long mapScanCode(int key, char c) {
|
||||||
|
if (key == GLFW_KEY_LEFT_CONTROL || key == GLFW_KEY_RIGHT_CONTROL) return 29;
|
||||||
|
return switch (key) {
|
||||||
|
case GLFW_KEY_DELETE -> 83;
|
||||||
|
case GLFW_KEY_LEFT -> 75;
|
||||||
|
case GLFW_KEY_DOWN -> 80;
|
||||||
|
case GLFW_KEY_UP -> 72;
|
||||||
|
case GLFW_KEY_RIGHT -> 77;
|
||||||
|
case GLFW_KEY_PAGE_DOWN -> 81;
|
||||||
|
case GLFW_KEY_PAGE_UP -> 73;
|
||||||
|
case GLFW_KEY_END -> 79;
|
||||||
|
case GLFW_KEY_HOME -> 71;
|
||||||
|
case VK_ENTER, GLFW_KEY_ENTER, GLFW_KEY_KP_ENTER -> 28;
|
||||||
|
default -> GLFW.glfwGetKeyScancode(key);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyDown(int key, int scanCode, int modifiers) {
|
||||||
|
return field.keyPressed(key, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyUp(int key, int scanCode, int modifiers) {
|
||||||
|
return field.keyReleased(key, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyTyped(int keyCode, int modifier) {
|
||||||
|
if(keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER)
|
||||||
|
parent.actionPerformed(new EnterPressedEvent(this));
|
||||||
|
else if(keyCode == GLFW.GLFW_KEY_TAB)
|
||||||
|
parent.actionPerformed(new TabPressedEvent(this));
|
||||||
|
else {
|
||||||
|
String old;
|
||||||
|
if(enabled && field.isFocused())
|
||||||
|
old = field.getValue();
|
||||||
|
else
|
||||||
|
old = null;
|
||||||
|
|
||||||
|
if(enabled && field.isFocused() && !field.getValue().equals(old)) {
|
||||||
|
for(TextChangeListener tcl : listeners)
|
||||||
|
tcl.onTextChange(this, old, field.getValue());
|
||||||
|
|
||||||
|
parent.actionPerformed(new TextChangedEvent(this, old));
|
||||||
|
}
|
||||||
|
|
||||||
|
return field.charTyped((char) keyCode, modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
|
||||||
|
if (field.mouseClicked(mouseX, mouseY, mouseButton)) {
|
||||||
|
setFocused(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unfocus() {
|
||||||
|
setFocused(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int state) {
|
||||||
|
return field.mouseReleased(mouseX, mouseY, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClickMove(double mouseX, double mouseY, int button, double dragX, double dragY) {
|
||||||
|
return field.mouseClicked(mouseX, mouseY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseMove(double mouseX, double mouseY) {
|
||||||
|
field.mouseMoved(mouseX, mouseY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseScroll(double mouseX, double mouseY, double amount) {
|
||||||
|
return field.mouseScrolled(mouseX, mouseY, 0.0, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
field.render(poseStack, mouseX, mouseY, ptt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setText(String text) {
|
||||||
|
String old = field.getValue();
|
||||||
|
field.setValue(text);
|
||||||
|
|
||||||
|
if(!old.equals(text)) {
|
||||||
|
for(TextChangeListener tcl : listeners)
|
||||||
|
tcl.onTextChange(this, old, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
field.setValue("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return field.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSelectedText() {
|
||||||
|
return field.getHighlighted();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(int width) {
|
||||||
|
field.setWidth(width - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return field.getWidth() + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(int height) {
|
||||||
|
field.setHeight(height - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return field.getHeight() + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(int w, int h) {
|
||||||
|
field.setWidth(w - 2);
|
||||||
|
field.setHeight(h - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPos(int x, int y) {
|
||||||
|
field.setPosition(
|
||||||
|
x + 1,
|
||||||
|
y + 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return field.getX() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getY() {
|
||||||
|
return field.getY() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisabled(boolean en) {
|
||||||
|
enabled = !en;
|
||||||
|
if (!en)
|
||||||
|
field.setFocused(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDisabled() {
|
||||||
|
return !enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enable() {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable() {
|
||||||
|
field.setFocused(false);
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(boolean vi) {
|
||||||
|
field.setVisible(vi);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return field.isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
field.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hide() {
|
||||||
|
field.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFocused(boolean val) {
|
||||||
|
field.setFocused(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasFocus() {
|
||||||
|
return field.isFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void focus() {
|
||||||
|
field.setFocused(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTextColor(int color) {
|
||||||
|
field.setTextColor(color);
|
||||||
|
textColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTextColor() {
|
||||||
|
return textColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisabledTextColor(int color) {
|
||||||
|
field.setTextColorUneditable(color);
|
||||||
|
disabledColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDisabledTextColor() {
|
||||||
|
return disabledColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EditBox getMcField() {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTextChangeListener(TextChangeListener l) {
|
||||||
|
if(l != null && !listeners.contains(l))
|
||||||
|
listeners.add(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeTextChangeListener(TextChangeListener l) {
|
||||||
|
listeners.remove(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
field.setPosition(
|
||||||
|
json.getInt("x", 0) + 1,
|
||||||
|
json.getInt("y", 0) + 1
|
||||||
|
);
|
||||||
|
field.setWidth(json.getInt("width", 200) - 2);
|
||||||
|
field.setHeight(json.getInt("height", 22) - 2);
|
||||||
|
field.setValue(tr(json.getString("text", "")));
|
||||||
|
field.setVisible(json.getBool("visible", true));
|
||||||
|
field.setMaxLength(json.getInt("maxLength", 32));
|
||||||
|
|
||||||
|
enabled = !json.getBool("disabled", false);
|
||||||
|
textColor = json.getColor("textColor", DEFAULT_TEXT_COLOR);
|
||||||
|
disabledColor = json.getColor("disabledColor", DEFAULT_DISABLED_COLOR);
|
||||||
|
|
||||||
|
field.setTextColor(textColor);
|
||||||
|
field.setTextColorUneditable(disabledColor);
|
||||||
|
setFocused(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class UpgradeGroup extends BasicControl {
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
private ArrayList<ItemStack> upgrades;
|
||||||
|
private ItemStack overStack;
|
||||||
|
private ItemStack clickStack;
|
||||||
|
private final ItemRenderer renderItem = Minecraft.getInstance().getItemRenderer();
|
||||||
|
|
||||||
|
public UpgradeGroup() {
|
||||||
|
parent.requirePostDraw(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
if(upgrades != null) {
|
||||||
|
int x = this.x;
|
||||||
|
|
||||||
|
for(ItemStack is: upgrades) {
|
||||||
|
if(is == overStack && !disabled)
|
||||||
|
fillRect(poseStack.bufferSource(), x, y, 16, 16, 0x80FF0000);
|
||||||
|
|
||||||
|
poseStack.renderItem(is, x, y);
|
||||||
|
poseStack.renderItemDecorations(font, is, x, y);
|
||||||
|
x += 18;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postDraw(GuiGraphics poseStack, int mouseX, int mouseY, float ptt) {
|
||||||
|
if(overStack != null)
|
||||||
|
parent.drawItemStackTooltip(poseStack, overStack, mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(int w) {
|
||||||
|
width = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(int h) {
|
||||||
|
height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpgrades(ArrayList<ItemStack> upgrades) {
|
||||||
|
this.upgrades = upgrades;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<ItemStack> getUpgrades() {
|
||||||
|
return upgrades;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
width = json.getInt("width", 0);
|
||||||
|
height = json.getInt("height", 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseMove(double mouseX, double mouseY) {
|
||||||
|
if(upgrades != null) {
|
||||||
|
overStack = null;
|
||||||
|
|
||||||
|
if(mouseY >= y && mouseY <= y + 16 && mouseX >= x) {
|
||||||
|
mouseX -= x;
|
||||||
|
int sel = (int) (mouseX / 18);
|
||||||
|
|
||||||
|
if(sel < upgrades.size() && mouseX % 18 <= 16)
|
||||||
|
overStack = upgrades.get(sel);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
|
||||||
|
if(mouseButton == 0) {
|
||||||
|
// don't process the click if it's not inbounds, lol
|
||||||
|
if (
|
||||||
|
mouseX >= x && mouseX <= x + width &&
|
||||||
|
mouseY >= y && mouseX <= y + height
|
||||||
|
) {
|
||||||
|
clickStack = overStack;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int state) {
|
||||||
|
if(state == 0 && clickStack != null) {
|
||||||
|
if(clickStack == overStack && !disabled && upgrades.contains(clickStack)) //HOTFIX: Make sure it's actually in the list :p
|
||||||
|
parent.actionPerformed(new ClickEvent(this));
|
||||||
|
|
||||||
|
clickStack = null;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack getMouseOverUpgrade() {
|
||||||
|
return overStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ClickEvent extends Event<UpgradeGroup> {
|
||||||
|
|
||||||
|
private final ItemStack clickStack;
|
||||||
|
|
||||||
|
public ClickEvent(UpgradeGroup src) {
|
||||||
|
source = src;
|
||||||
|
clickStack = src.clickStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack getMouseOverStack() {
|
||||||
|
return clickStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.controls;
|
||||||
|
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
|
||||||
|
import net.montoyo.wd.utilities.serialization.Util;
|
||||||
|
import net.montoyo.wd.utilities.VideoType;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class YTButton extends Button implements TextField.TextChangeListener {
|
||||||
|
|
||||||
|
private TextField urlField;
|
||||||
|
|
||||||
|
public YTButton() {
|
||||||
|
btn.setMessage(Component.nullToEmpty("YT"));
|
||||||
|
btn.active = false;
|
||||||
|
shiftColor = 0xFFFF6464;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onClick() {
|
||||||
|
if(urlField != null) {
|
||||||
|
String urlStr = Util.addProtocol(urlField.getText());
|
||||||
|
URL url;
|
||||||
|
|
||||||
|
try {
|
||||||
|
url = new URL(urlStr);
|
||||||
|
} catch(MalformedURLException ex) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoType vt = VideoType.getTypeFromURL(url);
|
||||||
|
if(vt == VideoType.YOUTUBE)
|
||||||
|
urlField.setText(VideoType.YOUTUBE_EMBED.getURLFromID(vt.getVideoIDFromURL(url), shiftDown));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setURLField(TextField tf) {
|
||||||
|
if(urlField != null)
|
||||||
|
tf.removeTextChangeListener(this);
|
||||||
|
|
||||||
|
urlField = tf;
|
||||||
|
|
||||||
|
if(urlField != null)
|
||||||
|
tf.addTextChangeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextField getURLField() {
|
||||||
|
return urlField;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(JsonOWrapper json) {
|
||||||
|
super.load(json);
|
||||||
|
|
||||||
|
String tfName = json.getString("urlField", null);
|
||||||
|
if(tfName != null) {
|
||||||
|
Control ctrl = parent.getControlByName(tfName);
|
||||||
|
|
||||||
|
if(ctrl != null && ctrl instanceof TextField) {
|
||||||
|
urlField = (TextField) ctrl;
|
||||||
|
urlField.addTextChangeListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChange(TextField tf, String oldContent, String newContent) {
|
||||||
|
btn.active = (VideoType.getTypeFromURL(Util.addProtocol(newContent)) == VideoType.YOUTUBE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.loading;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface FillControl {
|
||||||
|
|
||||||
|
String name() default "";
|
||||||
|
boolean required() default true;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.loading;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.packs.resources.Resource;
|
||||||
|
import net.montoyo.wd.client.gui.controls.*;
|
||||||
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class GuiLoader {
|
||||||
|
|
||||||
|
private static final HashMap<String, Class<? extends Control>> CONTROLS = new HashMap<>();
|
||||||
|
private static final HashMap<ResourceLocation, JsonObject> RESOURCES = new HashMap<>();
|
||||||
|
|
||||||
|
public static void register(Class<? extends Control> cls) {
|
||||||
|
if(Modifier.isAbstract(cls.getModifiers()))
|
||||||
|
throw new RuntimeException("GG retard, you just registered an abstract class...");
|
||||||
|
|
||||||
|
String name = cls.getSimpleName();
|
||||||
|
if(CONTROLS.containsKey(name))
|
||||||
|
throw new RuntimeException("Control class already registered or name taken!");
|
||||||
|
|
||||||
|
CONTROLS.put(name, cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
register(Button.class);
|
||||||
|
register(CheckBox.class);
|
||||||
|
register(ControlGroup.class);
|
||||||
|
register(Label.class);
|
||||||
|
register(List.class);
|
||||||
|
register(TextField.class);
|
||||||
|
register(Icon.class);
|
||||||
|
register(UpgradeGroup.class);
|
||||||
|
register(YTButton.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Control create(JsonOWrapper json) {
|
||||||
|
Control ret;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ret = CONTROLS.get(json.getString("type", null)).newInstance();
|
||||||
|
} catch(InstantiationException e) {
|
||||||
|
Log.errorEx("Could not create control from JSON: instantiation exception", e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch(IllegalAccessException e) {
|
||||||
|
Log.errorEx("Could not create control from JSON: access denied", e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.load(json);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonObject getJson(ResourceLocation resLoc) throws IOException {
|
||||||
|
JsonObject ret = RESOURCES.get(resLoc);
|
||||||
|
if(ret == null) {
|
||||||
|
Resource resource;
|
||||||
|
|
||||||
|
resource = Minecraft.getInstance().getResourceManager().getResource(resLoc).get();
|
||||||
|
|
||||||
|
JsonParser parser = new JsonParser();
|
||||||
|
ret = parser.parse(new InputStreamReader(resource.open())).getAsJsonObject();
|
||||||
|
|
||||||
|
RESOURCES.put(resLoc, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearCache() {
|
||||||
|
RESOURCES.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.loading;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class JsonAWrapper {
|
||||||
|
|
||||||
|
private final JsonArray array;
|
||||||
|
private final Map<String, Double> variables;
|
||||||
|
|
||||||
|
public JsonAWrapper(JsonArray a, Map<String, Double> vars) {
|
||||||
|
array = a;
|
||||||
|
variables = vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return array.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(int i) {
|
||||||
|
return array.get(i).getAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInt(int i) {
|
||||||
|
return array.get(i).getAsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLong(int i) {
|
||||||
|
return array.get(i).getAsLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFloat(int i) {
|
||||||
|
return array.get(i).getAsFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDouble(int i) {
|
||||||
|
return array.get(i).getAsDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getBool(int i) {
|
||||||
|
return array.get(i).getAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonOWrapper getObject(int i) {
|
||||||
|
return new JsonOWrapper(array.get(i).getAsJsonObject(), variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonAWrapper getArray(int i) {
|
||||||
|
return new JsonAWrapper(array.get(i).getAsJsonArray(), variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonArray getArray() {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,311 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.gui.loading;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import net.montoyo.wd.client.gui.controls.Control;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class JsonOWrapper {
|
||||||
|
|
||||||
|
private static final HashMap<String, Integer> defaultColors = new HashMap<>();
|
||||||
|
static {
|
||||||
|
defaultColors.put("black", Control.COLOR_BLACK);
|
||||||
|
defaultColors.put("white", Control.COLOR_WHITE);
|
||||||
|
defaultColors.put("red", Control.COLOR_RED);
|
||||||
|
defaultColors.put("green", Control.COLOR_GREEN);
|
||||||
|
defaultColors.put("blue", Control.COLOR_BLUE);
|
||||||
|
defaultColors.put("magenta", Control.COLOR_MANGENTA);
|
||||||
|
defaultColors.put("cyan", Control.COLOR_CYAN);
|
||||||
|
defaultColors.put("yellow", Control.COLOR_YELLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final JsonObject object;
|
||||||
|
private final Map<String, Double> variables;
|
||||||
|
|
||||||
|
public JsonOWrapper(JsonObject obj, Map<String, Double> vars) {
|
||||||
|
object = obj;
|
||||||
|
variables = vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(String key, String def) {
|
||||||
|
return object.has(key) ? object.get(key).getAsString() : def;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLong(String key, long def) {
|
||||||
|
return object.has(key) ? object.get(key).getAsLong() : def;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInt(String key, int def) {
|
||||||
|
if(!object.has(key))
|
||||||
|
return def;
|
||||||
|
|
||||||
|
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
|
||||||
|
if(prim.isNumber())
|
||||||
|
return prim.getAsInt();
|
||||||
|
|
||||||
|
return (int) evalExpr(prim.getAsString(), variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFloat(String key, float def) {
|
||||||
|
if(!object.has(key))
|
||||||
|
return def;
|
||||||
|
|
||||||
|
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
|
||||||
|
if(prim.isNumber())
|
||||||
|
return prim.getAsFloat();
|
||||||
|
|
||||||
|
return (float) evalExpr(prim.getAsString(), variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDouble(String key, double def) {
|
||||||
|
if(!object.has(key))
|
||||||
|
return def;
|
||||||
|
|
||||||
|
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
|
||||||
|
if(prim.isNumber())
|
||||||
|
return prim.getAsDouble();
|
||||||
|
|
||||||
|
return evalExpr(prim.getAsString(), variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getBool(String key, boolean def) {
|
||||||
|
if(!object.has(key))
|
||||||
|
return def;
|
||||||
|
|
||||||
|
JsonPrimitive prim = object.get(key).getAsJsonPrimitive();
|
||||||
|
if(prim.isBoolean())
|
||||||
|
return prim.getAsBoolean();
|
||||||
|
else if(prim.isNumber())
|
||||||
|
return prim.getAsInt() != 0;
|
||||||
|
|
||||||
|
return evalExpr(prim.getAsString(), variables) != 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonOWrapper getObject(String key) {
|
||||||
|
return new JsonOWrapper(object.has(key) ? object.get(key).getAsJsonObject() : (new JsonObject()), variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonAWrapper getArray(String key) {
|
||||||
|
return new JsonAWrapper(object.has(key) ? object.get(key).getAsJsonArray() : (new JsonArray()), variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonObject getObject() {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor(String key, int def) {
|
||||||
|
if(!object.has(key))
|
||||||
|
return def;
|
||||||
|
|
||||||
|
JsonElement c = object.get(key);
|
||||||
|
if(c.isJsonPrimitive()) {
|
||||||
|
JsonPrimitive prim = c.getAsJsonPrimitive();
|
||||||
|
|
||||||
|
if(prim.isNumber())
|
||||||
|
return (int) prim.getAsLong();
|
||||||
|
else if(prim.isString()) {
|
||||||
|
String str = prim.getAsString();
|
||||||
|
Integer dc = defaultColors.get(str.toLowerCase());
|
||||||
|
if(dc != null)
|
||||||
|
return dc;
|
||||||
|
|
||||||
|
if(!str.isEmpty() && str.charAt(0) == '#')
|
||||||
|
str = str.substring(1);
|
||||||
|
|
||||||
|
long ret = Long.parseLong(str, 16);
|
||||||
|
if(str.length() <= 6)
|
||||||
|
ret |= 0xFF000000L;
|
||||||
|
|
||||||
|
return (int) ret;
|
||||||
|
} else
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r, g, b, a;
|
||||||
|
if(c.isJsonArray()) {
|
||||||
|
JsonArray array = c.getAsJsonArray();
|
||||||
|
|
||||||
|
r = array.get(0).getAsInt();
|
||||||
|
g = array.get(1).getAsInt();
|
||||||
|
b = array.get(2).getAsInt();
|
||||||
|
a = (array.size() >= 4) ? array.get(3).getAsInt() : 255;
|
||||||
|
} else if(c.isJsonObject()) {
|
||||||
|
JsonObject obj = c.getAsJsonObject();
|
||||||
|
|
||||||
|
r = obj.get("r").getAsInt();
|
||||||
|
g = obj.get("g").getAsInt();
|
||||||
|
b = obj.get("b").getAsInt();
|
||||||
|
a = obj.has("a") ? obj.get("a").getAsInt() : 255;
|
||||||
|
} else
|
||||||
|
return def;
|
||||||
|
|
||||||
|
return (a << 24) | (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String OPS = "+*/%&|"; //The - sign is an exception, don't add it here
|
||||||
|
private static final String[] OPS_PRIORITY = new String[] { "*/%", "+-", "&|" };
|
||||||
|
|
||||||
|
private static class VarOpPair {
|
||||||
|
double var;
|
||||||
|
char op;
|
||||||
|
|
||||||
|
void setVar(String str, boolean isNumber, String expr, Map<String, Double> variables) {
|
||||||
|
if(isNumber)
|
||||||
|
var = Double.parseDouble(str);
|
||||||
|
else {
|
||||||
|
boolean neg = (str.charAt(0) == '-');
|
||||||
|
String varName = neg ? str.substring(1) : str;
|
||||||
|
Double d = variables.get(varName);
|
||||||
|
|
||||||
|
if(d == null)
|
||||||
|
throw new RuntimeException("Unknown variable \"" + varName + "\" in expression \"" + expr + "\"");
|
||||||
|
|
||||||
|
var = neg ? -d : d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOp(char op) {
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int findPair(List<VarOpPair> list, String ops) {
|
||||||
|
for(int i = 0; i < list.size(); i++) {
|
||||||
|
if(ops.indexOf(list.get(i).op) >= 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double evalExpr(String expr, Map<String, Double> variables) {
|
||||||
|
//Apply parenthesis
|
||||||
|
while(true) {
|
||||||
|
int pos = expr.indexOf('(');
|
||||||
|
if(pos < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int end = ++pos;
|
||||||
|
int lvl = 0;
|
||||||
|
|
||||||
|
for(; end < expr.length(); end++) {
|
||||||
|
char chr = expr.charAt(end);
|
||||||
|
|
||||||
|
if(chr == '(')
|
||||||
|
lvl++;
|
||||||
|
else if(chr == ')') {
|
||||||
|
if(lvl == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
lvl--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(end >= expr.length())
|
||||||
|
throw new RuntimeException("Unclosed parenthesis in expression \"" + expr + "\"");
|
||||||
|
|
||||||
|
double val = evalExpr(expr.substring(pos, end), variables);
|
||||||
|
expr = expr.substring(0, pos - 1) + val + expr.substring(end + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Parse into ops
|
||||||
|
ArrayList<VarOpPair> ops = new ArrayList<>();
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
boolean negIsPartOfStr = true;
|
||||||
|
boolean strIsNumber = true;
|
||||||
|
|
||||||
|
for(int i = 0; i < expr.length(); i++) {
|
||||||
|
char chr = expr.charAt(i);
|
||||||
|
if(Character.isSpaceChar(chr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if((chr == '-' && !negIsPartOfStr) || OPS.indexOf(chr) >= 0) {
|
||||||
|
//Parse
|
||||||
|
VarOpPair pair = new VarOpPair();
|
||||||
|
pair.setVar(str.toString(), strIsNumber, expr, variables);
|
||||||
|
pair.setOp(chr);
|
||||||
|
ops.add(pair);
|
||||||
|
|
||||||
|
//Reset
|
||||||
|
str.setLength(0);
|
||||||
|
negIsPartOfStr = true;
|
||||||
|
strIsNumber = true;
|
||||||
|
} else {
|
||||||
|
if(strIsNumber && chr != '-' && chr != '.' && !Character.isDigit(chr))
|
||||||
|
strIsNumber = false;
|
||||||
|
|
||||||
|
if(negIsPartOfStr)
|
||||||
|
negIsPartOfStr = false;
|
||||||
|
|
||||||
|
str.append(chr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(str.length() > 0) {
|
||||||
|
VarOpPair pair = new VarOpPair();
|
||||||
|
pair.setVar(str.toString(), strIsNumber, expr, variables);
|
||||||
|
pair.setOp((char) 0);
|
||||||
|
ops.add(pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Compute
|
||||||
|
while(true) {
|
||||||
|
int pairId = -1;
|
||||||
|
for(String opList : OPS_PRIORITY) {
|
||||||
|
pairId = findPair(ops, opList);
|
||||||
|
|
||||||
|
if(pairId >= 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pairId < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
VarOpPair a = ops.get(pairId);
|
||||||
|
VarOpPair b = ops.get(pairId + 1);
|
||||||
|
|
||||||
|
if(a.op == '*')
|
||||||
|
b.var = a.var * b.var;
|
||||||
|
else if(a.op == '/')
|
||||||
|
b.var = a.var / b.var;
|
||||||
|
else if(a.op == '%')
|
||||||
|
b.var = a.var % b.var;
|
||||||
|
else if(a.op == '+')
|
||||||
|
b.var = a.var + b.var;
|
||||||
|
else if(a.op == '-')
|
||||||
|
b.var = a.var - b.var;
|
||||||
|
else if(a.op == '&') {
|
||||||
|
if(a.var == 0.0)
|
||||||
|
b.var = 0.0;
|
||||||
|
|
||||||
|
//if b.var == 0, b.var stays 0
|
||||||
|
//if a.var != 0, b.var keeps its value
|
||||||
|
} else if(a.op == '|') {
|
||||||
|
if(a.var != 0.0)
|
||||||
|
b.var = a.var;
|
||||||
|
|
||||||
|
//if a.var == 0, b.var keeps its value
|
||||||
|
//if a.var != 0, b.var takes the value of a
|
||||||
|
}
|
||||||
|
|
||||||
|
ops.remove(pairId);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check
|
||||||
|
if(ops.size() != 1 || ops.get(0).op != (char) 0)
|
||||||
|
throw new RuntimeException("Error while parsing evaluating \"" + expr + "\"");
|
||||||
|
|
||||||
|
return ops.get(0).var;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.renderers;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
public interface IItemRenderer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param pose the pose stack
|
||||||
|
* @param stack the item stack
|
||||||
|
* @param handSideSign TODO:
|
||||||
|
* @param swingProgress TODO:
|
||||||
|
* @param equipProgress TODO:
|
||||||
|
* @param multiBufferSource the buffer source
|
||||||
|
* @param packedLight packed light
|
||||||
|
* @return whether or not to cancel vanilla rendering
|
||||||
|
*/
|
||||||
|
boolean render(PoseStack pose, ItemStack stack, float handSideSign, float swingProgress, float equipProgress, MultiBufferSource multiBufferSource, int packedLight);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.renderers;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.*;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.montoyo.wd.client.ClientProxy;
|
||||||
|
import net.montoyo.wd.registry.ItemRegistry;
|
||||||
|
import net.montoyo.wd.item.ItemLaserPointer;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
|
import static com.mojang.math.Axis.*;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public final class LaserPointerRenderer implements IItemRenderer {
|
||||||
|
|
||||||
|
public LaserPointerRenderer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isOn() {
|
||||||
|
if (Minecraft.getInstance().screen != null) return false;
|
||||||
|
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
return mc.player != null && mc.level != null &&
|
||||||
|
(
|
||||||
|
ClientProxy.mouseOn ||
|
||||||
|
ItemLaserPointer.isOn()
|
||||||
|
) &&
|
||||||
|
mc.player.getItemInHand(InteractionHand.MAIN_HAND).getItem().equals(ItemRegistry.LASER_POINTER.get()) &&
|
||||||
|
(mc.hitResult == null || mc.hitResult.getType() == HitResult.Type.BLOCK || mc.hitResult.getType() == HitResult.Type.MISS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean render(PoseStack poseStack, ItemStack is, float handSideSign, float swingProgress, float equipProgress, MultiBufferSource multiBufferSource, int packedLight) {
|
||||||
|
RenderSystem.disableCull();
|
||||||
|
// RenderSystem.disableTexture();
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
|
||||||
|
float PI = (float) Math.PI;
|
||||||
|
|
||||||
|
float sqrtSwingProg = (float) Math.sqrt(swingProgress);
|
||||||
|
float sinSqrtSwingProg1 = (float) Math.sin(sqrtSwingProg * PI);
|
||||||
|
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||||
|
|
||||||
|
var matrix0 = poseStack.last().pose();
|
||||||
|
//Laser pointer
|
||||||
|
poseStack.pushPose();
|
||||||
|
poseStack.translate(handSideSign * -0.4f * sinSqrtSwingProg1, (float) (0.2f * Math.sin(sqrtSwingProg * PI * 2.0f)), (float) (-0.2f * Math.sin(swingProgress * PI)));
|
||||||
|
poseStack.translate(handSideSign * 0.56f, -0.52f - equipProgress * 0.6f, -0.72f);
|
||||||
|
poseStack.mulPose(YP.rotationDegrees((float) (handSideSign * (45.0f - Math.sin(swingProgress * swingProgress * PI) * 20.0f))));
|
||||||
|
poseStack.mulPose(ZP.rotationDegrees(handSideSign * sinSqrtSwingProg1 * -20.0f));
|
||||||
|
poseStack.mulPose(XP.rotationDegrees(sinSqrtSwingProg1 * -80.0f));
|
||||||
|
poseStack.mulPose(YP.rotationDegrees(handSideSign * -30.0f));
|
||||||
|
poseStack.translate(0.0f, 0.2f, 0.0f);
|
||||||
|
poseStack.mulPose(XP.rotationDegrees(10.0f));
|
||||||
|
poseStack.scale(1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f);
|
||||||
|
var matrix = poseStack.last().pose();
|
||||||
|
|
||||||
|
BufferBuilder bb = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
|
||||||
|
|
||||||
|
bb.addVertex(matrix, 0.0f, 0.0f, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 1.0f, 0.0f, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 1.0f, 0.0f, 4.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 0.0f, 0.0f, 4.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
|
||||||
|
bb.addVertex(matrix, 0.0f, 0.0f, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 0.0f, -1.0f, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 0.0f, -1.0f, 4.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 0.0f, 0.0f, 4.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
|
||||||
|
bb.addVertex(matrix, 1.0f, 0.0f, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 1.0f, -1.0f, 0.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 1.0f, -1.0f, 4.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 1.0f, 0.0f, 4.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
|
||||||
|
bb.addVertex(matrix, 0.0f, -1.0f, 4.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 1.0f, -1.0f, 4.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 1.0f, 0.0f, 4.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 0.0f, 0.0f, 4.0f).setColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
|
||||||
|
if (isOn()) drawLineBetween(bb, matrix0, matrix, new Vec3(0.5f, -0.5f, 0.5f), new Vec3(-40.0f, 4000.5f, -100.0f));
|
||||||
|
|
||||||
|
BufferUploader.drawWithShader(bb.buildOrThrow());
|
||||||
|
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
RenderSystem.disableDepthTest();
|
||||||
|
// RenderSystem.enableTexture(); //Fix for shitty minecraft fire
|
||||||
|
RenderSystem.enableCull();
|
||||||
|
poseStack.popPose();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawLineBetween(BufferBuilder bb, Matrix4f matrix0, Matrix4f matrix, Vec3 local, Vec3 target) {
|
||||||
|
//Calculate distance between points -> length of the line
|
||||||
|
float distance = (float) local.distanceTo(target) / 2;
|
||||||
|
float quarterWidth = 0.25f;
|
||||||
|
float biggerWidth = 10;
|
||||||
|
|
||||||
|
bb.addVertex(matrix, 0.25f, -0.25f, 0.5f).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
bb.addVertex(matrix, quarterWidth + 0.25f, -0.25f, 0.5f).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
bb.addVertex(matrix0, biggerWidth - 6f, 3f, -distance).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
bb.addVertex(matrix0, -6f, 3f, -distance).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
bb.addVertex(matrix, 0.25f, -0.25f, 0.5f).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
bb.addVertex(matrix, 0.25f, -quarterWidth - 0.25f, 0.5f).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
bb.addVertex(matrix0, -6f, -biggerWidth + 3f, -distance).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
bb.addVertex(matrix0, -6f, 3f, -distance).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
bb.addVertex(matrix, quarterWidth + 0.25f, -0.25f, 0.5f).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
bb.addVertex(matrix, quarterWidth + 0.25f, -quarterWidth - 0.25f, 0.5f).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
bb.addVertex(matrix0, biggerWidth - 6f, -biggerWidth + 3f, -distance).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
bb.addVertex(matrix0, biggerWidth - 6f, 3f, -distance).setColor(0.5f, 0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.renderers;
|
||||||
|
|
||||||
|
import com.cinemamod.mcef.MCEFBrowser;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.*;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.entity.HumanoidArm;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.client.ClientProxy;
|
||||||
|
import net.montoyo.wd.data.WDDataComponents;
|
||||||
|
import net.montoyo.wd.config.ClientConfig;
|
||||||
|
import net.montoyo.wd.item.ItemMinePad2;
|
||||||
|
|
||||||
|
import static com.mojang.math.Axis.*;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public final class MinePadRenderer implements IItemRenderer {
|
||||||
|
private static final float PI = (float) Math.PI;
|
||||||
|
private final Minecraft mc = Minecraft.getInstance();
|
||||||
|
private final ResourceLocation tex = ResourceLocation.fromNamespaceAndPath("webdisplays", "textures/item/model/minepad.png");
|
||||||
|
private final ModelMinePad model = new ModelMinePad();
|
||||||
|
private final ClientProxy clientProxy = (ClientProxy) WebDisplays.PROXY;
|
||||||
|
|
||||||
|
private float sinSqrtSwingProg1;
|
||||||
|
private float sinSqrtSwingProg2;
|
||||||
|
private float sinSwingProg1;
|
||||||
|
private float sinSwingProg2;
|
||||||
|
|
||||||
|
public static boolean renderAtSide(float handSideSign) {
|
||||||
|
float relSide = handSideSign;
|
||||||
|
if (Minecraft.getInstance().player.getMainArm() == HumanoidArm.LEFT) relSide *= -1;
|
||||||
|
|
||||||
|
// by default, the player holds the device off to the side
|
||||||
|
// if they are crouching, they hold it infront of them
|
||||||
|
// however, if they are holding two at once, then it once again should just be held off to the side
|
||||||
|
boolean sideHold = Minecraft.getInstance().player.isShiftKeyDown() != ClientConfig.sidePad;
|
||||||
|
if (
|
||||||
|
(relSide < 0 && Minecraft.getInstance().player.getItemInHand(InteractionHand.MAIN_HAND).getItem() instanceof ItemMinePad2) ||
|
||||||
|
(relSide > 0 && Minecraft.getInstance().player.getItemInHand(InteractionHand.OFF_HAND).getItem() instanceof ItemMinePad2)
|
||||||
|
) sideHold = true;
|
||||||
|
|
||||||
|
return sideHold;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean render(PoseStack stack, ItemStack is, float handSideSign, float swingProgress, float equipProgress, MultiBufferSource multiBufferSource, int packedLight) {
|
||||||
|
//Pre-compute values
|
||||||
|
float sqrtSwingProg = (float) Math.sqrt(swingProgress);
|
||||||
|
sinSqrtSwingProg1 = (float) Math.sin(sqrtSwingProg * PI);
|
||||||
|
sinSqrtSwingProg2 = (float) Math.sin(sqrtSwingProg * PI * 2.0f);
|
||||||
|
sinSwingProg1 = (float) Math.sin(swingProgress * PI);
|
||||||
|
sinSwingProg2 = (float) Math.sin(swingProgress * swingProgress * PI);
|
||||||
|
|
||||||
|
boolean sideHold = renderAtSide(handSideSign);
|
||||||
|
|
||||||
|
//Render arm
|
||||||
|
stack.pushPose();
|
||||||
|
renderArmFirstPerson(stack, multiBufferSource, packedLight, equipProgress, handSideSign);
|
||||||
|
stack.popPose();
|
||||||
|
// if (!sideHold && handSideSign == 1 && mc.player.getItemInHand(InteractionHand.OFF_HAND).isEmpty()) {
|
||||||
|
// stack.pushPose();
|
||||||
|
// renderArmFirstPerson(stack, multiBufferSource, packedLight, 0, -handSideSign);
|
||||||
|
// stack.popPose();
|
||||||
|
// }
|
||||||
|
|
||||||
|
//Prepare minePad transform
|
||||||
|
stack.pushPose();
|
||||||
|
stack.translate(handSideSign * -0.4f * sinSqrtSwingProg1, 0.2f * sinSqrtSwingProg2, -0.2f * sinSwingProg1);
|
||||||
|
stack.translate(handSideSign * 0.56f, -0.52f - equipProgress * 0.6f, -0.72f);
|
||||||
|
stack.mulPose(YP.rotationDegrees(handSideSign * (45.0f - sinSwingProg2 * 20.0f)));
|
||||||
|
stack.mulPose(ZP.rotationDegrees(handSideSign * sinSqrtSwingProg1 * -20.0f));
|
||||||
|
stack.mulPose(XP.rotationDegrees(sinSqrtSwingProg1 * -80.0f));
|
||||||
|
stack.mulPose(YP.rotationDegrees(handSideSign * -45.0f));
|
||||||
|
|
||||||
|
if (sideHold) {
|
||||||
|
stack.translate(0.0f, 0.0f, -0.2f);
|
||||||
|
stack.mulPose(YP.rotationDegrees(20.0f * -handSideSign));
|
||||||
|
float total = 0.475f;
|
||||||
|
float off = -0.025f; // gotta love magic numbers
|
||||||
|
stack.translate(-(total - off) + (off * handSideSign), -0.1f, 0.0f);
|
||||||
|
stack.mulPose(ZP.rotationDegrees(1.0f));
|
||||||
|
} else if (handSideSign >= 0) // right hand
|
||||||
|
stack.translate(-1.065f, 0.0f, 0.0f);
|
||||||
|
else // left hand
|
||||||
|
stack.translate(0.065f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
//Render model
|
||||||
|
stack.translate(0.063f, 0.28f, 0.001f);
|
||||||
|
model.render(multiBufferSource, stack);
|
||||||
|
stack.translate(-0.063f, -0.28f, -0.001f);
|
||||||
|
|
||||||
|
// force draw so the browser can be drawn ontop of the model
|
||||||
|
multiBufferSource.getBuffer(RenderType.LINES);
|
||||||
|
|
||||||
|
if (is.has(WDDataComponents.PAD_ID.get())) {
|
||||||
|
ClientProxy.PadData pd = clientProxy.getPadByID(is.get(WDDataComponents.PAD_ID.get()));
|
||||||
|
|
||||||
|
//Render web view
|
||||||
|
if (pd != null) {
|
||||||
|
double x1 = 0.0;
|
||||||
|
double y1 = 0.0;
|
||||||
|
double x2 = 27.65 / 32.0 + 0.01;
|
||||||
|
double y2 = 14.0 / 32.0 + 0.002;
|
||||||
|
|
||||||
|
stack.translate(0.063f, 0.28f, 0.001f);
|
||||||
|
// RenderSystem.setShaderTexture(0, tex);
|
||||||
|
|
||||||
|
RenderSystem.disableDepthTest();
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionTexColorShader);
|
||||||
|
RenderSystem.setShaderTexture(0, ((MCEFBrowser) pd.view).getRenderer().getTextureID());
|
||||||
|
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR);
|
||||||
|
buffer.addVertex(stack.last().pose(), (float) x1, (float) y1, 0.0f).setUv(0.0F, 1.0F).setColor(1f, 1f, 1f, 1f);
|
||||||
|
buffer.addVertex(stack.last().pose(), (float) x2, (float) y1, 0.0f).setUv(1.0F, 1.0F).setColor(1f, 1f, 1f, 1f);
|
||||||
|
buffer.addVertex(stack.last().pose(), (float) x2, (float) y2, 0.0f).setUv(1.0F, 0.0F).setColor(1f, 1f, 1f, 1f);
|
||||||
|
buffer.addVertex(stack.last().pose(), (float) x1, (float) y2, 0.0f).setUv(0.0F, 0.0F).setColor(1f, 1f, 1f, 1f);
|
||||||
|
BufferUploader.drawWithShader(buffer.buildOrThrow());
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.popPose();
|
||||||
|
RenderSystem.enableCull();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderArmFirstPerson(PoseStack stack, MultiBufferSource buffer, int combinedLight, float equipProgress, float handSideSign) {
|
||||||
|
float tx = -0.3f * sinSqrtSwingProg1;
|
||||||
|
float ty = 0.4f * sinSqrtSwingProg2;
|
||||||
|
float tz = -0.4f * sinSwingProg1;
|
||||||
|
|
||||||
|
stack.translate(handSideSign * (tx + 0.64000005f), ty - 0.6f - equipProgress * 0.6f, tz - 0.71999997f);
|
||||||
|
stack.mulPose(YP.rotationDegrees(handSideSign * 45.0f));
|
||||||
|
stack.mulPose(YP.rotationDegrees(handSideSign * sinSqrtSwingProg1 * 70.0f));
|
||||||
|
stack.mulPose(ZP.rotationDegrees(handSideSign * sinSwingProg2 * -20.0f));
|
||||||
|
stack.translate(-handSideSign, 3.6f, 3.5f);
|
||||||
|
stack.mulPose(ZP.rotationDegrees(handSideSign * 120.0f));
|
||||||
|
stack.mulPose(XP.rotationDegrees(200.0f));
|
||||||
|
stack.mulPose(YP.rotationDegrees(handSideSign * -135.0f));
|
||||||
|
stack.translate(handSideSign * 5.6f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
PlayerRenderer playerRenderer = (PlayerRenderer) mc.getEntityRenderDispatcher().getRenderer(mc.player);
|
||||||
|
|
||||||
|
if (handSideSign >= 0.0f)
|
||||||
|
playerRenderer.renderRightHand(stack, buffer, combinedLight, mc.player);
|
||||||
|
else
|
||||||
|
playerRenderer.renderLeftHand(stack, buffer, combinedLight, mc.player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.renderers;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.*;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public final class ModelMinePad {
|
||||||
|
public void render(MultiBufferSource buffers, PoseStack stack) {
|
||||||
|
// TODO: this needs completing
|
||||||
|
// TODO: I'd like this to be able to load a model from a JSON if possible
|
||||||
|
|
||||||
|
double x1 = 0.0;
|
||||||
|
double y1 = 0.0;
|
||||||
|
double x2 = 27.65 / 32.0 + 0.01;
|
||||||
|
double y2 = 14.0 / 32.0 + 0.002;
|
||||||
|
|
||||||
|
Matrix4f positionMatrix = stack.last().pose();
|
||||||
|
BufferBuilder vb = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
|
||||||
|
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||||
|
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
vb.addVertex(positionMatrix, (float) x1, (float) y1, 0.0f).setColor(0f, 0f, 0f, 1f);
|
||||||
|
vb.addVertex(positionMatrix, (float) x2, (float) y1, 0.0f).setColor(0f, 0f, 0f, 1f);
|
||||||
|
vb.addVertex(positionMatrix, (float) x2, (float) y2, 0.0f).setColor(0f, 0f, 0f, 1f);
|
||||||
|
vb.addVertex(positionMatrix, (float) x1, (float) y2, 0.0f).setColor(0f, 0f, 0f, 1f);
|
||||||
|
BufferUploader.drawWithShader(vb.buildOrThrow());
|
||||||
|
|
||||||
|
int width = 32;
|
||||||
|
int height = 32;
|
||||||
|
|
||||||
|
float padding = 1f / 23;
|
||||||
|
float padding1 = 1f / 21;
|
||||||
|
|
||||||
|
float z = 0;
|
||||||
|
|
||||||
|
VertexConsumer consumer = buffers.getBuffer(RenderType.entityCutout(ResourceLocation.fromNamespaceAndPath("webdisplays", "textures/item/model/minepad_item.png")));
|
||||||
|
|
||||||
|
consumer.addVertex((float) x1, (float) y1 - padding, z).setColor(255, 255, 255, 255).setUv(1f / width, 12f / height).setOverlay(OverlayTexture.NO_OVERLAY).setLight(LightTexture.FULL_BRIGHT).setNormal(0.25f, 0.5f, 1);
|
||||||
|
consumer.addVertex((float) x2, (float) y1 - padding, z).setColor(255, 255, 255, 255).setUv(19f / width, 12f / height).setOverlay(OverlayTexture.NO_OVERLAY).setLight(LightTexture.FULL_BRIGHT).setNormal(0.25f, 0.5f, 1);
|
||||||
|
consumer.addVertex((float) x2, (float) y2 + padding, z).setColor(255, 255, 255, 255).setUv(19f / width, 0).setOverlay(OverlayTexture.NO_OVERLAY).setLight(LightTexture.FULL_BRIGHT).setNormal(0.25f, 0.5f, 1);
|
||||||
|
consumer.addVertex((float) x1, (float) y2 + padding, z).setColor(255, 255, 255, 255).setUv(1f / width, 0).setOverlay(OverlayTexture.NO_OVERLAY).setLight(LightTexture.FULL_BRIGHT).setNormal(0.25f, 0.5f, 1);
|
||||||
|
|
||||||
|
consumer.addVertex((float) x1 - padding1, (float) y1, z).setColor(255, 255, 255, 255).setUv(0f / width, 10f / height).setOverlay(OverlayTexture.NO_OVERLAY).setLight(LightTexture.FULL_BRIGHT).setNormal(0.25f, 0.5f, 1);
|
||||||
|
consumer.addVertex((float) x2 + padding1, (float) y1, z).setColor(255, 255, 255, 255).setUv(20f / width, 10f / height).setOverlay(OverlayTexture.NO_OVERLAY).setLight(LightTexture.FULL_BRIGHT).setNormal(0.25f, 0.5f, 1);
|
||||||
|
consumer.addVertex((float) x2 + padding1, (float) y2, z).setColor(255, 255, 255, 255).setUv(20f / width, 1f / height).setOverlay(OverlayTexture.NO_OVERLAY).setLight(LightTexture.FULL_BRIGHT).setNormal(0.25f, 0.5f, 1);
|
||||||
|
consumer.addVertex((float) x1 - padding1, (float) y2, z).setColor(255, 255, 255, 255).setUv(0f / width, 1f / height).setOverlay(OverlayTexture.NO_OVERLAY).setLight(LightTexture.FULL_BRIGHT).setNormal(0.25f, 0.5f, 1);
|
||||||
|
|
||||||
|
// consumer.vertex(positionMatrix, (float) x2, (float) y2 + padding, z - padding).color(255, 255, 255, 255).uv(0f / width, 1f / height).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(LightTexture.FULL_BRIGHT).normal(0.25f, 0.5f, 1).endVertex();
|
||||||
|
// consumer.vertex(positionMatrix, (float) x2, (float) y2 + padding, z).color(255, 255, 255, 255).uv(1f / width, 1f / height).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(LightTexture.FULL_BRIGHT).normal(0.25f, 0.5f, 1).endVertex();
|
||||||
|
// consumer.vertex(positionMatrix, (float) x2, (float) y1 - padding, z).color(255, 255, 255, 255).uv(1f / width, 2f / height).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(LightTexture.FULL_BRIGHT).normal(0.25f, 0.5f, 1).endVertex();
|
||||||
|
// consumer.vertex(positionMatrix, (float) x2, (float) y1 - padding, z - padding).color(255, 255, 255, 255).uv(0f / width, 2f / height).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(LightTexture.FULL_BRIGHT).normal(0.25f, 0.5f, 1).endVertex();
|
||||||
|
//
|
||||||
|
// consumer.vertex(positionMatrix, (float) x1, (float) y1 - padding, z - padding).color(255, 255, 255, 255).uv(0f / width, 2f / height).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(LightTexture.FULL_BRIGHT).normal(0.25f, 0.5f, 1).endVertex();
|
||||||
|
// consumer.vertex(positionMatrix, (float) x1, (float) y1 - padding, z).color(255, 255, 255, 255).uv(1f / width, 2f / height).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(LightTexture.FULL_BRIGHT).normal(0.25f, 0.5f, 1).endVertex();
|
||||||
|
// consumer.vertex(positionMatrix, (float) x1, (float) y2 + padding, z).color(255, 255, 255, 255).uv(1f / width, 1f / height).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(LightTexture.FULL_BRIGHT).normal(0.25f, 0.5f, 1).endVertex();
|
||||||
|
// consumer.vertex(positionMatrix, (float) x1, (float) y2 + padding, z - padding).color(255, 255, 255, 255).uv(0f / width, 1f / height).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(LightTexture.FULL_BRIGHT).normal(0.25f, 0.5f, 1).endVertex();
|
||||||
|
}
|
||||||
|
}
|
||||||
236
src/main/java/net/montoyo/wd/client/renderers/ScreenBaker.java
Normal file
236
src/main/java/net/montoyo/wd/client/renderers/ScreenBaker.java
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.renderers;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||||
|
import net.minecraft.client.renderer.block.model.ItemOverrides;
|
||||||
|
import net.minecraft.client.renderer.block.model.ItemTransforms;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
|
import net.minecraft.client.resources.model.ModelState;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.neoforged.neoforge.client.model.data.ModelData;
|
||||||
|
import net.neoforged.neoforge.client.model.data.ModelProperty;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3f;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ScreenBaker implements BakedModel {
|
||||||
|
|
||||||
|
private static final List<BakedQuad> noQuads = ImmutableList.of();
|
||||||
|
private final TextureAtlasSprite[] texs = new TextureAtlasSprite[16];
|
||||||
|
private final BlockSide[] blockSides = BlockSide.values();
|
||||||
|
private final Direction[] blockFacings = Direction.values();
|
||||||
|
private final ModelState modelState;
|
||||||
|
private final Function<net.minecraft.client.resources.model.Material, TextureAtlasSprite> spriteGetter;
|
||||||
|
private final ItemOverrides overrides;
|
||||||
|
private final ItemTransforms itemTransforms;
|
||||||
|
|
||||||
|
IntegerModelProperty[] TEXTURES = new IntegerModelProperty[6];
|
||||||
|
|
||||||
|
public ScreenBaker(ModelState modelState, Function<net.minecraft.client.resources.model.Material, TextureAtlasSprite> spriteGetter, ItemOverrides overrides, ItemTransforms itemTransforms) {
|
||||||
|
this.modelState = modelState;
|
||||||
|
this.spriteGetter = spriteGetter;
|
||||||
|
this.overrides = overrides;
|
||||||
|
this.itemTransforms = itemTransforms;
|
||||||
|
|
||||||
|
for (int i = 0; i < texs.length; i++) {
|
||||||
|
texs[i] = spriteGetter.apply(ScreenModelLoader.MATERIALS_SIDES[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < TEXTURES.length; i++) {
|
||||||
|
TEXTURES[i] = new IntegerModelProperty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putVertex(int[] buf, int pos, Vector3f vpos, TextureAtlasSprite tex, Vector3f uv, Vector3i normal) {
|
||||||
|
pos *= 8;
|
||||||
|
|
||||||
|
buf[pos] = Float.floatToRawIntBits(vpos.x);
|
||||||
|
buf[pos + 1] = Float.floatToRawIntBits(vpos.y);
|
||||||
|
buf[pos + 2] = Float.floatToRawIntBits(vpos.z);
|
||||||
|
buf[pos + 3] = 0xFFFFFFFF; //Color, let this white...
|
||||||
|
buf[pos + 4] = Float.floatToRawIntBits(tex.getU(uv.x));
|
||||||
|
buf[pos + 5] = Float.floatToRawIntBits(tex.getV(uv.y));
|
||||||
|
|
||||||
|
int nx = (normal.x * 127) & 0xFF;
|
||||||
|
int ny = (normal.y * 127) & 0xFF;
|
||||||
|
int nz = (normal.z * 127) & 0xFF;
|
||||||
|
buf[pos + 7] = nx | (ny << 8) | (nz << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3f rotateVec(Vector3f vec, BlockSide side) {
|
||||||
|
return switch (side) {
|
||||||
|
case BOTTOM -> new Vector3f(vec.x, 1.0f, 1.0f - vec.z);
|
||||||
|
case TOP -> new Vector3f(vec.x, 0.0f, vec.z);
|
||||||
|
case NORTH -> new Vector3f(vec.x, vec.z, 1.0f);
|
||||||
|
case SOUTH -> new Vector3f(vec.x, 1.0f - vec.z, 0.0f);
|
||||||
|
case WEST -> new Vector3f(1.f, vec.x, vec.z);
|
||||||
|
case EAST -> new Vector3f(0.0f, 1.0f - vec.x, vec.z);
|
||||||
|
//noinspection UnnecessaryDefault
|
||||||
|
default -> throw new RuntimeException("Unknown block side " + side);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3f rotateTex(BlockSide side, float u, float v) {
|
||||||
|
return switch (side) {
|
||||||
|
case BOTTOM, NORTH -> new Vector3f(16.f - u, 16.f - v, 0.0f);
|
||||||
|
case TOP -> new Vector3f(16.f - u, v, 0.0f);
|
||||||
|
case SOUTH -> new Vector3f(u, v, 0.0f);
|
||||||
|
case WEST -> new Vector3f(16.f - v, u, 0.0f);
|
||||||
|
case EAST -> new Vector3f(v, 16.f - u, 0.0f);
|
||||||
|
//noinspection UnnecessaryDefault
|
||||||
|
default -> throw new RuntimeException("Unknown block side " + side);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private BakedQuad bakeSide(BlockSide side, TextureAtlasSprite tex) {
|
||||||
|
int[] data = new int[8 * 4];
|
||||||
|
|
||||||
|
// I have no idea
|
||||||
|
int rotation = switch (side) {
|
||||||
|
case NORTH, TOP, BOTTOM -> 2;
|
||||||
|
case SOUTH -> 0;
|
||||||
|
case EAST -> 1;
|
||||||
|
case WEST -> 3;
|
||||||
|
//noinspection UnnecessaryDefault
|
||||||
|
default -> throw new RuntimeException("Unknown block side " + side);
|
||||||
|
};
|
||||||
|
|
||||||
|
putVertex(data, (rotation + 3) % 4, rotateVec(new Vector3f(0.0f, 0.0f, 0.0f), side), tex, rotateTex(side, 16.0f, 0.0f), side.backward);
|
||||||
|
putVertex(data, (rotation + 2) % 4, rotateVec(new Vector3f(0.0f, 0.0f, 1.0f), side), tex, rotateTex(side, 16.0f, 16.0f), side.backward);
|
||||||
|
putVertex(data, (rotation + 1) % 4, rotateVec(new Vector3f(1.0f, 0.0f, 1.0f), side), tex, rotateTex(side, 0.0f, 16.0f), side.backward);
|
||||||
|
putVertex(data, (rotation) % 4, rotateVec(new Vector3f(1.0f, 0.0f, 0.0f), side), tex, rotateTex(side, 0.0f, 0.0f), side.backward);
|
||||||
|
|
||||||
|
return new BakedQuad(data, 0xFFFFFFFF, blockFacings[side.ordinal()].getOpposite(), tex, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource random) {
|
||||||
|
return getQuads(state, side, random, ModelData.EMPTY, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @NotNull RandomSource rand, @NotNull ModelData data, @Nullable RenderType renderType) {
|
||||||
|
if (side == null)
|
||||||
|
return noQuads;
|
||||||
|
|
||||||
|
List<BakedQuad> ret = new ArrayList<>();
|
||||||
|
|
||||||
|
int sid = BlockSide.reverse(side.ordinal());
|
||||||
|
BlockSide s = blockSides[sid];
|
||||||
|
TextureAtlasSprite tex = texs[15];
|
||||||
|
if (data.has(TEXTURES[side.ordinal()]))
|
||||||
|
tex = texs[data.get(TEXTURES[side.ordinal()])];
|
||||||
|
ret.add(bakeSide(s, tex));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte check(BlockState state, BlockAndTintGetter level, BlockPos pos, Vector3i dir) {
|
||||||
|
BlockState u = level.getBlockState(pos.offset(dir.x, dir.y, dir.z));
|
||||||
|
BlockState d = level.getBlockState(pos.offset(-dir.x, -dir.y, -dir.z));
|
||||||
|
if (
|
||||||
|
u.getBlock() == state.getBlock() &&
|
||||||
|
d.getBlock() != state.getBlock()
|
||||||
|
) return (byte) 1; // away
|
||||||
|
else if (
|
||||||
|
d.getBlock() == state.getBlock() &&
|
||||||
|
u.getBlock() != state.getBlock()
|
||||||
|
) return (byte) 2; // to
|
||||||
|
else if (
|
||||||
|
d.getBlock() != state.getBlock() &&
|
||||||
|
u.getBlock() != state.getBlock()
|
||||||
|
) return (byte) 3; // both
|
||||||
|
return (byte) 0; // none
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull ModelData modelData) {
|
||||||
|
ModelData.Builder builder = ModelData.builder();
|
||||||
|
|
||||||
|
final int BAR_BOTTOM = 1;
|
||||||
|
final int BAR_RIGHT = 2;
|
||||||
|
final int BAR_TOP = 4;
|
||||||
|
final int BAR_LEFT = 8;
|
||||||
|
|
||||||
|
for (int i = 0; i < TEXTURES.length; i++) {
|
||||||
|
BlockSide side = blockSides[i];
|
||||||
|
|
||||||
|
// check up and down
|
||||||
|
int res = switch (check(state, level, pos, side.up)) {
|
||||||
|
case 1 -> BAR_BOTTOM;
|
||||||
|
case 2 -> BAR_TOP;
|
||||||
|
case 3 -> BAR_TOP | BAR_BOTTOM;
|
||||||
|
default -> 0;
|
||||||
|
};
|
||||||
|
// check left and right
|
||||||
|
res |= switch (check(state, level, pos, side.right)) {
|
||||||
|
case 1 -> BAR_LEFT;
|
||||||
|
case 2 -> BAR_RIGHT;
|
||||||
|
case 3 -> BAR_LEFT | BAR_RIGHT;
|
||||||
|
default -> 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
builder.with(TEXTURES[i], res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useAmbientOcclusion() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGui3d() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean usesBlockLight() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCustomRenderer() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public TextureAtlasSprite getParticleIcon() {
|
||||||
|
return texs[15];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public ItemTransforms getTransforms() {
|
||||||
|
return ItemTransforms.NO_TRANSFORMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public ItemOverrides getOverrides() {
|
||||||
|
return ItemOverrides.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
public static final class IntegerModelProperty extends ModelProperty<Integer> {}
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package net.montoyo.wd.client.renderers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import net.minecraft.client.renderer.block.model.ItemOverrides;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
|
import net.minecraft.client.resources.model.*;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||||
|
import net.minecraft.world.inventory.InventoryMenu;
|
||||||
|
import net.neoforged.neoforge.client.model.geometry.IGeometryBakingContext;
|
||||||
|
import net.neoforged.neoforge.client.model.geometry.IGeometryLoader;
|
||||||
|
import net.neoforged.neoforge.client.model.geometry.IUnbakedGeometry;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ScreenModelLoader implements IGeometryLoader<ScreenModelLoader.ScreenModelGeometry> {
|
||||||
|
public static final ResourceLocation SCREEN_LOADER = ResourceLocation.fromNamespaceAndPath("webdisplays", "screen_loader");
|
||||||
|
|
||||||
|
public static final ResourceLocation SCREEN_SIDE = ResourceLocation.fromNamespaceAndPath("webdisplays", "block/screen");
|
||||||
|
|
||||||
|
private static final ResourceLocation[] SIDES = new ResourceLocation[16];
|
||||||
|
public static final Material[] MATERIALS_SIDES = new Material[16];
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (int i = 0; i < SIDES.length; i++) {
|
||||||
|
SIDES[i] = ResourceLocation.fromNamespaceAndPath(SCREEN_SIDE.getNamespace(), SCREEN_SIDE.getPath() + i);
|
||||||
|
MATERIALS_SIDES[i] = new Material(InventoryMenu.BLOCK_ATLAS, SIDES[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScreenModelGeometry read(JsonObject jsonObject, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
|
||||||
|
return new ScreenModelGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ScreenModelGeometry implements IUnbakedGeometry<ScreenModelGeometry> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState, ItemOverrides overrides) {
|
||||||
|
return new ScreenBaker(modelState, spriteGetter, overrides, context.getTransforms());
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public void resolveParents(Function<ResourceLocation, UnbakedModel> modelGetter, IGeometryBakingContext context) {
|
||||||
|
// IUnbakedGeometry.super.resolveParents(modelGetter, context);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public Set<String> getConfigurableComponentNames() {
|
||||||
|
// return IUnbakedGeometry.super.getConfigurableComponentNames();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// In NeoForge 1.21, materials are discovered via atlas sources.
|
||||||
|
// We register screen0..screen15 textures in assets/webdisplays/atlases/blocks.json.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client.renderers;
|
||||||
|
|
||||||
|
import com.cinemamod.mcef.MCEFBrowser;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.*;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||||
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.ScreenData;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3f;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import static com.mojang.math.Axis.*;
|
||||||
|
|
||||||
|
public class ScreenRenderer implements BlockEntityRenderer<ScreenBlockEntity> {
|
||||||
|
public ScreenRenderer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ScreenRendererProvider implements BlockEntityRendererProvider<ScreenBlockEntity> {
|
||||||
|
@Override
|
||||||
|
public @NotNull BlockEntityRenderer<ScreenBlockEntity> create(@NotNull Context arg) {
|
||||||
|
return new ScreenRenderer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Vector3f mid = new Vector3f();
|
||||||
|
private final Vector3i tmpi = new Vector3i();
|
||||||
|
private final Vector3f tmpf = new Vector3f();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(ScreenBlockEntity te, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight, int packedOverlay) {
|
||||||
|
if (!te.isLoaded())
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Disable lighting
|
||||||
|
// RenderSystem.enableTexture();
|
||||||
|
// RenderSystem.disableCull();
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
|
||||||
|
for (int i = 0; i < te.screenCount(); i++) {
|
||||||
|
ScreenData scr = te.getScreen(i);
|
||||||
|
if (scr.browser == null) {
|
||||||
|
double dist = WebDisplays.PROXY.distanceTo(te, Minecraft.getInstance().getEntityRenderDispatcher().camera.getPosition());
|
||||||
|
if (dist <= WebDisplays.INSTANCE.loadDistance2 * 16)
|
||||||
|
scr.createBrowser(te, true);
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: manually backface cull the screens
|
||||||
|
|
||||||
|
tmpi.set(scr.side.right);
|
||||||
|
tmpi.mul(scr.size.x);
|
||||||
|
tmpi.addMul(scr.side.up, scr.size.y);
|
||||||
|
tmpf.set(tmpi);
|
||||||
|
mid.set(0.5, 0.5, 0.5);
|
||||||
|
mid.addMul(tmpf, 0.5f);
|
||||||
|
tmpf.set(scr.side.left);
|
||||||
|
mid.addMul(tmpf, 0.5f);
|
||||||
|
tmpf.set(scr.side.down);
|
||||||
|
mid.addMul(tmpf, 0.5f);
|
||||||
|
|
||||||
|
poseStack.pushPose();
|
||||||
|
poseStack.translate(mid.x, mid.y, mid.z);
|
||||||
|
|
||||||
|
switch (scr.side) {
|
||||||
|
case BOTTOM:
|
||||||
|
poseStack.mulPose(XP.rotation(90.f + 49.8f));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOP:
|
||||||
|
poseStack.mulPose(XN.rotation(90.f + 49.8f));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NORTH:
|
||||||
|
poseStack.mulPose(YN.rotationDegrees(180.f));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOUTH:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WEST:
|
||||||
|
poseStack.mulPose(YN.rotationDegrees(90.f));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EAST:
|
||||||
|
poseStack.mulPose(YP.rotationDegrees(90.f));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scr.doTurnOnAnim) {
|
||||||
|
long lt = System.currentTimeMillis() - scr.turnOnTime;
|
||||||
|
float ft = ((float) lt) / 100.0f;
|
||||||
|
|
||||||
|
if (ft >= 1.0f) {
|
||||||
|
ft = 1.0f;
|
||||||
|
scr.doTurnOnAnim = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
poseStack.scale(ft, ft, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scr.rotation.isNull)
|
||||||
|
poseStack.mulPose(ZP.rotationDegrees(scr.rotation.angle));
|
||||||
|
|
||||||
|
float sw = ((float) scr.size.x) * 0.5f - 2.f / 16.f;
|
||||||
|
float sh = ((float) scr.size.y) * 0.5f - 2.f / 16.f;
|
||||||
|
|
||||||
|
if (scr.rotation.isVertical) {
|
||||||
|
float tmp = sw;
|
||||||
|
sw = sh;
|
||||||
|
sh = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tesselator tesselator = Tesselator.getInstance();
|
||||||
|
BufferBuilder builder = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR);
|
||||||
|
//TODO: don't use tesselator
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionTexColorShader);
|
||||||
|
RenderSystem.setShaderTexture(0, ((MCEFBrowser) scr.browser).getRenderer().getTextureID());
|
||||||
|
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
builder.addVertex(poseStack.last().pose(), -sw, -sh, 0.505f).setUv(0.f, 1.f).setColor(1.f, 1.f, 1.f, 1.f);
|
||||||
|
builder.addVertex(poseStack.last().pose(), sw, -sh, 0.505f).setUv(1.f, 1.f).setColor(1.f, 1.f, 1.f, 1.f);
|
||||||
|
builder.addVertex(poseStack.last().pose(), sw, sh, 0.505f).setUv(1.f, 0.f).setColor(1.f, 1.f, 1.f, 1.f);
|
||||||
|
builder.addVertex(poseStack.last().pose(), -sw, sh, 0.505f).setUv(0.f, 0.f).setColor(1.f, 1.f, 1.f, 1.f);
|
||||||
|
BufferUploader.drawWithShader(builder.buildOrThrow());//Minecraft does shit with mah texture otherwise...
|
||||||
|
RenderSystem.disableDepthTest();
|
||||||
|
|
||||||
|
// TODO: it'd be neat to draw a mouse cursor on the screen
|
||||||
|
// // debug hit2pixels
|
||||||
|
// HitResult result = Minecraft.getInstance().hitResult;
|
||||||
|
// VertexConsumer consumer = bufferSource.getBuffer(RenderType.lines());
|
||||||
|
// poseStack.translate(-sw, -sh, 0);
|
||||||
|
// if (result instanceof BlockHitResult hit) {
|
||||||
|
// BlockPos bpos = hit.getBlockPos();
|
||||||
|
//
|
||||||
|
// Vector3i pos = new Vector3i(hit.getBlockPos());
|
||||||
|
// float hitX = ((float) result.getLocation().x) - (float) te.getBlockPos().getX();
|
||||||
|
// float hitY = ((float) result.getLocation().y) - (float) te.getBlockPos().getY();
|
||||||
|
// float hitZ = ((float) result.getLocation().z) - (float) te.getBlockPos().getZ();
|
||||||
|
// Vector2i tmp = new Vector2i();
|
||||||
|
//
|
||||||
|
// if (BlockScreen.hit2pixels(scr.side, bpos, pos, scr, hitX, hitY, hitZ, tmp)) {
|
||||||
|
// float x = tmp.x / (float) scr.resolution.x * scr.size.x;
|
||||||
|
// float y = tmp.y / (float) scr.resolution.y * scr.size.y;
|
||||||
|
// y = scr.size.y - y;
|
||||||
|
//
|
||||||
|
// x /= scr.size.x;
|
||||||
|
// y /= scr.size.y;
|
||||||
|
// x *= sw * 2;
|
||||||
|
// y *= sh * 2;
|
||||||
|
//
|
||||||
|
// LevelRenderer.renderLineBox(
|
||||||
|
// poseStack,
|
||||||
|
// consumer, new AABB(
|
||||||
|
// x - 0.01, y - 0.01, 0.5 - 0.01,
|
||||||
|
// x + 0.01, y + 0.01, 0.5 + 0.01
|
||||||
|
// ),
|
||||||
|
// 1f, 0, 0, 1f
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// //Bounding box debugging
|
||||||
|
// poseStack.pushPose();
|
||||||
|
// poseStack.translate(-te.getBlockPos().getX(), -te.getBlockPos().getY(), -te.getBlockPos().getZ());
|
||||||
|
// LevelRenderer.renderLineBox(
|
||||||
|
// poseStack, bufferSource.getBuffer(RenderType.LINES),
|
||||||
|
// te.getRenderBoundingBox(), 1, 1, 1, 1f
|
||||||
|
// );
|
||||||
|
// poseStack.popPose();
|
||||||
|
|
||||||
|
//Re-enable lighting
|
||||||
|
// RenderSystem.enableCull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public net.minecraft.world.phys.AABB getRenderBoundingBox(ScreenBlockEntity blockEntity) {
|
||||||
|
return blockEntity.getRenderBB();
|
||||||
|
}
|
||||||
|
}
|
||||||
133
src/main/java/net/montoyo/wd/config/ClientConfig.java
Normal file
133
src/main/java/net/montoyo/wd/config/ClientConfig.java
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
package net.montoyo.wd.config;
|
||||||
|
|
||||||
|
import net.neoforged.fml.config.ModConfig;
|
||||||
|
import net.neoforged.fml.ModLoadingContext;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.config.annoconfg.AnnoCFG;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.format.*;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.value.Default;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.value.DoubleRange;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.value.IntRange;
|
||||||
|
|
||||||
|
@Config(type = ModConfig.Type.CLIENT)
|
||||||
|
public class ClientConfig {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static final AnnoCFG CFG = new AnnoCFG(ModLoadingContext.get().getActiveContainer().getEventBus(), ClientConfig.class);
|
||||||
|
public static void init() {
|
||||||
|
// loads the class
|
||||||
|
}
|
||||||
|
|
||||||
|
@Name("load_distance")
|
||||||
|
@Comment("How far (in blocks) you can be before a screen starts rendering")
|
||||||
|
@Translation("config.webdisplays.load_distance")
|
||||||
|
@DoubleRange(minV = 0, maxV = Double.MAX_VALUE)
|
||||||
|
@Default(valueD = 30)
|
||||||
|
public static double loadDistance = 30.0;
|
||||||
|
|
||||||
|
@Name("unload_distance")
|
||||||
|
@Comment("How far you can be before a screen stops rendering")
|
||||||
|
@Translation("config.webdisplays.unload_distance")
|
||||||
|
@DoubleRange(minV = 0, maxV = Double.MAX_VALUE)
|
||||||
|
@Default(valueD = 32)
|
||||||
|
public static double unloadDistance = 32.0;
|
||||||
|
|
||||||
|
@Name("pad_resolution")
|
||||||
|
@Comment({
|
||||||
|
"The resolution that minePads should use",
|
||||||
|
"Smaller values produce lower qualities, higher values produce higher qualities",
|
||||||
|
"Due to how web browsers work however, the larger this value is, the smaller text is",
|
||||||
|
"Also, higher values will invariably lag more",
|
||||||
|
"A good goto value for this would be the height of your monitor, in pixels",
|
||||||
|
"A standard monitor is (at least currently) 1080",
|
||||||
|
})
|
||||||
|
@Translation("config.webdisplays.pad_res")
|
||||||
|
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
|
||||||
|
@Default(valueI = 720)
|
||||||
|
public static int padResolution = 720;
|
||||||
|
|
||||||
|
@Name("side_pad")
|
||||||
|
@Comment({
|
||||||
|
"When this is true, the minePad is placed off to the side of the screen when held, so it's visible but doesn't take up too much of the screen",
|
||||||
|
"When this is false, the minePad is placed closer to the center of the screen, allow it to be seen better, but taking up more of your view",
|
||||||
|
})
|
||||||
|
@Translation("config.webdisplays.side_pad")
|
||||||
|
@Default(valueBoolean = true)
|
||||||
|
public static boolean sidePad = true;
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Options relating to input handling"
|
||||||
|
})
|
||||||
|
@CFGSegment("input")
|
||||||
|
public static class Input {
|
||||||
|
@Name("keyboard_camera")
|
||||||
|
@Comment({
|
||||||
|
"If this is on, then the camera will try to focus on the selected element while a keyboard is in use",
|
||||||
|
"Elsewise, it'll try to focus on the center of the screen",
|
||||||
|
})
|
||||||
|
@Translation("config.webdisplays.keyboard_camera")
|
||||||
|
@Default(valueBoolean = true)
|
||||||
|
public static boolean keyboardCamera = true;
|
||||||
|
|
||||||
|
@Name("switch_buttons")
|
||||||
|
@Comment("If the left and right buttons should be swapped when using a laser")
|
||||||
|
@Translation("config.webdisplays.switch_buttons")
|
||||||
|
@DoubleRange(minV = 0, maxV = Double.MAX_VALUE)
|
||||||
|
@Default(valueD = 30)
|
||||||
|
public static boolean switchButtons = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Comment({
|
||||||
|
// "AutoVolume makes audio fade off based on distance",
|
||||||
|
// "Currently, this seems to not work"
|
||||||
|
// })
|
||||||
|
// @CFGSegment("auto_volume")
|
||||||
|
// public static class AutoVolumeControl {
|
||||||
|
// @Name("enabled")
|
||||||
|
// @Comment("Whether or not auto volume should be enabled")
|
||||||
|
// @Translation("config.webdisplays.auto_vol")
|
||||||
|
// @Default(valueBoolean = true)
|
||||||
|
// public static boolean enableAutoVolume = true;
|
||||||
|
//
|
||||||
|
// @Name("youtube_volume")
|
||||||
|
// @Comment("How loud youtube should be by default")
|
||||||
|
// @Translation("config.webdisplays.yt_vol")
|
||||||
|
// @DoubleRange(minV = 0, maxV = 100)
|
||||||
|
// @Default(valueD = 100)
|
||||||
|
// public static double ytVolume = 100.0;
|
||||||
|
//
|
||||||
|
// @Name("dist0")
|
||||||
|
// @Comment("Distance after which you can't hear anything (in blocks)")
|
||||||
|
// @Translation("config.webdisplays.d0")
|
||||||
|
// @DoubleRange(minV = 0, maxV = Double.MAX_VALUE)
|
||||||
|
// @Default(valueD = 30)
|
||||||
|
// public static double dist0 = 30.0;
|
||||||
|
//
|
||||||
|
// @Name("dist100")
|
||||||
|
// @Comment("Distance after which the sound starts dropping (in blocks)")
|
||||||
|
// @Translation("config.webdisplays.d100")
|
||||||
|
// @DoubleRange(minV = 0, maxV = Double.MAX_VALUE)
|
||||||
|
// @Default(valueD = 10)
|
||||||
|
// public static double dist100 = 10.0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static void postLoad() {
|
||||||
|
if (unloadDistance < loadDistance + 2.0)
|
||||||
|
unloadDistance = loadDistance + 2.0;
|
||||||
|
|
||||||
|
// if (AutoVolumeControl.dist0 < AutoVolumeControl.dist100 + 0.1)
|
||||||
|
// AutoVolumeControl.dist0 = AutoVolumeControl.dist100 + 0.1;
|
||||||
|
|
||||||
|
// cache pad resolution
|
||||||
|
WebDisplays.INSTANCE.padResY = padResolution;
|
||||||
|
WebDisplays.INSTANCE.padResX = WebDisplays.INSTANCE.padResY * WebDisplays.PAD_RATIO;
|
||||||
|
|
||||||
|
// cache unload/load distances
|
||||||
|
WebDisplays.INSTANCE.unloadDistance2 = unloadDistance * unloadDistance;
|
||||||
|
WebDisplays.INSTANCE.loadDistance2 = loadDistance * loadDistance;
|
||||||
|
|
||||||
|
// WebDisplays.INSTANCE.ytVolume = (float) AutoVolumeControl.ytVolume;
|
||||||
|
// WebDisplays.INSTANCE.avDist100 = (float) AutoVolumeControl.dist100;
|
||||||
|
// WebDisplays.INSTANCE.avDist0 = (float) AutoVolumeControl.dist0;
|
||||||
|
}
|
||||||
|
}
|
||||||
127
src/main/java/net/montoyo/wd/config/CommonConfig.java
Normal file
127
src/main/java/net/montoyo/wd/config/CommonConfig.java
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package net.montoyo.wd.config;
|
||||||
|
|
||||||
|
import net.neoforged.fml.config.ModConfig;
|
||||||
|
import net.neoforged.fml.ModLoadingContext;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.config.annoconfg.AnnoCFG;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.format.*;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.value.Default;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.value.IntRange;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.value.LongRange;
|
||||||
|
|
||||||
|
@SuppressWarnings("DefaultAnnotationParam")
|
||||||
|
@Config(type = ModConfig.Type.COMMON)
|
||||||
|
public class CommonConfig {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static final AnnoCFG CFG = new AnnoCFG(ModLoadingContext.get().getActiveContainer().getEventBus(), CommonConfig.class);
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
// loads the class
|
||||||
|
}
|
||||||
|
|
||||||
|
@Name("hard_recipes")
|
||||||
|
@Comment("If true, breaking the minePad is required to craft upgrades.")
|
||||||
|
@Translation("config.webdisplays.hard_recipes")
|
||||||
|
@Default(valueBoolean = true)
|
||||||
|
public static boolean hardRecipes = true;
|
||||||
|
|
||||||
|
@Name("join_message")
|
||||||
|
@Comment("Whether or not webdisplays should thank the user for using the mod")
|
||||||
|
@Translation("config.webdisplays.join_message")
|
||||||
|
@Default(valueBoolean = true)
|
||||||
|
public static boolean joinMessage = true;
|
||||||
|
|
||||||
|
@Name("disable_ownership_thief")
|
||||||
|
@Comment("If true, the ownership thief item will be disabled")
|
||||||
|
@Translation("config.webdisplays.disable_thief")
|
||||||
|
@Default(valueBoolean = false)
|
||||||
|
public static boolean disableOwnershipThief = false;
|
||||||
|
|
||||||
|
@Comment("Options for the browsers (both the minePad and the screens)")
|
||||||
|
@CFGSegment("browser_options")
|
||||||
|
public static class Browser {
|
||||||
|
@Name("blacklist")
|
||||||
|
@Comment("The page which screens should open up to when turning on")
|
||||||
|
@Translation("config.webdisplays.blacklist")
|
||||||
|
@Default(valueStr = "")
|
||||||
|
public static String[] blacklist = new String[0];
|
||||||
|
|
||||||
|
@Name("home_page")
|
||||||
|
@Comment("The page which screens should open up to when turning on")
|
||||||
|
@Translation("config.webdisplays.home_page")
|
||||||
|
@Default(valueStr = "https://git.lnkos.cn")
|
||||||
|
public static String homepage = "https://git.lnkos.cn";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Comment("Options for the in world screen blocks")
|
||||||
|
@CFGSegment("screen_options")
|
||||||
|
public static class Screen {
|
||||||
|
@Name("max_resolution_x")
|
||||||
|
@Comment("The maximum value screen's horizontal resolution, in pixels")
|
||||||
|
@Translation("config.webdisplays.max_res_x")
|
||||||
|
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
|
||||||
|
@Default(valueI = 1920)
|
||||||
|
public static int maxResolutionX = 1920;
|
||||||
|
|
||||||
|
@Name("max_resolution_y")
|
||||||
|
@Comment("The maximum value screen's vertical resolution, in pixels")
|
||||||
|
@Translation("config.webdisplays.max_res_y")
|
||||||
|
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
|
||||||
|
@Default(valueI = 1080)
|
||||||
|
public static int maxResolutionY = 1080;
|
||||||
|
|
||||||
|
@Name("max_width")
|
||||||
|
@Comment("The maximum width for the screen multiblock, in blocks")
|
||||||
|
@Translation("config.webdisplays.max_width")
|
||||||
|
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
|
||||||
|
@Default(valueI = 16)
|
||||||
|
public static int maxScreenSizeX = 16;
|
||||||
|
|
||||||
|
@Name("max_height")
|
||||||
|
@Comment("The maximum height for the screen multiblock, in blocks")
|
||||||
|
@Translation("config.webdisplays.max_height")
|
||||||
|
@IntRange(minV = 0, maxV = Integer.MAX_VALUE)
|
||||||
|
@Default(valueI = 16)
|
||||||
|
public static int maxScreenSizeY = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Comment("Options for the miniserver")
|
||||||
|
@CFGSegment("mini_server")
|
||||||
|
public static class MiniServ {
|
||||||
|
@Name("miniserv_port")
|
||||||
|
@Comment("The port used by miniserv. 0 to disable")
|
||||||
|
@Translation("config.webdisplays.miniserv_port")
|
||||||
|
@IntRange(minV = 0, maxV = Short.MAX_VALUE)
|
||||||
|
@Default(valueI = 25566)
|
||||||
|
public static int miniservPort = 25566;
|
||||||
|
|
||||||
|
@Name("miniserv_quota")
|
||||||
|
@Comment("The amount of data that can be uploaded to miniserv, in KiB (so 1024 = 1 MiO)")
|
||||||
|
@Translation("config.webdisplays.miniserv_quota")
|
||||||
|
@LongRange(minV = 0, maxV = Long.MAX_VALUE)
|
||||||
|
@Default(valueL = 1920)
|
||||||
|
public static long miniservQuota = 1024; //It's stored as a string anyway
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static void postLoad() {
|
||||||
|
WebDisplays.INSTANCE.miniservPort = MiniServ.miniservPort;
|
||||||
|
WebDisplays.INSTANCE.miniservQuota = MiniServ.miniservQuota * 1024L;
|
||||||
|
}
|
||||||
|
|
||||||
|
// //Comments & shit
|
||||||
|
// blacklist.setComment("An array of domain names you don't want to load.");
|
||||||
|
// padHeight.setComment("The minePad Y resolution in pixels. padWidth = padHeight * " + PAD_RATIO);
|
||||||
|
// hardRecipe.setComment("If true, breaking the minePad is required to craft upgrades.");
|
||||||
|
// homePage.setComment("The URL that will be loaded each time you create a screen");
|
||||||
|
// disableOT.setComment("If true, the ownership thief item will be disabled");
|
||||||
|
// loadDistance.setComment("All screens outside this range will be unloaded");
|
||||||
|
// unloadDistance.setComment("All unloaded screens inside this range will be loaded");
|
||||||
|
// maxResX.setComment("Maximum horizontal screen resolution, in pixels");
|
||||||
|
// maxResY.setComment("Maximum vertical screen resolution, in pixels");
|
||||||
|
// miniservPort.setComment("The port used by miniserv. 0 to disable.");
|
||||||
|
// miniservPort.setMaxValue(Short.MAX_VALUE);
|
||||||
|
// miniservQuota.setComment("The amount of data that can be uploaded to miniserv, in KiB (so 1024 = 1 MiO)");
|
||||||
|
// maxScreenX.setComment("Maximum screen width, in blocks. Resolution will be clamped by maxResolutionX.");
|
||||||
|
// maxScreenY.setComment("Maximum screen height, in blocks. Resolution will be clamped by maxResolutionY.");
|
||||||
|
}
|
||||||
220
src/main/java/net/montoyo/wd/config/annoconfg/AnnoCFG.java
Normal file
220
src/main/java/net/montoyo/wd/config/annoconfg/AnnoCFG.java
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg;
|
||||||
|
|
||||||
|
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||||
|
import net.neoforged.bus.api.IEventBus;
|
||||||
|
import net.neoforged.fml.ModLoadingContext;
|
||||||
|
import net.neoforged.fml.config.ModConfig;
|
||||||
|
import net.neoforged.fml.event.config.ModConfigEvent;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.format.*;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.value.Default;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.value.DoubleRange;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.value.IntRange;
|
||||||
|
import net.montoyo.wd.config.annoconfg.annotation.value.LongRange;
|
||||||
|
import net.montoyo.wd.config.annoconfg.handle.UnsafeHandle;
|
||||||
|
import net.montoyo.wd.config.annoconfg.util.EnumType;
|
||||||
|
|
||||||
|
import java.lang.reflect.AnnotatedElement;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class AnnoCFG {
|
||||||
|
private ModConfigSpec mySpec;
|
||||||
|
|
||||||
|
private final HashMap<String, ConfigEntry> handles = new HashMap<>();
|
||||||
|
|
||||||
|
private static final ArrayList<AnnoCFG> configs = new ArrayList<>();
|
||||||
|
private final Method postInit;
|
||||||
|
|
||||||
|
public AnnoCFG(IEventBus bus, Class<?> clazz) {
|
||||||
|
bus.addListener(this::onConfigChange);
|
||||||
|
ModConfigSpec.Builder configBuilder = new ModConfigSpec.Builder();
|
||||||
|
setup("", configBuilder, clazz);
|
||||||
|
configs.add(this);
|
||||||
|
|
||||||
|
Method m = null;
|
||||||
|
try {
|
||||||
|
m = clazz.getDeclaredMethod("postLoad");
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
postInit = m;
|
||||||
|
|
||||||
|
Config configDescriptor = clazz.getAnnotation(Config.class);
|
||||||
|
if (configDescriptor != null) {
|
||||||
|
String pth = configDescriptor.path();
|
||||||
|
if (!pth.isEmpty()) pth = pth + "/";
|
||||||
|
switch (configDescriptor.type()) {
|
||||||
|
case SERVER -> create(ModConfig.Type.SERVER, pth + ModLoadingContext.get().getActiveNamespace() + "_server.toml");
|
||||||
|
case CLIENT -> create(ModConfig.Type.CLIENT, pth + ModLoadingContext.get().getActiveNamespace() + "_client.toml");
|
||||||
|
case COMMON -> create(ModConfig.Type.COMMON, pth + ModLoadingContext.get().getActiveNamespace() + "_common.toml");
|
||||||
|
default -> throw new RuntimeException("wat");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setupCommentsAndTranslations(AnnotatedElement element, ModConfigSpec.Builder builder, String... additionalLines) {
|
||||||
|
Translation translation = element.getAnnotation(Translation.class);
|
||||||
|
Comment comment = element.getAnnotation(Comment.class);
|
||||||
|
|
||||||
|
StringBuilder builder1 = new StringBuilder();
|
||||||
|
if (comment != null) {
|
||||||
|
for (int i = 0; i < comment.value().length; i++) {
|
||||||
|
String s = comment.value()[i];
|
||||||
|
builder1.append(s);
|
||||||
|
if (i != comment.value().length - 1)
|
||||||
|
builder1.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String additionalLine : additionalLines) builder1.append(additionalLine);
|
||||||
|
if (!builder1.isEmpty())
|
||||||
|
builder.comment(builder1.toString());
|
||||||
|
|
||||||
|
if (translation != null)
|
||||||
|
builder.translation(translation.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setup(String dir, ModConfigSpec.Builder builder, Class<?> clazz) {
|
||||||
|
if (dir.startsWith(".")) dir = dir.substring(1);
|
||||||
|
|
||||||
|
for (Field field : clazz.getFields()) {
|
||||||
|
if (field.canAccess(null)) {
|
||||||
|
Skip skip = field.getAnnotation(Skip.class);
|
||||||
|
if (skip != null) continue;
|
||||||
|
|
||||||
|
Name name = field.getAnnotation(Name.class);
|
||||||
|
|
||||||
|
String nameStr = field.getName();
|
||||||
|
if (name != null) nameStr = name.value();
|
||||||
|
|
||||||
|
setupCommentsAndTranslations(field, builder);
|
||||||
|
|
||||||
|
Supplier<?> value;
|
||||||
|
|
||||||
|
Default defaultValue = field.getAnnotation(Default.class);
|
||||||
|
try {
|
||||||
|
switch (EnumType.forClass(field.getType())) {
|
||||||
|
case INT -> {
|
||||||
|
IntRange range = field.getAnnotation(IntRange.class);
|
||||||
|
int v = defaultValue.valueI();
|
||||||
|
if (range != null) {
|
||||||
|
int min = range.minV();
|
||||||
|
int max = range.maxV();
|
||||||
|
|
||||||
|
value = builder.defineInRange(nameStr, v, min, max);
|
||||||
|
} else {
|
||||||
|
value = builder.define(nameStr, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case LONG -> {
|
||||||
|
LongRange range = field.getAnnotation(LongRange.class);
|
||||||
|
long v = defaultValue.valueL();
|
||||||
|
if (range != null) {
|
||||||
|
long min = range.minV();
|
||||||
|
long max = range.maxV();
|
||||||
|
|
||||||
|
value = builder.defineInRange(nameStr, v, min, max);
|
||||||
|
} else {
|
||||||
|
value = builder.define(nameStr, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case DOUBLE -> {
|
||||||
|
DoubleRange range = field.getAnnotation(DoubleRange.class);
|
||||||
|
double v = defaultValue.valueD();
|
||||||
|
if (range != null) {
|
||||||
|
double min = range.minV();
|
||||||
|
double max = range.maxV();
|
||||||
|
|
||||||
|
value = builder.defineInRange(nameStr, v, min, max);
|
||||||
|
} else {
|
||||||
|
value = builder.define(nameStr, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case BOOLEAN -> {
|
||||||
|
boolean b = defaultValue.valueBoolean();
|
||||||
|
value = builder.define(nameStr, b);
|
||||||
|
}
|
||||||
|
case OTHER -> {
|
||||||
|
Class<?> fieldType = field.getType();
|
||||||
|
if (fieldType.equals(String[].class)) {
|
||||||
|
Supplier<String> sup = builder.define(nameStr, defaultValue.valueStr());
|
||||||
|
value = () -> {
|
||||||
|
String v = sup.get();
|
||||||
|
return v.split(",");
|
||||||
|
};
|
||||||
|
} else if (fieldType.equals(String.class)) {
|
||||||
|
value = builder.define(nameStr, defaultValue.valueStr());
|
||||||
|
} else
|
||||||
|
throw new RuntimeException("NYI " + field.getType());
|
||||||
|
}
|
||||||
|
default -> throw new RuntimeException("NYI " + field.getType());
|
||||||
|
}
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
String inf = "";
|
||||||
|
if (npe.getMessage().contains("\"value.Default\""))
|
||||||
|
inf = " this is likely due to a missing default.";
|
||||||
|
throw new RuntimeException("A null pointer occurred on " + field.getName() + inf, npe);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object o;
|
||||||
|
try {
|
||||||
|
// without this line, this system freaks out due to using theUnsafe
|
||||||
|
//noinspection UnusedAssignment
|
||||||
|
o = field.get(null);
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
UnsafeHandle handle = new UnsafeHandle(field);
|
||||||
|
o = handle.get();
|
||||||
|
handle.set(o);
|
||||||
|
|
||||||
|
//noinspection FunctionalExpressionCanBeFolded
|
||||||
|
handles.put(dir + "." + nameStr, new ConfigEntry(
|
||||||
|
handle, value::get
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if the nested class is a direct nesting
|
||||||
|
for (Class<?> nestMember : clazz.getClasses()) {
|
||||||
|
if (nestMember == clazz) continue;
|
||||||
|
if (!nestMember.getName().startsWith(clazz.getName())) continue;
|
||||||
|
CFGSegment segment = nestMember.getAnnotation(CFGSegment.class);
|
||||||
|
if (segment == null) {
|
||||||
|
System.out.println(nestMember);
|
||||||
|
throw new RuntimeException("NYI: default name");
|
||||||
|
}
|
||||||
|
String name = segment.value();
|
||||||
|
|
||||||
|
setupCommentsAndTranslations(nestMember, builder);
|
||||||
|
|
||||||
|
builder.push(name);
|
||||||
|
setup(dir + "." + name, builder, nestMember);
|
||||||
|
builder.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
mySpec = builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onConfigChange(ModConfigEvent event) {
|
||||||
|
if (
|
||||||
|
event.getConfig().getSpec().equals(mySpec) ||
|
||||||
|
event.getConfig().getSpec() == mySpec
|
||||||
|
) {
|
||||||
|
for (String s : handles.keySet()) {
|
||||||
|
ConfigEntry entry = handles.get(s);
|
||||||
|
entry.handle.set(entry.supplier.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
postInit.invoke(null);
|
||||||
|
} catch (Throwable err) {
|
||||||
|
err.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void create(ModConfig.Type type, String file) {
|
||||||
|
// NeoForge 1.21+: 注册配置通过 ModContainer,文件名使用默认命名约定
|
||||||
|
ModLoadingContext.get().getActiveContainer().registerConfig(type, mySpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg;
|
||||||
|
|
||||||
|
import net.montoyo.wd.config.annoconfg.handle.UnsafeHandle;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ConfigEntry {
|
||||||
|
UnsafeHandle handle;
|
||||||
|
Supplier<?> supplier;
|
||||||
|
|
||||||
|
public ConfigEntry(UnsafeHandle handle, Supplier<?> supplier) {
|
||||||
|
this.handle = handle;
|
||||||
|
this.supplier = supplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.annotation.format;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface CFGSegment {
|
||||||
|
String value();
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.annotation.format;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Comment {
|
||||||
|
String[] value();
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.annotation.format;
|
||||||
|
|
||||||
|
import net.neoforged.fml.config.ModConfig;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Config {
|
||||||
|
ModConfig.Type type();
|
||||||
|
String path() default "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.annotation.format;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Name {
|
||||||
|
String value();
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.annotation.format;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Skip {
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.annotation.format;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Translation {
|
||||||
|
String value();
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.annotation.value;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Default {
|
||||||
|
byte valueB() default 0;
|
||||||
|
short valueS() default 0;
|
||||||
|
int valueI() default 0;
|
||||||
|
long valueL() default 0;
|
||||||
|
float valueF() default 0;
|
||||||
|
double valueD() default 0;
|
||||||
|
boolean valueBoolean() default false;
|
||||||
|
String valueStr() default "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.annotation.value;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface DoubleRange {
|
||||||
|
double minV();
|
||||||
|
double maxV();
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.annotation.value;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface IntRange {
|
||||||
|
int minV();
|
||||||
|
int maxV();
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.annotation.value;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface LongRange {
|
||||||
|
long minV();
|
||||||
|
long maxV();
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.handle;
|
||||||
|
|
||||||
|
import net.montoyo.wd.config.annoconfg.util.EnumType;
|
||||||
|
import sun.misc.Unsafe;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class UnsafeHandle {
|
||||||
|
private static final Unsafe theUnsafe;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Field f = Unsafe.class.getDeclaredField("theUnsafe");
|
||||||
|
f.setAccessible(true);
|
||||||
|
theUnsafe = (Unsafe) f.get(null);
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
throw new RuntimeException("AnnoConfg: Failed to acquire an instance of the unsafe.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final long offset;
|
||||||
|
|
||||||
|
private final Consumer<Object> uploader;
|
||||||
|
private final Supplier<Object> getter;
|
||||||
|
|
||||||
|
public UnsafeHandle(Field f) {
|
||||||
|
this(null, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnsafeHandle(Object relative, Field f) {
|
||||||
|
offset = theUnsafe.staticFieldOffset(f);
|
||||||
|
if (relative == null) relative = theUnsafe.staticFieldBase(f);
|
||||||
|
Object finalRelative = relative;
|
||||||
|
if (f.getType().isPrimitive()) {
|
||||||
|
switch (EnumType.forClass(f.getType())) {
|
||||||
|
case BYTE -> {
|
||||||
|
uploader = (v) -> theUnsafe.putByte(finalRelative, offset, (byte) v);
|
||||||
|
getter = () -> theUnsafe.getByte(finalRelative, offset);
|
||||||
|
}
|
||||||
|
case SHORT -> {
|
||||||
|
uploader = (v) -> theUnsafe.putShort(finalRelative, offset, (short) v);
|
||||||
|
getter = () -> theUnsafe.getShort(finalRelative, offset);
|
||||||
|
}
|
||||||
|
case INT -> {
|
||||||
|
uploader = (v) -> theUnsafe.putInt(finalRelative, offset, (int) v);
|
||||||
|
getter = () -> theUnsafe.getInt(finalRelative, offset);
|
||||||
|
}
|
||||||
|
case LONG -> {
|
||||||
|
uploader = (v) -> theUnsafe.putLong(finalRelative, offset, (long) v);
|
||||||
|
getter = () -> theUnsafe.getLong(finalRelative, offset);
|
||||||
|
}
|
||||||
|
case FLOAT -> {
|
||||||
|
uploader = (v) -> theUnsafe.putFloat(finalRelative, offset, (float) v);
|
||||||
|
getter = () -> theUnsafe.getFloat(finalRelative, offset);
|
||||||
|
}
|
||||||
|
case DOUBLE -> {
|
||||||
|
uploader = (v) -> theUnsafe.putDouble(finalRelative, offset, (double) v);
|
||||||
|
getter = () -> theUnsafe.getDouble(finalRelative, offset);
|
||||||
|
}
|
||||||
|
case BOOLEAN -> {
|
||||||
|
uploader = (v) -> theUnsafe.putBoolean(finalRelative, offset, (boolean) v);
|
||||||
|
getter = () -> theUnsafe.getBoolean(finalRelative, offset);
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
// TODO: check that I have all primitives?
|
||||||
|
uploader = null;
|
||||||
|
getter = () -> null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uploader = (v) -> theUnsafe.putObject(finalRelative, offset, v);
|
||||||
|
getter = () -> theUnsafe.getObject(finalRelative, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(Object o) {
|
||||||
|
uploader.accept(o);
|
||||||
|
// System.out.println(getter.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get() {
|
||||||
|
return getter.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package net.montoyo.wd.config.annoconfg.util;
|
||||||
|
|
||||||
|
public enum EnumType {
|
||||||
|
BYTE(byte.class),
|
||||||
|
SHORT(short.class),
|
||||||
|
INT(int.class),
|
||||||
|
LONG(long.class),
|
||||||
|
FLOAT(float.class),
|
||||||
|
DOUBLE(double.class),
|
||||||
|
BOOLEAN(boolean.class),
|
||||||
|
OTHER(Object.class),
|
||||||
|
;
|
||||||
|
|
||||||
|
Class<?> clazz;
|
||||||
|
|
||||||
|
EnumType(Class<?> clazz) {
|
||||||
|
this.clazz = clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EnumType forClass(Class<?> clazz) {
|
||||||
|
for (EnumType value : EnumType.values())
|
||||||
|
if (value.clazz.equals(clazz)) return value;
|
||||||
|
return OTHER;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/main/java/net/montoyo/wd/controls/ScreenControl.java
Normal file
38
src/main/java/net/montoyo/wd/controls/ScreenControl.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package net.montoyo.wd.controls;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public abstract class ScreenControl {
|
||||||
|
private final ResourceLocation id;
|
||||||
|
|
||||||
|
public ScreenControl(ResourceLocation id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void write(FriendlyByteBuf buf);
|
||||||
|
public abstract void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException;
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public abstract void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx);
|
||||||
|
|
||||||
|
public void checkPerms(int perms, Function<Integer, Boolean> checker, ServerPlayer player) throws MissingPermissionException {
|
||||||
|
if (!checker.apply(perms)) {
|
||||||
|
throw new MissingPermissionException(perms, Objects.requireNonNull(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final ResourceLocation getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package net.montoyo.wd.controls;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.fml.loading.FMLEnvironment;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.controls.builtin.*;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
// TODO: enable deferred registry of these
|
||||||
|
public class ScreenControlRegistry {
|
||||||
|
private static final HashMap<ResourceLocation, ScreenControlType<?>> CONTROL_TYPES = new HashMap<>();
|
||||||
|
|
||||||
|
public static void register(ResourceLocation name, ScreenControlType<?> type) {
|
||||||
|
if (CONTROL_TYPES.containsKey(name)) {
|
||||||
|
Log.warning("ScreenControlRegistry#CONTROL_TYPES already contains an entry with name " + name);
|
||||||
|
throw new IllegalArgumentException("Cannot have two entries with the same name.");
|
||||||
|
}
|
||||||
|
CONTROL_TYPES.put(name, type);
|
||||||
|
|
||||||
|
// lil thing for sanity
|
||||||
|
// avoids the pain the dist cleaner causes, hopefully
|
||||||
|
if (!FMLEnvironment.production) {
|
||||||
|
if (FMLEnvironment.dist.isClient()) {
|
||||||
|
boolean shouldThrow = false;
|
||||||
|
try {
|
||||||
|
Method m = type.clazz.getMethod("handleClient", BlockPos.class, BlockSide.class, ScreenBlockEntity.class, IPayloadContext.class);
|
||||||
|
OnlyIn onlyIn = m.getAnnotation(OnlyIn.class);
|
||||||
|
if (onlyIn == null) shouldThrow = true;
|
||||||
|
Dist d = onlyIn.value(); // idc if this throws, lol
|
||||||
|
if (d != Dist.CLIENT) shouldThrow = true;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
if (shouldThrow) {
|
||||||
|
Log.warning("handleClient on ScreenControl classes MUST be marked with `@OnlyIn(Dist.CLIENT)`, but it is not on " + type.clazz);
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"handleClient on ScreenControl classes MUST be marked with `@OnlyIn(Dist.CLIENT)`, but it is not on " + type.clazz
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if needed, the old code
|
||||||
|
// https://github.com/Mysticpasta1/webdisplays/blob/ff55cbf1b27773c15f44f17ad3364da3a16b6ed9/src/main/java/net/montoyo/wd/net/server/SMessageScreenCtrl.java#L281-L364
|
||||||
|
// https://github.com/Mysticpasta1/webdisplays/blob/5ce9e4574df356910645b0382628f74d1401e26d/src/main/java/net/montoyo/wd/net/client_bound/S2CMessageScreenUpdate.java#L261-L284
|
||||||
|
static {
|
||||||
|
register(SetURLControl.id, new ScreenControlType<>(SetURLControl.class, SetURLControl::new));
|
||||||
|
register(KeyTypedControl.id, new ScreenControlType<>(KeyTypedControl.class, KeyTypedControl::new));
|
||||||
|
register(AutoVolumeControl.id, new ScreenControlType<>(AutoVolumeControl.class, AutoVolumeControl::new));
|
||||||
|
register(JSRequestControl.id, new ScreenControlType<>(JSRequestControl.class, JSRequestControl::new));
|
||||||
|
register(LaserControl.id, new ScreenControlType<>(LaserControl.class, LaserControl::new));
|
||||||
|
register(ScreenModifyControl.id, new ScreenControlType<>(ScreenModifyControl.class, ScreenModifyControl::new));
|
||||||
|
register(ModifyFriendListControl.id, new ScreenControlType<>(ModifyFriendListControl.class, ModifyFriendListControl::new));
|
||||||
|
register(ManageRightsAndUpdgradesControl.id, new ScreenControlType<ManageRightsAndUpdgradesControl>(ManageRightsAndUpdgradesControl.class, (FriendlyByteBuf buf) -> new ManageRightsAndUpdgradesControl(buf)));
|
||||||
|
register(ClickControl.id, new ScreenControlType<>(ClickControl.class, ClickControl::new));
|
||||||
|
register(OwnerControl.id, new ScreenControlType<>(OwnerControl.class, OwnerControl::new));
|
||||||
|
register(TurnOffControl.id, new ScreenControlType<>(TurnOffControl.class, (buf) -> TurnOffControl.INSTANCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScreenControl parse(FriendlyByteBuf buf) {
|
||||||
|
return CONTROL_TYPES.get(ResourceLocation.parse(buf.readUtf()))
|
||||||
|
.deserialize(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
/* NO-OP: allows static init to run during mod init in dev env */
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/main/java/net/montoyo/wd/controls/ScreenControlType.java
Normal file
19
src/main/java/net/montoyo/wd/controls/ScreenControlType.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package net.montoyo.wd.controls;
|
||||||
|
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ScreenControlType<T extends ScreenControl> {
|
||||||
|
Class<T> clazz;
|
||||||
|
Function<FriendlyByteBuf, T> deserializer;
|
||||||
|
|
||||||
|
public ScreenControlType(Class<T> clazz, Function<FriendlyByteBuf, T> deserializer) {
|
||||||
|
this.clazz = clazz;
|
||||||
|
this.deserializer = deserializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScreenControl deserialize(FriendlyByteBuf buf) {
|
||||||
|
return deserializer.apply(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.core.ScreenRights;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class AutoVolumeControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "auto_volume");
|
||||||
|
|
||||||
|
boolean autoVol;
|
||||||
|
|
||||||
|
public AutoVolumeControl(boolean autoVol) {
|
||||||
|
super(id);
|
||||||
|
this.autoVol = autoVol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutoVolumeControl(FriendlyByteBuf buf) {
|
||||||
|
super(id);
|
||||||
|
autoVol = buf.readBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
buf.writeBoolean(autoVol);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
// I feel like there's probably a better permission category
|
||||||
|
checkPerms(ScreenRights.MANAGE_UPGRADES, permissionChecker, (ServerPlayer) ctx.player());
|
||||||
|
tes.setAutoVolume(side, autoVol);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
tes.setAutoVolume(side, autoVol);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector2i;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ClickControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "click");
|
||||||
|
|
||||||
|
public enum ControlType {
|
||||||
|
CLICK, MOVE, DOWN, UP
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlType type;
|
||||||
|
Vector2i coord;
|
||||||
|
|
||||||
|
public ClickControl(ControlType type, Vector2i coord) {
|
||||||
|
this(type, coord, -1);
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClickControl(ControlType type, Vector2i coord, int button) {
|
||||||
|
super(id);
|
||||||
|
this.coord = coord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClickControl(FriendlyByteBuf buf) {
|
||||||
|
super(id);
|
||||||
|
type = ControlType.values()[buf.readByte()];
|
||||||
|
coord = new Vector2i(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
buf.writeByte(type.ordinal());
|
||||||
|
coord.writeTo(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
throw new RuntimeException("Cannot call click control on server");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
if (coord != null)
|
||||||
|
tes.handleMouseEvent(side, ClickControl.ControlType.MOVE, coord, -1);
|
||||||
|
|
||||||
|
tes.handleMouseEvent(side, type, coord, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.JSServerRequest;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class JSRequestControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "js_req");
|
||||||
|
|
||||||
|
int reqId;
|
||||||
|
JSServerRequest reqType;
|
||||||
|
Object[] data;
|
||||||
|
|
||||||
|
public JSRequestControl(int reqId, JSServerRequest reqType, Object[] data) {
|
||||||
|
super(id);
|
||||||
|
this.reqId = reqId;
|
||||||
|
this.reqType = reqType;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSRequestControl(FriendlyByteBuf buf) {
|
||||||
|
super(id);
|
||||||
|
reqId = buf.readInt();
|
||||||
|
reqType = JSServerRequest.fromID(buf.readByte());
|
||||||
|
|
||||||
|
if (reqType != null)
|
||||||
|
data = reqType.deserialize(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
buf.writeInt(reqId);
|
||||||
|
buf.writeByte(reqType.ordinal());
|
||||||
|
|
||||||
|
if (!reqType.serialize(buf, data))
|
||||||
|
throw new RuntimeException("Could not serialize CTRL_JS_REQUEST " + reqType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
ServerPlayer player = (ServerPlayer) ctx.player();
|
||||||
|
// if (reqType == null || data == null) Log.warning("Caught invalid JS request from player %s (UUID %s)", player.getName(), player.getGameProfile().getId().toString());
|
||||||
|
// else tes.handleJSRequest(player, side, reqId, reqType, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
throw new RuntimeException("TODO");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.core.ScreenRights;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class KeyTypedControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "type");
|
||||||
|
|
||||||
|
String text;
|
||||||
|
BlockPos soundPos;
|
||||||
|
|
||||||
|
public KeyTypedControl(String text, BlockPos soundPos) {
|
||||||
|
super(id);
|
||||||
|
this.text = text;
|
||||||
|
this.soundPos = soundPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyTypedControl(FriendlyByteBuf buf) {
|
||||||
|
super(id);
|
||||||
|
text = buf.readUtf();
|
||||||
|
soundPos = buf.readBlockPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
buf.writeUtf(text);
|
||||||
|
buf.writeBlockPos(soundPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
ServerPlayer player = (ServerPlayer) ctx.player();
|
||||||
|
checkPerms(ScreenRights.INTERACT, permissionChecker, player);
|
||||||
|
tes.type(side, text, soundPos, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
tes.type(side, text, soundPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector2i;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class LaserControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "laser");
|
||||||
|
|
||||||
|
public enum ControlType {
|
||||||
|
MOVE, DOWN, UP
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlType type;
|
||||||
|
Vector2i coord;
|
||||||
|
int button;
|
||||||
|
|
||||||
|
public LaserControl(ControlType type, Vector2i coord) {
|
||||||
|
this(type, coord, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LaserControl(ControlType type, Vector2i coord, int button) {
|
||||||
|
super(id);
|
||||||
|
this.type = type;
|
||||||
|
this.coord = coord;
|
||||||
|
this.button = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LaserControl(FriendlyByteBuf buf) {
|
||||||
|
super(id);
|
||||||
|
type = ControlType.values()[buf.readByte()];
|
||||||
|
if (!type.equals(ControlType.UP))
|
||||||
|
coord = new Vector2i(buf);
|
||||||
|
if (!type.equals(ControlType.MOVE))
|
||||||
|
button = buf.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
buf.writeByte(type.ordinal());
|
||||||
|
if (coord != null) coord.writeTo(buf);
|
||||||
|
if (type != ControlType.MOVE) buf.writeInt(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
// feel like this makes sense, but I wanna get opinions first
|
||||||
|
// checkPerms(ScreenRights.INTERACT, permissionChecker, (ServerPlayer) ctx.player());
|
||||||
|
ServerPlayer sender = (ServerPlayer) ctx.player();
|
||||||
|
switch (type) {
|
||||||
|
case UP -> tes.laserUp(side, sender, button);
|
||||||
|
case DOWN -> tes.laserDownMove(side, sender, coord, true, button);
|
||||||
|
case MOVE -> tes.laserDownMove(side, sender, coord, false, button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
if (coord != null)
|
||||||
|
tes.handleMouseEvent(side, ClickControl.ControlType.MOVE, coord, -1);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case UP -> tes.handleMouseEvent(side, ClickControl.ControlType.UP, coord, button);
|
||||||
|
case DOWN -> tes.handleMouseEvent(side, ClickControl.ControlType.DOWN, coord, button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.core.ScreenRights;
|
||||||
|
import net.montoyo.wd.entity.ScreenData;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: I'm considering merging this with {@link ModifyFriendListControl} to make ManageScreenControl
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public class ManageRightsAndUpdgradesControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "mod_rights_upgrades");
|
||||||
|
|
||||||
|
public enum ControlType {
|
||||||
|
RIGHTS, UPGRADES
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlType type;
|
||||||
|
boolean adding;
|
||||||
|
ItemStack toRemove;
|
||||||
|
|
||||||
|
private int friendRights;
|
||||||
|
private int otherRights;
|
||||||
|
|
||||||
|
public ManageRightsAndUpdgradesControl(boolean adding, ItemStack toRemove) {
|
||||||
|
super(id);
|
||||||
|
this.adding = adding;
|
||||||
|
type = ControlType.UPGRADES;
|
||||||
|
this.toRemove = toRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ManageRightsAndUpdgradesControl(int friendRights, int otherRights) {
|
||||||
|
super(id);
|
||||||
|
type = ControlType.RIGHTS;
|
||||||
|
this.friendRights = friendRights;
|
||||||
|
this.otherRights = otherRights;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ManageRightsAndUpdgradesControl(FriendlyByteBuf buf) {
|
||||||
|
super(id);
|
||||||
|
type = ControlType.values()[buf.readByte()];
|
||||||
|
switch (type) {
|
||||||
|
case UPGRADES -> {
|
||||||
|
adding = buf.readBoolean();
|
||||||
|
toRemove = ItemStack.STREAM_CODEC.decode((RegistryFriendlyByteBuf) buf);
|
||||||
|
}
|
||||||
|
case RIGHTS -> {
|
||||||
|
friendRights = buf.readInt();
|
||||||
|
otherRights = buf.readInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
buf.writeByte(type.ordinal());
|
||||||
|
switch (type) {
|
||||||
|
case UPGRADES -> {
|
||||||
|
buf.writeBoolean(adding);
|
||||||
|
ItemStack.STREAM_CODEC.encode((RegistryFriendlyByteBuf) buf, toRemove);
|
||||||
|
}
|
||||||
|
case RIGHTS -> {
|
||||||
|
buf.writeInt(friendRights);
|
||||||
|
buf.writeInt(otherRights);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
ServerPlayer player = (ServerPlayer) ctx.player();
|
||||||
|
switch (type) {
|
||||||
|
case UPGRADES -> {
|
||||||
|
checkPerms(ScreenRights.MANAGE_UPGRADES, permissionChecker, player);
|
||||||
|
if (adding)
|
||||||
|
throw new RuntimeException("Cannot add an upgrade from the client");
|
||||||
|
else tes.removeUpgrade(side, toRemove, player);
|
||||||
|
}
|
||||||
|
case RIGHTS -> {
|
||||||
|
ScreenData scr = tes.getScreen(side);
|
||||||
|
|
||||||
|
int fr = scr.owner.uuid.equals(player.getGameProfile().getId()) ? friendRights : scr.friendRights;
|
||||||
|
int or = (scr.rightsFor(player) & ScreenRights.MANAGE_OTHER_RIGHTS) == 0 ? scr.otherRights : otherRights;
|
||||||
|
|
||||||
|
if(scr.friendRights != fr || scr.otherRights != or)
|
||||||
|
tes.setRights(player, side, fr, or);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
ServerPlayer player = (ServerPlayer) ctx.player();
|
||||||
|
switch (type) {
|
||||||
|
case UPGRADES -> {
|
||||||
|
if (adding)
|
||||||
|
tes.addUpgrade(side, toRemove, player, true);
|
||||||
|
else tes.removeUpgrade(side, toRemove, player);
|
||||||
|
}
|
||||||
|
case RIGHTS -> {
|
||||||
|
ScreenData scr = tes.getScreen(side);
|
||||||
|
|
||||||
|
int fr = friendRights;
|
||||||
|
int or = otherRights;
|
||||||
|
|
||||||
|
if(scr.friendRights != fr || scr.otherRights != or)
|
||||||
|
tes.setRights(player, side, fr, or);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.core.ScreenRights;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.serialization.NameUUIDPair;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ModifyFriendListControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "mod_friend_list");
|
||||||
|
|
||||||
|
boolean adding;
|
||||||
|
NameUUIDPair friend;
|
||||||
|
|
||||||
|
public ModifyFriendListControl(NameUUIDPair pair, boolean adding) {
|
||||||
|
super(id);
|
||||||
|
this.adding = adding;
|
||||||
|
this.friend = pair;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModifyFriendListControl(FriendlyByteBuf buf) {
|
||||||
|
super(id);
|
||||||
|
adding = buf.readBoolean();
|
||||||
|
friend = new NameUUIDPair(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
buf.writeBoolean(adding);
|
||||||
|
friend.writeTo(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
ServerPlayer player = (ServerPlayer) ctx.player();
|
||||||
|
checkPerms(ScreenRights.MANAGE_FRIEND_LIST, permissionChecker, player);
|
||||||
|
if (adding) tes.addFriend(player, side, friend);
|
||||||
|
else tes.removeFriend(player, side, friend);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
throw new RuntimeException("TODO");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.serialization.NameUUIDPair;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class OwnerControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "set_owner");
|
||||||
|
|
||||||
|
NameUUIDPair owner;
|
||||||
|
|
||||||
|
public OwnerControl(NameUUIDPair pair) {
|
||||||
|
super(id);
|
||||||
|
this.owner = pair;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OwnerControl(FriendlyByteBuf buf) {
|
||||||
|
super(id);
|
||||||
|
owner = new NameUUIDPair(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
owner.writeTo(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
throw new RuntimeException("Cannot handle ownership theft packet from server");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
tes.getScreen(side).owner = owner;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.core.ScreenRights;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.data.Rotation;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector2i;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ScreenModifyControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "mod_screen");
|
||||||
|
|
||||||
|
public enum ControlType {
|
||||||
|
RESOLUTION, ROTATION
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlType type;
|
||||||
|
Vector2i res;
|
||||||
|
Rotation rotation;
|
||||||
|
|
||||||
|
public ScreenModifyControl(Vector2i res) {
|
||||||
|
super(id);
|
||||||
|
this.type = ControlType.RESOLUTION;
|
||||||
|
this.res = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScreenModifyControl(Rotation rotation) {
|
||||||
|
super(id);
|
||||||
|
this.type = ControlType.ROTATION;
|
||||||
|
this.rotation = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScreenModifyControl(FriendlyByteBuf buf) {
|
||||||
|
super(id);
|
||||||
|
type = ControlType.values()[buf.readByte()];
|
||||||
|
if (type.equals(ControlType.RESOLUTION))
|
||||||
|
res = new Vector2i(buf);
|
||||||
|
else rotation = Rotation.values()[buf.readByte()];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
buf.writeByte(type.ordinal());
|
||||||
|
if (res != null) res.writeTo(buf);
|
||||||
|
else if (rotation != null) buf.writeByte(rotation.ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
checkPerms(ScreenRights.MODIFY_SCREEN, permissionChecker, (ServerPlayer) ctx.player());
|
||||||
|
switch (type) {
|
||||||
|
case RESOLUTION -> tes.setResolution(side, res);
|
||||||
|
case ROTATION -> tes.setRotation(side, rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
switch (type) {
|
||||||
|
case RESOLUTION -> tes.setResolution(side, res);
|
||||||
|
case ROTATION -> tes.setRotation(side, rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.core.ScreenRights;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class SetURLControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "set_url");
|
||||||
|
|
||||||
|
String url;
|
||||||
|
Vector3i remoteLocation;
|
||||||
|
|
||||||
|
public SetURLControl(String url, Vector3i remoteLocation) {
|
||||||
|
super(id);
|
||||||
|
this.url = url;
|
||||||
|
this.remoteLocation = remoteLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetURLControl(FriendlyByteBuf buf) {
|
||||||
|
super(id);
|
||||||
|
url = buf.readUtf();
|
||||||
|
if (buf.readBoolean()) remoteLocation = new Vector3i(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
buf.writeUtf(url);
|
||||||
|
buf.writeBoolean(remoteLocation != null);
|
||||||
|
if (remoteLocation != null) remoteLocation.writeTo(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
// TODO: deal with remote
|
||||||
|
checkPerms(ScreenRights.CHANGE_URL, permissionChecker, (ServerPlayer) ctx.player());
|
||||||
|
try {
|
||||||
|
tes.setScreenURL(side, url);
|
||||||
|
} catch (Throwable err) {
|
||||||
|
err.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
try {
|
||||||
|
tes.setScreenURL(side, url);
|
||||||
|
} catch (Throwable err) {
|
||||||
|
err.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package net.montoyo.wd.controls.builtin;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.controls.ScreenControl;
|
||||||
|
import net.montoyo.wd.core.MissingPermissionException;
|
||||||
|
import net.montoyo.wd.entity.ScreenBlockEntity;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class TurnOffControl extends ScreenControl {
|
||||||
|
public static final ResourceLocation id = ResourceLocation.fromNamespaceAndPath("webdisplays", "deactivate");
|
||||||
|
|
||||||
|
public static final TurnOffControl INSTANCE = new TurnOffControl();
|
||||||
|
|
||||||
|
public TurnOffControl() {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FriendlyByteBuf buf) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleServer(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx, Function<Integer, Boolean> permissionChecker) throws MissingPermissionException {
|
||||||
|
throw new RuntimeException("Cannot handle deactivation packet from server");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void handleClient(BlockPos pos, BlockSide side, ScreenBlockEntity tes, IPayloadContext ctx) {
|
||||||
|
if (side != null) {
|
||||||
|
WebDisplays.PROXY.closeGui(pos, side);
|
||||||
|
tes.disableScreen(side);
|
||||||
|
} else {
|
||||||
|
for (BlockSide value : BlockSide.values()) {
|
||||||
|
WebDisplays.PROXY.closeGui(pos, value);
|
||||||
|
tes.disableScreen(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
src/main/java/net/montoyo/wd/core/CCArguments.java
Normal file
91
src/main/java/net/montoyo/wd/core/CCArguments.java
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.core;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
// TODO: bring this back when SSR is implemented
|
||||||
|
public class CCArguments implements IComputerArgs {
|
||||||
|
|
||||||
|
private final Object[] args;
|
||||||
|
|
||||||
|
public CCArguments(Object[] args) {
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String checkString(int i) {
|
||||||
|
checkIndex(i, "string");
|
||||||
|
|
||||||
|
Object obj = args[i];
|
||||||
|
if(!(obj instanceof String))
|
||||||
|
throw typeError(i, "string", obj);
|
||||||
|
|
||||||
|
return (String) obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int checkInteger(int i) {
|
||||||
|
checkIndex(i, "number");
|
||||||
|
|
||||||
|
Object obj = args[i];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if(obj instanceof Integer)
|
||||||
|
ret = (int) obj;
|
||||||
|
else if(obj instanceof Double)
|
||||||
|
ret = ((Double) obj).intValue();
|
||||||
|
else if(obj instanceof Float)
|
||||||
|
ret = ((Float) obj).intValue();
|
||||||
|
else
|
||||||
|
throw typeError(i, "number", obj);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map checkTable(int i) {
|
||||||
|
checkIndex(i, "table");
|
||||||
|
|
||||||
|
Object obj = args[i];
|
||||||
|
if(!(obj instanceof Map))
|
||||||
|
throw typeError(i, "table", args[i]);
|
||||||
|
|
||||||
|
return (Map) obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkIndex(int idx, String want) {
|
||||||
|
if(idx < 0 || idx >= args.length)
|
||||||
|
typeError(idx, want, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IllegalArgumentException typeError(int idx, String want, Object got) {
|
||||||
|
return new IllegalArgumentException("bad argument #" + (idx + 1) + " (" + want + " expected, got " + luaTypeName(got) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String luaTypeName(Object obj) {
|
||||||
|
if(obj == null)
|
||||||
|
return "nil";
|
||||||
|
|
||||||
|
Class<?> cls = obj.getClass();
|
||||||
|
if(cls == Boolean.class || cls == Boolean.TYPE)
|
||||||
|
return "boolean";
|
||||||
|
else if(cls == Integer.class || cls == Integer.TYPE || cls == Double.class || cls == Double.TYPE || cls == Float.class || cls == Float.TYPE)
|
||||||
|
return "number";
|
||||||
|
else if(cls == String.class)
|
||||||
|
return "string";
|
||||||
|
else if(Map.class.isAssignableFrom(cls))
|
||||||
|
return "table";
|
||||||
|
else
|
||||||
|
return cls.getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int count() {
|
||||||
|
return args.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
33
src/main/java/net/montoyo/wd/core/CCPeripheralProvider.java
Normal file
33
src/main/java/net/montoyo/wd/core/CCPeripheralProvider.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.core;
|
||||||
|
|
||||||
|
/*
|
||||||
|
import net.montoyo.wd.entity.TileEntityCCInterface;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheralProvider", modid = "computercraft")
|
||||||
|
public class CCPeripheralProvider implements IPeripheralProvider {
|
||||||
|
|
||||||
|
private CCPeripheralProvider() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Optional.Method(modid = "computercraft")
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IPeripheral getPeripheral(@Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing f) {
|
||||||
|
TileEntity te = world.getTileEntity(pos);
|
||||||
|
return (te instanceof TileEntityCCInterface) ? ((TileEntityCCInterface) te) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Optional.Method(modid = "computercraft")
|
||||||
|
public static void register() {
|
||||||
|
ComputerCraftAPI.registerPeripheralProvider(new CCPeripheralProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
37
src/main/java/net/montoyo/wd/core/CraftComponent.java
Normal file
37
src/main/java/net/montoyo/wd/core/CraftComponent.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.core;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.montoyo.wd.registry.ItemRegistry;
|
||||||
|
|
||||||
|
public enum CraftComponent {
|
||||||
|
STONEKEY("stonekey", "StoneKey"),
|
||||||
|
UPGRADE("upgrade", "Upgrade"),
|
||||||
|
PERIPHERAL("peripheral", "Peripheral"),
|
||||||
|
BATCELL("batcell", "BatCell"),
|
||||||
|
BATPACK("batpack", "BatPack"),
|
||||||
|
LASERDIODE("laserdiode", "LaserDiode"),
|
||||||
|
BACKLIGHT("backlight", "Backlight"),
|
||||||
|
EXTCARD("extcard", "ExtCard"),
|
||||||
|
BADEXTCARD("badextcard", "BadExtCard");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final String wikiName;
|
||||||
|
|
||||||
|
CraftComponent(String n, String wikiName) {
|
||||||
|
name = n;
|
||||||
|
this.wikiName = wikiName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack makeItemStack() {
|
||||||
|
return new ItemStack(ItemRegistry.getComputerCraftItem(ordinal()).get(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
73
src/main/java/net/montoyo/wd/core/DefaultPeripheral.java
Normal file
73
src/main/java/net/montoyo/wd/core/DefaultPeripheral.java
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.core;
|
||||||
|
|
||||||
|
import net.minecraft.util.StringRepresentable;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.montoyo.wd.entity.KeyboardBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.RemoteControlBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.RedstoneControlBlockEntity;
|
||||||
|
import net.montoyo.wd.entity.ServerBlockEntity;
|
||||||
|
import net.montoyo.wd.registry.BlockRegistry;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public enum DefaultPeripheral implements StringRepresentable {
|
||||||
|
KEYBOARD("keyboard", "Keyboard", KeyboardBlockEntity::new, BlockRegistry.KEYBOARD_BLOCK), //WITH FACING (< 3)
|
||||||
|
// CC_INTERFACE("ccinterface", "ComputerCraft_Interface", TileEntityCCInterface.class),
|
||||||
|
// OC_INTERFACE("cointerface", "OpenComputers_Interface", TileEntityOCInterface.class),
|
||||||
|
REMOTE_CONTROLLER("remotectrl", "Remote_Controller", RemoteControlBlockEntity::new , BlockRegistry.REMOTE_CONTROLLER_BLOCK), //WITHOUT FACING (>= 3)
|
||||||
|
REDSTONE_CONTROLLER("redstonectrl", "Redstone_Controller", RedstoneControlBlockEntity::new , BlockRegistry.REDSTONE_CONTROL_BLOCK),
|
||||||
|
SERVER("server", "Server", ServerBlockEntity::new, BlockRegistry.SERVER_BLOCK);
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final String wikiName;
|
||||||
|
private final BlockEntityType.BlockEntitySupplier<? extends BlockEntity> teClass;
|
||||||
|
private final Supplier<? extends Block> bClass;
|
||||||
|
|
||||||
|
DefaultPeripheral(String name, String wname, BlockEntityType.BlockEntitySupplier<? extends BlockEntity> factory, Supplier<? extends Block> supplier) {
|
||||||
|
this.name = name;
|
||||||
|
wikiName = wname;
|
||||||
|
teClass = factory;
|
||||||
|
bClass = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Supplier<? extends Block> getBlockClass() {
|
||||||
|
return bClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DefaultPeripheral fromMetadata(int meta) {
|
||||||
|
if((meta & 3) == 3)
|
||||||
|
return values()[(((meta >> 2) & 3) | 4) - 1]; //Without facing
|
||||||
|
else
|
||||||
|
return values()[meta & 3]; //With facing
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockEntityType.BlockEntitySupplier<? extends BlockEntity> getTEClass() {
|
||||||
|
return teClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasFacing() {
|
||||||
|
return ordinal() < 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int toMetadata(int facing) {
|
||||||
|
int ret = ordinal();
|
||||||
|
if(ret < 3) //With facing
|
||||||
|
ret |= facing << 2;
|
||||||
|
else //Without facing
|
||||||
|
ret = (((ret + 1) & 3) << 2) | 3;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getSerializedName() {
|
||||||
|
return "default_peripheral_" + name;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/main/java/net/montoyo/wd/core/DefaultUpgrade.java
Normal file
50
src/main/java/net/montoyo/wd/core/DefaultUpgrade.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.core;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.montoyo.wd.item.ItemUpgrade;
|
||||||
|
|
||||||
|
public enum DefaultUpgrade {
|
||||||
|
LASERMOUSE("lasermouse", "LaserMouse"),
|
||||||
|
REDINPUT("redinput", "RedInput"),
|
||||||
|
REDOUTPUT("redoutput", "RedOutput"),
|
||||||
|
GPS("gps", "GPS");
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public final String wikiName;
|
||||||
|
|
||||||
|
DefaultUpgrade(String n, String wn) {
|
||||||
|
name = n;
|
||||||
|
wikiName = wn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean matches(ItemStack stack, DefaultUpgrade upgrade) {
|
||||||
|
if (stack.getItem() instanceof ItemUpgrade upgrade1)
|
||||||
|
return upgrade1.type == upgrade;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesLaserMouse(ItemStack is) {
|
||||||
|
return matches(is, LASERMOUSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesRedInput(ItemStack is) {
|
||||||
|
return matches(is, REDINPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesRedOutput(ItemStack is) {
|
||||||
|
return matches(is, REDOUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesGps(ItemStack is) {
|
||||||
|
return matches(is, GPS);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/main/java/net/montoyo/wd/core/HasAdvancement.java
Normal file
11
src/main/java/net/montoyo/wd/core/HasAdvancement.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.core;
|
||||||
|
|
||||||
|
public enum HasAdvancement {
|
||||||
|
DONT_KNOW,
|
||||||
|
YES,
|
||||||
|
NO
|
||||||
|
}
|
||||||
14
src/main/java/net/montoyo/wd/core/IComputerArgs.java
Normal file
14
src/main/java/net/montoyo/wd/core/IComputerArgs.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.core;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface IComputerArgs {
|
||||||
|
String checkString(int i);
|
||||||
|
int checkInteger(int i);
|
||||||
|
Map checkTable(int i);
|
||||||
|
int count();
|
||||||
|
}
|
||||||
15
src/main/java/net/montoyo/wd/core/IPeripheral.java
Normal file
15
src/main/java/net/montoyo/wd/core/IPeripheral.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.core;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.montoyo.wd.utilities.data.BlockSide;
|
||||||
|
import net.montoyo.wd.utilities.math.Vector3i;
|
||||||
|
|
||||||
|
public interface IPeripheral {
|
||||||
|
boolean connect(Level world, BlockPos blockPos, BlockState blockState, Vector3i screenPos, BlockSide screenSide);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user