wip education ui

This commit is contained in:
Moritz Zwerger 2024-08-10 15:19:13 +02:00
parent cd6a256b75
commit b3812ad487
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
7 changed files with 287 additions and 12 deletions

View File

@ -38,14 +38,16 @@ Internally it is running minecraft 1.16.5 in the background.
## System requirements ## System requirements
- OS: Windows/Linux/macOS - OS: Windows/Linux/macOS (FreeBSD, [Android](https://gitlab.bixilon.de/bixilon/minosoft/-/issues/71), Chrome OS, iOS are not supported)
- CPU: x64/x86 processor (arm 64 is supported on macOS and linux) - CPU: x64/x86 processor (arm 64 is supported on macOS and linux)
- Memory: At least 150 MB free, 300 MB recommended - Memory: At least 150 MB free, 300 MB+ recommended
- GPU: Pretty much anything will work, it just needs to support OpenGL 3.3+ (gpus form 2010 up) - GPU: Pretty much anything will work, it just needs to support OpenGL 3.3+ (gpus form 2010 up)
- Disk space: The executable (60MB) + 3 MB for assets like textures - Disk space: The executable (60MB) + 3 MB for assets like textures
- Java 11+ - Java 11+
- No network is required (only for starting once, but it can also run completely offline, see #Offline) - No network is required (only for starting once, but it can also run completely offline, see #Offline)
Minosoft is really optimized and runs on really little hardware, ideal for schools/people with old computers.
Sadly due to not having opengl, the raspberry pi (or similar arm boards) are not supported, see [#77](https://gitlab.bixilon.de/bixilon/minosoft/-/issues/77) for more details. Sadly due to not having opengl, the raspberry pi (or similar arm boards) are not supported, see [#77](https://gitlab.bixilon.de/bixilon/minosoft/-/issues/77) for more details.
## Offline ## Offline

View File

@ -523,7 +523,7 @@ tasks.withType<JavaCompile> {
} }
application { application {
mainClass.set("de.bixilon.minosoft.Minosoft") mainClass.set("de.bixilon.minosoft.education.MinosoftEducation")
} }
var destination: File? = null var destination: File? = null

View File

@ -17,16 +17,20 @@ import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.kutil.shutdown.AbstractShutdownReason import de.bixilon.kutil.shutdown.AbstractShutdownReason
import de.bixilon.kutil.shutdown.ShutdownManager import de.bixilon.kutil.shutdown.ShutdownManager
import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.Minosoft
import de.bixilon.minosoft.assets.IntegratedAssets
import de.bixilon.minosoft.assets.minecraft.index.IndexAssetsType import de.bixilon.minosoft.assets.minecraft.index.IndexAssetsType
import de.bixilon.minosoft.assets.util.InputStreamUtil.readJson
import de.bixilon.minosoft.config.profile.profiles.account.AccountProfileManager import de.bixilon.minosoft.config.profile.profiles.account.AccountProfileManager
import de.bixilon.minosoft.config.profile.profiles.audio.AudioProfileManager import de.bixilon.minosoft.config.profile.profiles.audio.AudioProfileManager
import de.bixilon.minosoft.config.profile.profiles.rendering.RenderingProfileManager import de.bixilon.minosoft.config.profile.profiles.rendering.RenderingProfileManager
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfileManager import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfileManager
import de.bixilon.minosoft.data.accounts.Account import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.accounts.types.offline.OfflineAccount import de.bixilon.minosoft.data.accounts.types.offline.OfflineAccount
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
import de.bixilon.minosoft.education.config.EducationC import de.bixilon.minosoft.education.config.EducationC
import de.bixilon.minosoft.education.world.EducationGenerator import de.bixilon.minosoft.education.world.EducationGenerator
import de.bixilon.minosoft.education.world.EducationStorage import de.bixilon.minosoft.education.world.EducationStorage
import de.bixilon.minosoft.gui.eros.education.EducationUI
import de.bixilon.minosoft.local.LocalConnection import de.bixilon.minosoft.local.LocalConnection
import de.bixilon.minosoft.protocol.network.session.play.PlaySession import de.bixilon.minosoft.protocol.network.session.play.PlaySession
import de.bixilon.minosoft.protocol.network.session.play.PlaySessionStates.Companion.disconnected import de.bixilon.minosoft.protocol.network.session.play.PlaySessionStates.Companion.disconnected
@ -37,7 +41,7 @@ import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType import de.bixilon.minosoft.util.logging.LogMessageType
object MinosoftEducation { object MinosoftEducation {
val config: EducationC = EducationC() var config: EducationC = EducationC()
private fun getAccount(): Account { private fun getAccount(): Account {
val profile = AccountProfileManager.selected val profile = AccountProfileManager.selected
@ -72,6 +76,9 @@ object MinosoftEducation {
} }
session::error.observe(this) { ShutdownManager.shutdown(reason = AbstractShutdownReason.CRASH) } session::error.observe(this) { ShutdownManager.shutdown(reason = AbstractShutdownReason.CRASH) }
session.connect() session.connect()
val ui = EducationUI(session)
ui.show()
} }
fun setup() { fun setup() {
@ -92,13 +99,18 @@ object MinosoftEducation {
ResourcesProfileManager.selected.assets.indexAssetsTypes += IndexAssetsType.LANGUAGE ResourcesProfileManager.selected.assets.indexAssetsTypes += IndexAssetsType.LANGUAGE
} }
fun loadSettings() {
Log.log(LogMessageType.LOADING, LogLevels.VERBOSE) { "Loading education.json" }
val stream = IntegratedAssets.DEFAULT.getOrNull(minosoft("education.json")) ?: return
this.config = stream.readJson()
}
@JvmStatic @JvmStatic
fun main(args: Array<String>) { fun main(args: Array<String>) {
setup() setup()
Minosoft.main(emptyArray()) Minosoft.main(args)
postSetup() postSetup()
loadSettings()
// TODO: load education.json
start() start()
} }

View File

@ -0,0 +1,87 @@
/*
* Minosoft
* Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.eros.education
import de.bixilon.kutil.shutdown.ShutdownManager
import de.bixilon.minosoft.data.entities.entities.Entity
import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
import de.bixilon.minosoft.gui.eros.controller.JavaFXWindowController
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
import javafx.fxml.FXML
import javafx.scene.control.ComboBox
import javafx.scene.control.Slider
import javafx.scene.control.TextField
import javafx.scene.text.TextFlow
import java.lang.reflect.Method
class EducationUI(
val session: PlaySession,
) : JavaFXWindowController() {
@FXML private lateinit var blockX: TextField
@FXML private lateinit var blockY: TextField
@FXML private lateinit var blockZ: TextField
@FXML private lateinit var blockFX: ComboBox<Block>
@FXML private lateinit var entityFX: ComboBox<Entity>
@FXML private lateinit var timeStatus: TextFlow
@FXML private lateinit var timeSpeed: Slider
@FXML private lateinit var codeStatus: TextFlow
@FXML private lateinit var functionsFX: ComboBox<Method>
public override fun show() {
JavaFXUtil.openModalAsync("Minosoft Education UI", LAYOUT, this) { super.show() }
}
override fun postInit() {
stage.setOnCloseRequest {
if (closing) return@setOnCloseRequest
ShutdownManager.shutdown()
}
}
override fun close() {
super.close()
ShutdownManager.shutdown()
}
fun reset() = Unit
fun killAll() = Unit
fun freeze() = Unit
fun getBlock() = Unit
fun setBlock() = Unit
fun kill() = Unit
fun highlight() = Unit
fun teleport() = Unit
fun pause() = Unit
fun step() = Unit
fun stop() = Unit
fun restart() = Unit
fun reload() = Unit
fun invoke() = Unit
companion object {
val LAYOUT = minosoft("eros/education/education.fxml")
}
}

View File

@ -41,11 +41,7 @@ import javafx.beans.property.BooleanPropertyBase
import javafx.css.StyleableProperty import javafx.css.StyleableProperty
import javafx.fxml.FXMLLoader import javafx.fxml.FXMLLoader
import javafx.scene.* import javafx.scene.*
import javafx.scene.control.Alert import javafx.scene.control.*
import javafx.scene.control.Labeled
import javafx.scene.control.TableColumnBase
import javafx.scene.control.TextField
import javafx.scene.control.Tooltip
import javafx.scene.image.Image import javafx.scene.image.Image
import javafx.scene.input.KeyCode import javafx.scene.input.KeyCode
import javafx.scene.input.KeyEvent import javafx.scene.input.KeyEvent
@ -59,6 +55,7 @@ import java.io.File
object JavaFXUtil { object JavaFXUtil {
private const val DEFAULT_STYLE = "resource:minosoft:eros/style.css" private const val DEFAULT_STYLE = "resource:minosoft:eros/style.css"
private const val EDUCATION_STYLE = "resource:minosoft:eros/education/education.css"
private val SHOWING_FIELD = Window::class.java.getFieldOrNull("showing")!! private val SHOWING_FIELD = Window::class.java.getFieldOrNull("showing")!!
private val MARK_INVALID_METHOD = BooleanPropertyBase::class.java.getDeclaredMethod("markInvalid").apply { setUnsafeAccessible() } private val MARK_INVALID_METHOD = BooleanPropertyBase::class.java.getDeclaredMethod("markInvalid").apply { setUnsafeAccessible() }
private val stages = StageList() private val stages = StageList()
@ -81,6 +78,7 @@ object JavaFXUtil {
stage ?: break stage ?: break
stage.scene.stylesheets.clear() stage.scene.stylesheets.clear()
stage.scene.stylesheets.add(DEFAULT_STYLE) stage.scene.stylesheets.add(DEFAULT_STYLE)
stage.scene.stylesheets.add(EDUCATION_STYLE)
stage.scene.stylesheets.add(getThemeURL(it)) stage.scene.stylesheets.add(getThemeURL(it))
} }
} }
@ -95,6 +93,7 @@ object JavaFXUtil {
stage.icons.setAll(MINOSOFT_LOGO) stage.icons.setAll(MINOSOFT_LOGO)
stage.scene.stylesheets.add(DEFAULT_STYLE) stage.scene.stylesheets.add(DEFAULT_STYLE)
stage.scene.stylesheets.add(EDUCATION_STYLE)
val theme = ErosProfileManager.selected.theme.theme val theme = ErosProfileManager.selected.theme.theme
stage.scene.stylesheets.add(getThemeURL(theme)) stage.scene.stylesheets.add(getThemeURL(theme))

View File

@ -0,0 +1,35 @@
/*
* Minosoft
* Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
.status {
-fx-border-width: 3px;
-fx-border-style: solid;
}
.status-running {
-fx-border-color: green;
-fx-background-color: lightgreen;
-fx-text-fill: white;
}
.status-paused {
-fx-border-color: orange;
-fx-background-color: yellow;
-fx-text-fill: black;
}
.status-terminated {
-fx-border-color: red;
-fx-background-color: lightred;
-fx-text-fill: black;
}

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.text.TextFlow?>
<!--
~ Minosoft
~ Copyright (C) 2020-2024 Moritz Zwerger
~
~ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
~
~ This software is not affiliated with Mojang AB, the original developer of Minecraft.
-->
<HBox xmlns:fx="http://javafx.com/fxml/1" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/18">
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="NEVER"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/>
</rowConstraints>
<Label text="World"/>
<HBox GridPane.columnIndex="1">
<Button onAction="#reset" text="Reset"/>
<Button onAction="#killAll" text="Remove all"/>
<Button onAction="#freeze" text="Freeze"/>
</HBox>
<Label text="Blocks" GridPane.rowIndex="1"/>
<GridPane GridPane.columnIndex="1" GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="NEVER"/>
<ColumnConstraints hgrow="ALWAYS"/>
<ColumnConstraints hgrow="NEVER"/>
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="SOMETIMES"/>
</rowConstraints>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="NEVER"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="50.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/>
</rowConstraints>
<Label text="X"/>
<Label text="Y" GridPane.rowIndex="1"/>
<Label text="Z" GridPane.rowIndex="2"/>
<TextField fx:id="blockX" text="0" GridPane.columnIndex="1"/>
<TextField fx:id="blockY" text="0" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<TextField fx:id="blockZ" text="0" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
</GridPane>
<ComboBox fx:id="blockFX" prefWidth="200.0" GridPane.columnIndex="1"/>
<VBox GridPane.columnIndex="2">
<Button onAction="#getBlock" text="Get"/>
<Button onAction="#setBlock" text="Set"/>
</VBox>
</GridPane>
<Label text="Entities" GridPane.rowIndex="2"/>
<GridPane GridPane.columnIndex="1" GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" minWidth="200.0" prefWidth="200.0"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<ComboBox fx:id="entityFX" prefWidth="200.0"/>
<HBox GridPane.columnIndex="1">
<Button onAction="#kill" text="Remove"/>
<Button onAction="#highlight" text="Highlight"/>
<Button onAction="#teleport" text="Teleport"/>
</HBox>
<rowConstraints>
<RowConstraints/>
</rowConstraints>
</GridPane>
<Label text="Time" GridPane.rowIndex="3"/>
<GridPane GridPane.columnIndex="1" GridPane.rowIndex="3">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES"/>
<ColumnConstraints hgrow="SOMETIMES"/>
<ColumnConstraints hgrow="SOMETIMES"/>
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="SOMETIMES"/>
</rowConstraints>
<TextFlow fx:id="timeStatus" styleClass="status,status-running">
<Text text="Running"/>
</TextFlow>
<Slider fx:id="timeSpeed" GridPane.columnIndex="1"/>
<HBox GridPane.columnIndex="2">
<Button onAction="#pause" text="Pause"/>
<Button onAction="#step" text="Step"/>
</HBox>
</GridPane>
<Label text="Code" GridPane.rowIndex="4"/>
<HBox GridPane.columnIndex="1" GridPane.rowIndex="4">
<TextFlow fx:id="codeStatus" styleClass="status,status-terminated">
<Text text="Terminated"/>
</TextFlow>
<Button onAction="#stop" text="Terminate"/>
<Button onAction="#restart" text="Restart"/>
<Button onAction="#reload" text="Reload"/>
</HBox>
<Label text="Functions" GridPane.rowIndex="5"/>
<GridPane GridPane.columnIndex="1" GridPane.rowIndex="5">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" prefWidth="200.0"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<ComboBox fx:id="functionsFX" prefWidth="200.0"/>
<HBox GridPane.columnIndex="1">
<Button onAction="#invoke" text="Invoke"/>
</HBox>
<rowConstraints>
<RowConstraints/>
</rowConstraints>
</GridPane>
</GridPane>
</HBox>