🎉 Trading starts!

This commit is contained in:
2023-08-15 21:30:14 +02:00
commit 51814b9f5d
76 changed files with 4585 additions and 0 deletions

26
.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
# eclipse
bin
*.launch
.settings
.metadata
.classpath
.project
# idea
out
*.ipr
*.iws
*.iml
.idea
# gradle
build
.gradle
# other
eclipse
run
# Files from Forge MDK
forge*changelog.txt
scripts/output

65
CREDITS.txt Normal file
View File

@@ -0,0 +1,65 @@
Minecraft Forge: Credits/Thank You
Forge is a set of tools and modifications to the Minecraft base game code to assist
mod developers in creating new and exciting content. It has been in development for
several years now, but I would like to take this time thank a few people who have
helped it along it's way.
First, the people who originally created the Forge projects way back in Minecraft
alpha. Eloraam of RedPower, and SpaceToad of Buildcraft, without their acceptiance
of me taking over the project, who knows what Minecraft modding would be today.
Secondly, someone who has worked with me, and developed some of the core features
that allow modding to be as functional, and as simple as it is, cpw. For developing
FML, which stabelized the client and server modding ecosystem. As well as the base
loading system that allows us to modify Minecraft's code as elegently as possible.
Mezz, who has stepped up as the issue and pull request manager. Helping to keep me
sane as well as guiding the community into creating better additions to Forge.
Searge, Bspks, Fesh0r, ProfMobious, and all the rest over on the MCP team {of which
I am a part}. For creating some of the core tools needed to make Minecraft modding
both possible, and as stable as can be.
On that note, here is some specific information of the MCP data we use:
* Minecraft Coder Pack (MCP) *
Forge Mod Loader and Minecraft Forge have permission to distribute and automatically
download components of MCP and distribute MCP data files. This permission is not
transitive and others wishing to redistribute the Minecraft Forge source independently
should seek permission of MCP or remove the MCP data files and request their users
to download MCP separately.
And lastly, the countless community members who have spent time submitting bug reports,
pull requests, and just helping out the community in general. Thank you.
--LexManos
=========================================================================
This is Forge Mod Loader.
You can find the source code at all times at https://github.com/MinecraftForge/MinecraftForge/tree/1.12.x/src/main/java/net/minecraftforge/fml
This minecraft mod is a clean open source implementation of a mod loader for minecraft servers
and minecraft clients.
The code is authored by cpw.
It began by partially implementing an API defined by the client side ModLoader, authored by Risugami.
http://www.minecraftforum.net/topic/75440-
This support has been dropped as of Minecraft release 1.7, as Risugami no longer maintains ModLoader.
It also contains suggestions and hints and generous helpings of code from LexManos, author of MinecraftForge.
http://www.minecraftforge.net/
Additionally, it contains an implementation of topological sort based on that
published at http://keithschwarz.com/interesting/code/?dir=topological-sort
It also contains code from the Maven project for performing versioned dependency
resolution. http://maven.apache.org/
It also contains a partial repackaging of the javaxdelta library from http://sourceforge.net/projects/javaxdelta/
with credit to it's authors.
Forge Mod Loader downloads components from the Minecraft Coder Pack
(http://mcp.ocean-labs.de/index.php/Main_Page) with kind permission from the MCP team.

7
LICENSE.txt Normal file
View File

@@ -0,0 +1,7 @@
Copyright 2022 oierbravo
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.

2
README.md Normal file
View File

@@ -0,0 +1,2 @@
# TradingStation

321
build.gradle Normal file
View File

@@ -0,0 +1,321 @@
buildscript {
repositories {
gradlePluginPortal()
maven { url = 'https://maven.minecraftforge.net' }
mavenCentral()
maven { url = 'https://repo.spongepowered.org/repository/maven-public' }
maven { url = 'https://maven.parchmentmc.org' }
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: "${forgegradle_version}", changing: false
classpath 'gradle.plugin.com.matthewprenger:CurseGradle:1.1.0'
classpath group: 'org.spongepowered', name: 'mixingradle', version: '0.7-SNAPSHOT'
classpath "org.parchmentmc:librarian:1.+"
}
}
plugins {
id 'maven-publish'
id 'com.matthewprenger.cursegradle' version "${cursegradle_version}"
id "com.modrinth.minotaur" version "2.+"
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'org.parchmentmc.librarian.forgegradle'
apply plugin: 'com.matthewprenger.cursegradle'
apply plugin: 'org.spongepowered.mixin'
apply plugin: 'idea'
apply plugin: 'maven-publish'
jarJar.enable()
group = "com.${author}.${modid}"
version = "${mod_version}"
archivesBaseName = "${modid}-${minecraft_version}"
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
minecraft {
if (Boolean.parseBoolean(project.use_parchment)) {
mappings channel: 'parchment', version: "${parchment_version}-${minecraft_version}"
} else {
mappings channel: 'official', version: "${minecraft_version}"
}
// accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Currently, this location cannot be changed from the default.
runs {
client {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
// The markers can be added/remove as needed separated by commas.
// "SCAN": For mods scan.
// "REGISTRIES": For firing of registry events.
// "REGISTRYDUMP": For getting the contents of all registries.
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
// You can set various levels here.
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
property 'forge.logging.console.level', 'debug'
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
property 'forge.enabledGameTestNamespaces', 'trading_station'
mods {
trading_station {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
property 'forge.enabledGameTestNamespaces', 'trading_station'
mods {
trading_station {
source sourceSets.main
}
}
}
// This run config launches GameTestServer and runs all registered gametests, then exits.
// By default, the server will crash when no gametests are provided.
// The gametest system is also enabled by default for other run configs under the /test command.
gameTestServer {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
// The markers can be added/remove as needed separated by commas.
// "SCAN": For mods scan.
// "REGISTRIES": For firing of registry events.
// "REGISTRYDUMP": For getting the contents of all registries.
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
// You can set various levels here.
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
property 'forge.logging.console.level', 'debug'
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
property 'forge.enabledGameTestNamespaces', 'trading_station'
mods {
trading_station {
source sourceSets.main
}
}
}
data {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
args '--mod', 'trading_station', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
mods {
trading_station {
source sourceSets.main
}
}
}
}
}
// Include resources generated by data generators.
sourceSets.main.resources { srcDir 'src/generated/resources' }
repositories {
maven {
// Location of the maven that hosts JEI files (and TiC)
name 'Progwml6 maven'
url 'https://dvs1.progwml6.com/files/maven'
}
maven {
name = 'tterrag maven'
url = 'https://maven.tterrag.com/'
}
maven {
url "https://www.cursemaven.com"
content {
includeGroup "curse.maven"
}
}
maven {
url "https://maven.saps.dev/minecraft"
content {
includeGroup "dev.latvian.mods"
includeGroup "dev.ftb.mods"
}
}
maven {
url "https://maven.architectury.dev/"
content {
includeGroup "dev.architectury"
}
}
maven {
url "https://maven.blamejared.com"
}
}
dependencies {
implementation 'org.jetbrains:annotations:22.0.0'
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
jarJar(group: 'com.tterrag.registrate', name: 'Registrate', version: "[MC1.19,MC1.20)")
jarJar(group: 'com.tterrag.registrate', name: 'Registrate', version: '[MC1.19-1.1.5,)') {
jarJar.pin(it, project.registrate_version)
}
implementation fg.deobf("com.tterrag.registrate:Registrate:${registrate_version}")
compileOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}-common-api:${jei_version}")
compileOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}-forge-api:${jei_version}")
implementation fg.deobf("mezz.jei:jei-${jei_minecraft_version}-forge:${jei_version}")
if (kubejs_enabled.toBoolean()) {
implementation fg.deobf("dev.latvian.mods:rhino-forge:${rhino_version}")
implementation fg.deobf("dev.architectury:architectury-forge:${architectury_version}")
implementation fg.deobf("dev.latvian.mods:kubejs-forge:${kubejs_version}")
}
implementation fg.deobf("curse.maven:jade-324717:${jade_id}")
if (create_enabled.toBoolean()) {
implementation fg.deobf("com.simibubi.create:create-${create_minecraft_version}:${create_version}:slim") { transitive = false }
implementation fg.deobf("com.jozufozu.flywheel:flywheel-forge-${flywheel_minecraft_version}:${flywheel_version}")
}
if (ct_enabled.toBoolean()) {
def minecraftVersion= "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
def ctDep = "com.blamejared.crafttweaker:CraftTweaker-forge-${ct_minecraft_version}:${ct_version}"
compileOnly(ctDep)
runtimeOnly(fg.deobf(ctDep))
annotationProcessor "com.blamejared.crafttweaker:Crafttweaker_Annotation_Processors:${ct_annotation_processor_version}"
annotationProcessor minecraftVersion
annotationProcessor ctDep
}
//annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
}
compileJava.options.encoding = 'UTF-8'
compileJava {
options.compilerArgs = ['-Xdiags:verbose']
}
tasks.withType(Jar) {
//from tasks.createChangelog.outputFile
archiveClassifier = 'slim'
manifest {
attributes([
"Specification-Title" : modid,
"Specification-Vendor" : author,
"Specification-Version" : "1", // We are version 1 of ourselves
"Implementation-Title" : project.name,
"Implementation-Version" : project.version,
"Implementation-Vendor" : author,
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
"MixinConfigs" : "${modid}.mixins.json"
])
}
if(file("./src/main/resources/${modid}.mixins.json").exists()) {
manifest {
attributes 'MixinConfigs': "${modid}.mixins.json"
}
}
}
task jarJarRelease {
group = 'jarjar'
doLast {
tasks.jarJar {
archiveClassifier = ''
}
}
finalizedBy tasks.jarJar
}
tasks.jarJar {
archiveClassifier = ''
}
void addLicense(jarTask) {
jarTask.from('LICENSE.txt') {
rename { "${it}_${project.archivesBaseName}" }
}
}
addLicense(jar)
addLicense(tasks.jarJar)
mixin {
add sourceSets.main, "${modid}.refmap.json"
}
afterEvaluate {
tasks.configureReobfTaskForReobfJar.mustRunAfter(tasks.compileJava)
tasks.configureReobfTaskForReobfJarJar.mustRunAfter(tasks.compileJava)
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
}
compileJava {
options.compilerArgs = ['-Xdiags:verbose']
}
reobf {
jarJar { }
}
jar.finalizedBy('reobfJar')
tasks.jarJar.finalizedBy('reobfJarJar')
//from components.java
//def getArtifact = { ->
// from components.java
// return jarJar.component(it)
// Method body here
//}
if(System.getenv('MODRINTH_TOKEN') != null) {
modrinth {
token = System.getenv("MODRINTH_TOKEN")
projectId = "trading_station"
versionNumber = "${mod_version}"
versionName = "${display_name} - v${mod_version} for Minecraft ${minecraft_version}"
versionType = "release" // This is the default -- can also be `beta` or `alpha`
uploadFile = tasks.jarJar // With Loom, this MUST be set to `remapJar` instead of `jar`!
gameVersions = ["${minecraft_version}"] // Must be an array, even with only one version
loaders = ["forge"] // Must also be an array - no need to specify this if you're using Loom or ForgeGradle
dependencies { // A special DSL for creating dependencies
optional.project "create"
optional.project "jei"
optional.project "crafttweaker"
}
syncBodyFrom = rootProject.file("README.md").text
}
tasks.modrinth.dependsOn(tasks.modrinthSyncBody)
}
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
// publish.dependsOn('reobfJar')
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
}

383
changelog.txt Normal file
View File

@@ -0,0 +1,383 @@
1.18.x Changelog
40.1
====
- 40.1.80 Revert "[1.18.x] Backport: Cache resource listing calls in resource packs (#8868)" (#9026)
This reverts commit 4df024ef43524d8ec48928c70f561903f7a8e184.
- 40.1.79 [1.18.x] Backport #8981 ("Add event to growing fungus") to 1.18 (#8998)
- 40.1.78 LTS Backport of ModMismachEvent (#8989) (#9010)
- 40.1.77 LTS Backport of #8927 (#9012)
- 40.1.76 Backport Reach Distance fix (#9008)
- 40.1.75 Backport version-checker user-agent changes to 1.18 (#8975)
- 40.1.74 Fix circular dependency in static init of RecipeBookRegistry (#8996)
- 40.1.73 Backport: Load custom ITransformationServices from the classpath in dev (#8350)
- 40.1.72 [1.18.x] Backport: Cache resource listing calls in resource packs (#8868)
- 40.1.71 Backport: Re-add PotentialSpawns event (#8944)
- 40.1.70 [1.18.2][Backport] Let isRemotePresent check minecraft:register for packet ids from other mod loaders (#8943)
- 40.1.69 Fix crossbows not firing ArrowLooseEvent (#8888)
- 40.1.68 [1.18] Allow blocks to provide a dynamic MaterialColor for display on maps (#8855)
- 40.1.67 [1.18.x] Add RenderLevelStageEvent to expand on and replace RenderLevelLastEvent (#8603)
- 40.1.66 [1.18] Fix EnumArgument to use enum names for suggestions (#8746)
Previously, the suggestions used the string representation of the enum
through Enum#toString, which can differ from the name of the enum as
required by Enum#valueOf, causing invalid suggestions (both in gui and
through the error message).
Using Enum#name fixes this discrepancy, so now the suggestions are
always valid inputs regardless of the return of Enum#toString.
Fixes #8618
- 40.1.65 [1.18] Add MC-105317 fix into patch to rotate entities in structures properly (#8793)
- 40.1.64 [1.18] Update to the latest JarJar (#8848)
- 40.1.63 [1.18.x] Fix a weird interaction between shulker boxes and hoppers. (#8824)
- 40.1.62 [1.18.x] Implement full support for IPv6 (#8376)
- 40.1.61 [1.16] Make tryEmptyContainer respect doDrain (#8318)
- 40.1.60 Jar-In-Jar (#8657)
* Jar-In-Jar
* Change to use the custom 4.x SPI.
* Bump JarJar to fix some version range selectors.
* Address requested changes.
* Mark the JiJ locator as a locator.
* Remove the unused imports.
- 40.1.59 Fix static member ordering crash in UnitSprite (#8839)
The previous ordering caused LOCATION to be null during the construction
of the UnitSprite INSTANCE, leading to errors as the atlas location for
the sprite would be null.
Fixes #8795
- 40.1.58 Backport: ForgeChunkManager ticking ticket fixes. (#8784)
- 40.1.57 Delete LootItemRandomChanceCondition.java.patch (#8734)
- 40.1.56 Use stack sensitive translation key by default (#8674)
- 40.1.55 Add callback after a BlockState was changed and the neighbors were updated (#8617)
- 40.1.54 [1.18.x] Allow safely registering RenderType predicates at any time (#8671)
* Allow safely registering RenderType predicates at any time
* Requested changes
- 40.1.53 Add Filtered Message to ServerChatEvent
- 40.1.52 [1.18] Make ConfigValue implement Supplier. (#8777)
- 40.1.51 Make IVertexConsumers such as the lighting pipeline, be aware of which format they are dealing with (#8665)
Also fix Lighting pipeline ignoring the overlay coords from the block renderer.
- 40.1.50 Revert "TeamCity change in 'MinecraftForge / MinecraftForge' project: build features of 'Build' build configuration were updated"
This reverts commit 0cc85bc314c8c90f1bdb24d77c7035bb09150489.
- 40.1.49 TeamCity change in 'MinecraftForge / MinecraftForge' project: build features of 'Build' build configuration were updated
- 40.1.48 [1.18.x] Fix #8530 (Banner Pattern) NPE (#8666)
- 40.1.47 Revert "[1.18.x] Enable the Forge light pipeline by default (#8629)" (#8663)
- 40.1.46 Fix eager loading of model loaders during datagen causing NPE (#8659)
- 40.1.45 [1.18.x] Fix 2 crossbow animations not applying to custom variants (#8625)
- 40.1.44 [1.18.x] Added new Disconnection screen to display better channel/registry mismatch information (#8402)
Co-authored-by: Curle <42079760+TheCurle@users.noreply.github.com>
- 40.1.43 [1.18] Avoid exclusive synchronisation in block render type lookups (#8476)
- 40.1.42 [1.18] Fix command redirects by replacing Commands#fillUsableCommands (#8616)
Commands#fillUsableCommands does not handle redirect nodes properly. It
blindly pulls from the cached node map for a redirect node, which may
have no result because the target node of the redirect has not been
visited yet.
CommandHelper#mergeCommandNode is better in this regard, because it
visits the target node of the redirect instead of blindly pulling from
the node map.
Fixes #7551
- 40.1.41 [1.18] Fix tags command suggestion to include dynamic registries (#8638)
Manually entering the names of dynamic registries work as expected. The
suggestions for registries didn't include dynamic registries because
they queried the static registries rather than querying all registries
from the server's `RegistryAccess` (which includes both static
registries and dynamic registries).
- 40.1.40 Low code language provider (#8633)
Co-authored-by: Curle <42079760+TheCurle@users.noreply.github.com>
- 40.1.39 [1.18.x] Add checkJarCompatibility task (#8644)
- 40.1.38 [1.18.x] Fix Banner Patterns not being extensible (#8530)
Co-authored-by: Curle <42079760+TheCurle@users.noreply.github.com>
- 40.1.37 1.18.x Port BiomeDictionary over to biome tags (#8564)
- 40.1.36 [1.18.x] Enable the Forge light pipeline by default (#8629)
- 40.1.35 [1.18.x] Allow Modders to add custom data-pack registries through RegistryBuilder (#8630)
Co-authored-by: Silverminer007 <66484505+Silverminer007@users.noreply.github.com>
Co-authored-by: Curle <42079760+TheCurle@users.noreply.github.com>
- 40.1.34 [1.18] Allow custom rarities to directly modify the style (#8648)
- 40.1.33 [1.18] Fix reload listener registration in ModelLoaderRegistry (#8650)
- 40.1.32 Fix wrong position in Level#hasChunk() call in IForgeBlockGetter (#8654)
- 40.1.31 Add ItemStack context to Enchantment#getDamageBonus (#8635)
- 40.1.30 Fix attack cooldown bar showing when out of reach of target. Closes #8639 (#8640)
- 40.1.29 Improve TagsUpdatedEvent by adding update case information. (#8636)
- 40.1.28 Deprecate patched-in Style methods for removal, vanilla variants exist. (#8615)
- 40.1.27 Add pack-type-specific format versions in pack metadata. Fixes #8563 (#8612)
- 40.1.26 Catch and aggregate exceptions during NewRegistryEvent (#8601)
- 40.1.25 Added removeErroringEntities config option (#8627)
Counterpart to removeErroringBlockEntities
- 40.1.24 Add missing patches for not lowering mipmap level for small textures (#8622)
- 40.1.23 Make TransformType enum extensible, includes the possibility to specify a fallback type for cases where models don't specify the transform explicitly. (#8566)
Makes it possible to add new perspectives.
- 40.1.22 Fix CheckSAS to actually validate that the SAS line will do something.
This removes all method level lines as they are not necessary now.
- 40.1.21 Add Attack Range attribute and Update Reach Distance (#8478)
- 40.1.20 Implement PlayerNegotiationEvent (#8599)
- 40.1.19 Fire EntityTravelToDimensionEvent in all expected cases (#8614)
Fixes #8520
- 40.1.18 Fix isEdible crash (#8613)
Fixes #8602
- 40.1.17 Fix typo in Snow Golem patch causing them to destroy blocks they shouldn't. Closes #8611
- 40.1.16 Re-introduce an attribute for entity step height in a non-breaking way (#8607)
- 40.1.15 Revert step height attribute (#8604)
- 40.1.14 [1.18.x] Fix ContextNbtProvider serializing the wrong name (#8575)
- 40.1.13 Let BaseRailBlock decide if the calculated RailShape for placement or connection to neighbors is valid (#8562)
- 40.1.12 Fix shears not playing a breakage sound (#8600)
- 40.1.11 Update IExtensionPoint javadoc to be correct (#8568)
- 40.1.10 Fix IDs of Multi-part entities being desynced across client and server. (#8576)
- 40.1.9 Expose ICondition$IContext to modded reload listeners. (#8596)
- 40.1.8 Fix undead causing chunkloading leading to extensive lag (#8583)
- 40.1.7 Accomodate Bukkit-like Servers not sending Command Args (#8582)
Note to modded server devs:
Please, please, please implement full compatibility with [Brigadier](https://github.com/Mojang/Brigadier) instead of hacking around it.
- 40.1.6 Restore translation key comments to ForgeConfigSpec (#8584)
- 40.1.5 Fix entity parts being ignored when collecting entities in an AABB (#8588)
Previously entity parts are only taken into consideration when the parent entity is in a chunk that intersects with the AABB
- 40.1.4 Fix EntityInteraction event running twice on client side (#8598)
- 40.1.3 Introduce an attribute for step height additions (#8389)
- 40.1.2 Fix shears passing on a client when interacting with a shearable entity (#8597)
Caused the offhand item to also interact with the entity, possibly sending a packet to the server causing both hands to interact
- 40.1.1 Allow Exception passed through CommandEvent to propagate (#8590)
- 40.1.0 Mark 1.18.2 Recommended Build.
Co-authored-by: sciwhiz12 <arnoldnunag12@gmail.com>
Co-authored-by: Marc Hermans <marc.hermans@ldtteam.com>
Co-authored-by: Curle <curle@gemwire.uk>
Co-authored-by: SizableShrimp <sizableshrimp@sizableshrimp.me>
Co-authored-by: David Quintana <gigaherz@gmail.com>
40.0
====
- 40.0.54 Add event for hooking into StructuresBecomeConfiguredFix Fixes #8505
Pass-through unknown structure IDs with "unknown." prefix
This avoids the fixer throwing an exception due to the unknown
structure, which causes the chunk data to be dropped (and freshly
regenerated later). The deserializer logs and ignores the unknown
structure ID, avoiding full chunk data loss.
- 40.0.53 Fix missed patch for loading modded dimensions on Dedicated Server start (#8555)
- 40.0.52 Fix potential concurrency issues with BiomeDictionary. Closes #8266
- 40.0.51 Fix debug text being rendered slightly wrong.
- 40.0.50 Fix intrusive handlers on dummy objects.
- 40.0.49 Amend license header to include contributors and apply to FML subprojects (#8525)
After internal discussion, it was decided that we need to include
"contributors" to the license header. This avoids claiming that the
Java source files are under the exclusive copyright ownership of Forge
LLC, which excludes contributors that still hold copyright ownership
over their contributions (but is licensed under the LGPLv2.1 as stated
in the Forge CLA).
- 40.0.48 Add modern implementation of the Slider widget and deprecate the old one (#8496)
- 40.0.47 Implement ItemStack and LivingEntity sensitive method to get the FoodProperties for an Item (#8477)
- 40.0.46 Add use context and simulate flag to getToolModifiedState, enabled HOE_TILL action. (#8557)
- 40.0.45 Remove bad patch for AbstractFurnaceBlockEntity (#8561)
The patch prevented the entity from being marked as changed when an
item finished smelting.
- 40.0.44 Fix issues with custom forge ingredients causing sub ingredients to be prematurely and invalidly cached (#8550)
Add config option and skip checking for empty ingredients in shapeless recipe deserialization
- 40.0.43 Add EnderManAngerEvent to make it possible to prevent endermen getting angry at a player based on more then their helmet. (#8406)
- 40.0.42 Fix misaligned patch in BlockEntity.save.
- 40.0.41 Expose `getHolder()` method on RegistryObject, as helper for when absolutely necessary to pass into Vanilla code. (#8548)
It is recommended you avoid if you can.
- 40.0.40 Fix return value of Recipe#isIncomplete being inaccurate for empty tags (#8549)
- 40.0.39 Simplfy default behavior of isSimple (#8543)
isSimple should only return true if the ingredient is any more sensitive then JUST itemA == itemB
It used to take metadata and damage into account, but that was removed in the flattening.
Also prevents fetching tag values too early, as tags are not ready during the ingredient constructor
- 40.0.38 Implement IPlantable in BambooBlock (#8508)
- 40.0.37 Fix compiler error in eclipse, bump MCPConfig for FF/Record fix.
- 40.0.36 Fix TagEmptyCondition by passing tag context into conditional and recipe deserializers. (#8546)
- 40.0.35 Allow using DeferredRegisters for vanilla registries (#8527)
Catch and aggregate exceptions when applying object holders
- 40.0.34 Remove cut copper from copper storage blocks tag. Closes #8403 (#8539)
- 40.0.33 Fix brewing stand input placement not auto-splitting stackable potions. (#8534)
- 40.0.32 Fix lost validation of registry data on singleplayer world load (#8533)
Fix some leftover 1.18.2 TODOs
- 40.0.31 1.18 Allow mod menus to have their own recipebook (#8028)
- 40.0.30 [1.18.x] Add 3 new ingredient types, and make existing ingredients compatible with datagen (#8517)
- 40.0.29 [1.18.x] Add the projectile search event. (#8322)
Co-authored-by: noeppi_noeppi <noeppinoeppi@gmail.com>
- 40.0.28 Allow confirm-and-save of the Experimental Settings warning. (#7275)
- 40.0.27 Add hook for powdered-snow shoes (#8514)
- 40.0.26 Add some helper Access Transformers (#8490)
- 40.0.25 Fix incorrect method used in getStream (#8532)
The original correct method is getPath, but the patch uses getLocation.
The former is the actual resource path to the sound OGG file, while the
latter is the sound's location.
Fixes #8531
- 40.0.24 [1.18] Make it easier to register custom skull blocks models (#8351)
- 40.0.23 Rework fog events (#8492)
- 40.0.22 Update Forge Auto Renaming Tool to the latest version (#8515)
- 40.0.21 Add patches to enable MobEffects with IDs > 255 (#8380)
- 40.0.20 Allow sound instances to play custom audio streams (#8295)
- 40.0.19 Fix NPE caused by canceling onServerChatEvent (#8516)
- 40.0.18 [1.18.2] Fix tags for custom forge registries. (#8495)
Tag-enabled registries must now be registered to vanilla's root registry. See RegistryBuilder#hasTags.
Modded tag-enabled registries have to use the format `data/<namespace>/tags/<registrynamespace>/<registryname>/<tag>.json`
This format is to prevent conflicts for registries with the same path but different namespaces
EX: Registry name `examplemod:shoe`, tag name `blue_shoes` would be `data/<namespace>/tags/examplemod/shoe/blue_shoes.json`
RegistryEvent.NewRegistry has been moved and renamed to NewRegistryEvent.
RegistryBuilder#create has been made private. See NewRegistryEvent#create
Created new ITagManager system for looking up Forge tags. See IForgeRegistry#tags.
Add lookup methods for Holders from forge registries. See IForgeRegistry#getHolder.
- 40.0.17 Lower custom item entity replacement from highest to high so mods can cancel it during a specific tick (#8417)
- 40.0.16 Fix MC-176559 related to the Mending enchantment (#7606)
- 40.0.15 [1.18.x] Allow blocks to hide faces on a neighboring block (#8300)
* Allow blocks to hide faces on a neighboring block
* Allow blocks to opt-out of external face hiding
- 40.0.14 [1.18.x] Fix FMLOnly in forgedev and userdev (#8512)
- 40.0.13 Clear local variable table on RuntimeEnumExtender transformation (#8502)
- 40.0.12 Pass server resources to reload listener event (#8493)
- 40.0.11 Use UTF-8 charset for Java compilation (#8486)
- 40.0.10 Use wither as griefing entity when it indirectly hurts an entity (#8431)
- 40.0.9 Provide access to the haveTime supplier in WorldTickEvent and ServerTickEvent (#8470)
- 40.0.8 Fix durability bar not respecting an item's custom max damage (#8482)
- 40.0.7 Add event for controlling potion indicators size (#8483)
This event allows forcing the rendering of the potion indicators in the
inventory screen to either compact mode (icons only) or classic mode
(full width with potion effect name).
- 40.0.6 Introduce system mods to mod loading (#8238)
Core game mods are mods which are required to exist in the environment
during mod loading. These may be specially provided mods (for example,
the `minecraft` mod), or mods which are vital to the framework which
FML is connected to (for example, Forge and the `forge` mod).
These core game mods are used as the only existing mods in the mod list
if mod sorting or dependency verification fails. This allows later
steps in the which use resources from these mod files to work correctly
(up to when the error screen is shown and the game exits).
- 40.0.5 Add missing module exports arg to server arguments list (#8500)
- 40.0.4 Fixed swim speed attribute (#8499)
- 40.0.3 Fix incorrect movement distance calculation (#8497)
- 40.0.2 Add support to Forge registry wrappers for new Holder system. Closes #8491
Fix TagBasedToolTypesTest not generating needed data correctly.
- 40.0.1 Fix JNA not working at runtime and causing issues with natives.
- 40.0.0 Update to 1.18.2
Co-authored-by: sciwhiz12 <arnoldnunag12@gmail.com>
Co-authored-by: Marc Hermans <marc.hermans@ldtteam.com>
Co-authored-by: LexManos <LexManos@gmail.com>
Co-authored-by: Curle <curle@gemwire.uk>
39.1
====
- 39.1.2 1.18.x Omnibus (#8239)
- 39.1.1 Bump modlauncher and securejarhandler version (#8489)
- 39.1.0 Update license headers to compact SPDX format.
License has not changed, this is just more compact and doesn't include years.
Bump version for RB.
39.0
====
- 39.0.91 Remove - from allowed characters in mod ids.
The Java Module System does not allow them in module ids.
Closes #8488
- 39.0.90 Fix static initializer crash when loading BakedRenderable.
- 39.0.89 Fix regressions for onAddedTo/RemovedFromWorld and related events (#8434)
- 39.0.88 [1.18] Integrate the gametest framework with Forge (#8225)
- 39.0.87 Re-add missing Shulker patch for EntityTeleportEvent (#8481)
- 39.0.86 Fix entity type in conversion event to Drowned (#8479)
- 39.0.85 Add VanillaGameEvent to allow for globally listening to vanilla's GameEvents (#8472)
- 39.0.84 Provide damage source context to Item#onDestroyed(ItemEntity) (#8473)
- 39.0.83 Add missing shear and elytra game events (#8471)
- 39.0.82 Fix comment for permission handler config setting (#8466)
- 39.0.81 Apply nullable annotations to LootingLevelEvent (#8422)
- 39.0.80 Fix Mob Spawner logic with CustomSpawnRules. Closes #8398
- 39.0.79 Fix LivingDropsEvent not having all drops for foxes (#8387)
- 39.0.78 Add missing Locale parameter to String.format calls, Fixes getArmorResource functionality on some locaales. (#8463)
- 39.0.77 Allow items to hide parts of their tooltips by default (#8358)
- 39.0.76 Prevent 1.x Branches being treated as Pull Requests. (#8443)
- 39.0.75 Fix RegistryObject not working if created after registry events (#8383)
- 39.0.74 Add support for tagging StructureFeatures (#8408)
- 39.0.73 Re-added the patch for LivingExperienceDropEvent and enable it for dragons (#8388)
- 39.0.72 Implement getPickupSound on ForgeFlowingFluid (#8374)
- 39.0.71 Add getCodec method in ForgeRegistry (#8333)
- 39.0.70 Fix #8298 (MobBucketItem) and add test mod (#8313)
- 39.0.69 Deprecate IForgeAbstractMinecart::getCartItem (#8283)
- 39.0.68 Fix HoeItem patch incorrectly applied during migration. (#8384)
- 39.0.67 Fix issues with client only commands in combination with server only commands not using MC's command system. (#8452)
- 39.0.66 Fix FoliagePlacerType and TreeDecoratorType registry (#8394)
- 39.0.65 Fix PlayerChangeGameModeEvent (#8441)
- 39.0.64 Fix comparison of custom ParticleRenderTypes leading to broken particle effects. (#8385)
- 39.0.63 Fix cases where null is potentially sent to Screen events. Closes #8432
- 39.0.62 Ensure ScreenEvent doesn't accept null screens (#8296)
- 39.0.61 Update cobblestone tags (#8292)
- 39.0.60 Prevent release of custom payload packet buffer on the server side. (#8181)
- 39.0.59 Make `MinecraftLocator` respect non-`MOD` FML Mod Types Fixes #8344 (#8346)
- 39.0.58 Fix vanilla worlds being marked experimental (#8415)
- 39.0.57 Simplify usage of IItemRenderProperties::getArmorModel (#8349)
- 39.0.56 Hide mod update notification while screen is still fading in (#8386)
- 39.0.55 Revert "Hooks to allow registering and managing custom DFU schemes and types. (#8242)"
- 39.0.54 Provide NPE protection against out of order init of the TYPES and REF (#8410)
- 39.0.53 Add ShieldBlockEvent (#8261)
- 39.0.52 Add renderable API to allow easier rendering of OBJ and other custom models, from Entity and BlockEntity renderers. (#8259)
This is a redesign of a discarded section of my initial model system rewrite, back in 1.14.
In order to use it with the OBJ loader, you can use OBJLoader.INSTANCE.loadModel to get the OBJModel, and then call OBJModel#bakeRenderable() to get a SimpleRenderable object to render with.
The SimpleRenderable support animation, by providing different transformation matrices for each part in the MultipartTransforms.
Additionally, a BakedRenderable helper exists to turn an arbitrary BakedModel into a renderable.
After trying to get the B3D loader to work, I decided it wasn't worth the trouble and marked it for removal instead.
- 39.0.51 Merge values of defaulted optional tags, Fixes issue where multiple mods declare the same optional tag. (#8250)
- 39.0.50 Added new 1.18 biomes to the BiomeDictionary (#8246)
- 39.0.49 Hooks to allow registering and managing custom DFU schemes and types. (#8242)
- 39.0.48 Ping data compression (#8169)
- 39.0.47 Expand the LevelStem codec to allow dimension jsons to specify that the dimension's chunk generator should use the overworld/server's seed (#7955)
- 39.0.46 Add Client Commands (#7754)
- 39.0.45 Remove references to the now-broken `BlockEntity#save(CompoundTag)` method (#8235)
- 39.0.44 update McModLauncher libraries to newer versions...
- 39.0.43 add extra keystore properties
- 39.0.42 TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
- 39.0.41 TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
- 39.0.40 TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
- 39.0.39 TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
- 39.0.38 TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
- 39.0.37 TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
- 39.0.36 fix crowdin key
- 39.0.35 TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
- 39.0.34 TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
- 39.0.33 TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
- 39.0.32 fix secondary branches builds
- 39.0.31 TeamCity change in 'MinecraftForge / MinecraftForge' project: parameters of 'Build - Secondary Branches' build configuration were updated
- 39.0.30 TeamCity change in 'MinecraftForge / MinecraftForge' project: VCS roots of 'Build - Secondary Branches' build configuration were updated
- 39.0.29 TeamCity change in 'MinecraftForge / MinecraftForge' project: VCS roots of 'Build - Secondary Branches' build configuration were updated
- 39.0.28 TeamCity change in 'MinecraftForge / MinecraftForge' project: VCS roots of 'Build - Secondary Branches' build configuration were updated
- 39.0.27 TeamCity change in 'MinecraftForge / MinecraftForge' project: parameters of 'Build - Secondary Branches' build configuration were updated
- 39.0.26 TeamCity change in 'MinecraftForge / MinecraftForge' project: parameters of 'Build - Secondary Branches' build configuration were updated
- 39.0.25 TeamCity change in 'MinecraftForge / MinecraftForge' project: VCS roots of 'Build - Secondary Branches' build configuration were updated
- 39.0.24 Remove primary branches from building on secondary branch configuration and publish crowdin data. (#8397)
* Remove the normalized branch names also from the filter.
* Add the additional publishing arguments to get the crowdin information.
* TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
* Fix the configuration.
* Remove the required patch and use the base script.
* Make a note about the reference.
Co-authored-by: cpw <cpw@weeksfamily.ca>
- 39.0.23 TeamCity change in 'MinecraftForge / MinecraftForge' project: project parameters were changed
- 39.0.22 Correct the build configuration to support a setup. (#8395)
* Add a setup task and publish the correct versions.
* Reconfigure build task and disable the normal build and test cycle on everything but pull requests, run an assemble there.
* Fix the derp in the build configuration.
- 39.0.21 Enable the TeamCity CI pipeline (#8368)
* Setup the build.gradle
* Setup the teamcity toolchain.
* Revert the usage of the local build of GU.
* Automatically add it now, it will always exist and is added to maven automatically by GU.
* Implement the branch filter and move the constant for the minimal changelog tag to a constant in the extension.
* Adding the JDK and Gradle version to the build script.
- 39.0.20 Fix and improve Ingredient invalidation (#8361)
- 39.0.19 Rework world persistence hooks to fix the double registry injection when loading single player worlds. (#8234)
- 39.0.18 Update tags for new 1.17 and 1.18 content (#7891)
- 39.0.17 Fix TerrainParticle rendering black under certain conditions (#8378)
- 39.0.16 Allow modded tools to work on glow lichen (#8371)
- 39.0.15 Fix custom climbable blocks not sending a death message (#8372)
Fixes #8370
- 39.0.14 Provide access to the blockstate in BucketPickup#getPickupSound for multiply-logged blocks (#8357)
- 39.0.13 Fix clients being unable to deserialize tags for custom registries (#8352)
- 39.0.12 Fix particles going fullbright for a few frames when first spawning (#8291)
- 39.0.11 Also create parent directories when creating config files (#8364)
- 39.0.10 Fix crash with PermissionsAPI (#8330)
Fixes a crash in singleplayer, when the internal server didn't shut down correctly between world loads.
- 39.0.9 Re-add missing default spawn lists in features (#8285)
Fixes #8265
Fixes #8301
- 39.0.8 Fixed incorrect generic in PermissionAPI (#8317)
- 39.0.7 Redo of the whole PermissionAPI (#7780)
Co-authored-by: LexManos <LexManos@gmail.com>
- 39.0.6 Fix misplaced patch in SpreadingSnowyDirtBlock.
Fixes #8308.
- 39.0.5 Add RenderArmEvent to make overriding just the arm rendering not require copying nearly as much vanilla code (#8254)
- 39.0.4 Add MobEffect tags (#8231)
- 39.0.3 Log missing or unsupported dependencies (#8218)
- 39.0.2 Fix datagen test for sounds definitions provider (#8249)
- 39.0.1 Fix wrong stage being declared in transition to common (#8267)
- 39.0.0 Update to 1.18.1
Co-Authored by:
- Curle
_ Orion

48
gradle.properties Normal file
View File

@@ -0,0 +1,48 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false
mod_version=0.0.1
modid=trading_station
author=oierbravo
display_name=Trading Station
forgegradle_version = 5.1.74
mixingradle_version = 0.7-SNAPSHOT
librarian_version = 1.+
cursegradle_version = 1.4.0
# Versions
minecraft_version = 1.19.2
forge_version = 43.2.4
use_parchment=true
mappings_channel=parchment
parchment_version = 2022.11.27
registrate_version = MC1.19-1.1.5
jei_minecraft_version = 1.19.2
jei_version = 11.4.0.290
create_enabled = false;
create_minecraft_version = 1.19.2
flywheel_minecraft_version = 1.19.2
create_version = 0.5.1.c-36
flywheel_version = 0.6.9-18
kubejs_enabled = true
architectury_version=6.5.85
rhino_version=1902.2.2-build.269
kubejs_version=1902.6.1-build.348
jade_id = 3960379
ct_enabled = false
ct_minecraft_version = 1.19.2
ct_version = 10.1.40
ct_annotation_processor_version = 3.0.0.10

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

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

234
gradlew vendored Executable file
View File

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

89
gradlew.bat vendored Normal file
View File

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

View File

@@ -0,0 +1,9 @@
// 1.19.2 2023-08-15T19:12:23.552338231 Registrate Provider for trading_station [Recipes, Advancements, Loot tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)]
ac427e21e7a0915809800ce83800780c045678c6 assets/trading_station/blockstates/powered_trading_station.json
391b0f87f6c9bd80e20dfc8b949e7dd99cd16fe9 assets/trading_station/blockstates/trading_station.json
59d487ef1d18c0234dbb7c4b7a99eb0a8bf30520 assets/trading_station/lang/en_ud.json
fcd793fe1e0ddcc1d5cc535bda29fe37fee4c1a2 assets/trading_station/lang/en_us.json
373be6ce42eee460888161c967f098e5943e3778 assets/trading_station/models/item/powered_trading_station.json
7ddda578b6d6072db924599a9959579470354897 assets/trading_station/models/item/trading_station.json
c3b4c04c1cecdc5001fcddda7b30b11b15f0b2b2 data/trading_station/loot_tables/blocks/powered_trading_station.json
4c82f05fb35c8b26972d5fd3abf4bb5da6cba466 data/trading_station/loot_tables/blocks/trading_station.json

View File

@@ -0,0 +1,34 @@
{
"variants": {
"facing=east,powered=false": {
"model": "trading_station:block/powered_trading_station",
"y": 90
},
"facing=east,powered=true": {
"model": "trading_station:block/powered_trading_station_powered",
"y": 90
},
"facing=north,powered=false": {
"model": "trading_station:block/powered_trading_station"
},
"facing=north,powered=true": {
"model": "trading_station:block/powered_trading_station_powered"
},
"facing=south,powered=false": {
"model": "trading_station:block/powered_trading_station",
"y": 180
},
"facing=south,powered=true": {
"model": "trading_station:block/powered_trading_station_powered",
"y": 180
},
"facing=west,powered=false": {
"model": "trading_station:block/powered_trading_station",
"y": 270
},
"facing=west,powered=true": {
"model": "trading_station:block/powered_trading_station_powered",
"y": 270
}
}
}

View File

@@ -0,0 +1,34 @@
{
"variants": {
"facing=east,powered=false": {
"model": "trading_station:block/trading_station",
"y": 90
},
"facing=east,powered=true": {
"model": "trading_station:block/trading_station_powered",
"y": 90
},
"facing=north,powered=false": {
"model": "trading_station:block/trading_station"
},
"facing=north,powered=true": {
"model": "trading_station:block/trading_station_powered"
},
"facing=south,powered=false": {
"model": "trading_station:block/trading_station",
"y": 180
},
"facing=south,powered=true": {
"model": "trading_station:block/trading_station_powered",
"y": 180
},
"facing=west,powered=false": {
"model": "trading_station:block/trading_station",
"y": 270
},
"facing=west,powered=true": {
"model": "trading_station:block/trading_station_powered",
"y": 270
}
}
}

View File

@@ -0,0 +1,12 @@
{
"block.trading_station.powered_trading_station": "uoıʇɐʇS buıpɐɹ⟘ pǝɹǝʍoԀ",
"block.trading_station.trading_station": "uoıʇɐʇS buıpɐɹ⟘",
"config.jade.plugin_trading_station.trading_station_data": "ɐʇɐp uoıʇɐʇS buıpɐɹ⟘",
"itemGroup.trading_station:main": "uoıʇɐʇS buıpɐɹ⟘",
"trading_station.block.display": "uoıʇɐʇS buıpɐɹ⟘",
"trading_station.recipe": "ǝdıɔǝɹ buıpɐɹ⟘",
"trading_station.select_target.button": "ʇǝbɹɐʇ ʇɔǝןǝS",
"trading_station.select_target.clear": "ɹɐǝןƆ",
"trading_station.select_target.title": "ʇǝbɹɐʇ ʇndʇno uɐ ʇɔǝןǝS",
"trading_station.tooltip.progress": "%d%% :ssǝɹboɹԀ"
}

View File

@@ -0,0 +1,12 @@
{
"block.trading_station.powered_trading_station": "Powered Trading Station",
"block.trading_station.trading_station": "Trading Station",
"config.jade.plugin_trading_station.trading_station_data": "Trading Station data",
"itemGroup.trading_station:main": "Trading Station",
"trading_station.block.display": "Trading Station",
"trading_station.recipe": "Trading recipe",
"trading_station.select_target.button": "Select target",
"trading_station.select_target.clear": "Clear",
"trading_station.select_target.title": "Select an output target",
"trading_station.tooltip.progress": "Progress: %d%%"
}

View File

@@ -0,0 +1,3 @@
{
"parent": "trading_station:block/powered_trading_station"
}

View File

@@ -0,0 +1,3 @@
{
"parent": "trading_station:block/trading_station"
}

View File

@@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "trading_station:powered_trading_station"
}
],
"rolls": 1.0
}
]
}

View File

@@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "trading_station:trading_station"
}
],
"rolls": 1.0
}
]
}

View File

@@ -0,0 +1,75 @@
package com.oierbravo.trading_station;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mojang.logging.LogUtils;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.registrate.*;
import com.tterrag.registrate.Registrate;
import net.minecraftforge.common.util.Lazy;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.slf4j.Logger;
// The value here should match an entry in the META-INF/mods.toml file
@Mod("trading_station")
public class TradingStation
{
// Directly reference a slf4j logger
public static final Logger LOGGER = LogUtils.getLogger();
public static final String MODID = "trading_station";
public static final String DISPLAY_NAME = "Trading Station";
public static IEventBus modEventBus;
private static final Lazy<Registrate> REGISTRATE = Lazy.of(() -> Registrate.create(MODID));
public static final boolean withCreate = ModList.get().isLoaded("create");
public static final Gson GSON = new GsonBuilder().setPrettyPrinting()
.disableHtmlEscaping()
.create();
public TradingStation()
{
modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
ModCreativeTab modTab = new ModCreativeTab();
ModBlocks.register();
ModBlockEntities.register();
ModRecipes.register(modEventBus);
ModMessages.register();
ModMenus.register();
Config.register();
registrate().addRawLang("itemGroup.trading_station:main", "Trading Station");
registrate().addRawLang(ModLang.key("block.display"), "Trading Station");
registrate().addRawLang(ModLang.key("recipe"), "Trading recipe");
registrate().addRawLang(ModLang.key("tooltip.progress"), "Progress: %d%%");
registrate().addRawLang(ModLang.key("select_target.title"), "Select an output target");
registrate().addRawLang(ModLang.key("select_target.button"), "Select target");
registrate().addRawLang(ModLang.key("select_target.clear"), "Clear");
registrate().addRawLang("config.jade.plugin_trading_station.trading_station_data", "Trading Station data");
}
public static Registrate registrate() {
return REGISTRATE.get();
}
public static ResourceLocation asResource(String path) {
return new ResourceLocation(MODID, path);
}
}

View File

@@ -0,0 +1,35 @@
package com.oierbravo.trading_station.compat.crafttweaker;
import com.blamejared.crafttweaker.api.recipe.component.IDecomposedRecipe;
import com.blamejared.crafttweaker.api.recipe.handler.IRecipeHandler;
import com.blamejared.crafttweaker.api.recipe.manager.base.IRecipeManager;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.Recipe;
import java.util.Optional;
@IRecipeHandler.For(TradingRecipe.class)
public class TradingRecipeHandler implements IRecipeHandler<TradingRecipe>{
@Override
public String dumpToCommandString(IRecipeManager<? super TradingRecipe> manager, TradingRecipe recipe) {
return manager.getCommandString() + recipe.toString() + recipe.getOutput() + "[" + recipe.getIngredient() + "]";
}
@Override
public <U extends Recipe<?>> boolean doesConflict(IRecipeManager<? super TradingRecipe> manager, TradingRecipe firstRecipe, U secondRecipe) {
return false;
}
@Override
public Optional<IDecomposedRecipe> decompose(IRecipeManager<? super TradingRecipe> manager, TradingRecipe recipe) {
return Optional.empty();
}
@Override
public Optional<TradingRecipe> recompose(IRecipeManager<? super TradingRecipe> manager, ResourceLocation name, IDecomposedRecipe recipe) {
return Optional.empty();
}
}

View File

@@ -0,0 +1,46 @@
package com.oierbravo.trading_station.compat.crafttweaker;
import com.blamejared.crafttweaker.api.CraftTweakerAPI;
import com.blamejared.crafttweaker.api.action.recipe.ActionAddRecipe;
import com.blamejared.crafttweaker.api.annotation.ZenRegister;
import com.blamejared.crafttweaker.api.fluid.IFluidStack;
import com.blamejared.crafttweaker.api.ingredient.IIngredient;
import com.blamejared.crafttweaker.api.recipe.manager.base.IRecipeManager;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.RecipeType;
import org.openzen.zencode.java.ZenCodeType;
@ZenRegister
@ZenCodeType.Name("mods.trading_station.TradingManager")
//@Document("mods/trading_station/melting")
public class TradingRecipeManager implements IRecipeManager<TradingRecipe> {
/**
* Adds a Trading recipe.
*
* @param name The name of the recipe
* @param output The output fluidStack of the recipe.
* @param input The input of the recipe.
* @param processingTime The duration of the recipe (default 100 ticks)
* @param heatLevel Minimum heat level
*
* @docParam name "meltDown"
* @docParam output <fluid:minecraft:lava> * 100
* @docParam input <item:minecraft:dirt>
* @docParam duration 200
* @docParam heatLevel 2
*/
@ZenCodeType.Method
public void addRecipe(String name, IFluidStack output, IIngredient input, int processingTime, int heatLevel ){
name = fixRecipeName(name);
ResourceLocation resourceLocation = new ResourceLocation(TradingStation.MODID, name);
CraftTweakerAPI.apply(new ActionAddRecipe<>( this, new TradingRecipe(resourceLocation, output.getInternal(), input.asVanillaIngredient(), processingTime, heatLevel)));
}
@Override
public RecipeType<TradingRecipe> getRecipeType() {
return TradingRecipe.Type.INSTANCE;
}
}

View File

@@ -0,0 +1,45 @@
package com.oierbravo.trading_station.compat.jade;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import snownee.jade.api.BlockAccessor;
import snownee.jade.api.IBlockComponentProvider;
import snownee.jade.api.IServerDataProvider;
import snownee.jade.api.ITooltip;
import snownee.jade.api.config.IPluginConfig;
import snownee.jade.api.ui.IElementHelper;
import snownee.jade.api.ui.IProgressStyle;
public class ProgressComponentProvider implements IBlockComponentProvider, IServerDataProvider<BlockEntity> {
@Override
public void appendTooltip(ITooltip tooltip, BlockAccessor accessor, IPluginConfig config) {
//CompoundTag serverData = accessor.getServerData();
if (accessor.getServerData().contains("trading_station.progress")) {
int progress = accessor.getServerData().getInt("trading_station.progress");
IElementHelper elementHelper = tooltip.getElementHelper();
IProgressStyle progressStyle = elementHelper.progressStyle();
if(progress > 0)
tooltip.add(elementHelper.progress((float)progress / 100, Component.translatable("trading_station.tooltip.progress", progress), progressStyle,elementHelper.borderStyle()));
}
}
@Override
public void appendServerData(CompoundTag compoundTag, ServerPlayer serverPlayer, Level level, BlockEntity blockEntity, boolean b) {
if(blockEntity instanceof TradingStationBlockEntity){
TradingStationBlockEntity trading_station = (TradingStationBlockEntity) blockEntity;
compoundTag.putInt("trading_station.progress",trading_station.getProgressPercent());
}
}
@Override
public ResourceLocation getUid() {
return TradingStationPlugin.TRADING_STATION_DATA;
}
}

View File

@@ -0,0 +1,22 @@
package com.oierbravo.trading_station.compat.jade;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlock;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import net.minecraft.resources.ResourceLocation;
import snownee.jade.api.*;
@WailaPlugin
public class TradingStationPlugin implements IWailaPlugin {
public static final ResourceLocation TRADING_STATION_DATA = TradingStation.asResource("trading_station_data");
@Override
public void register(IWailaCommonRegistration registration) {
registration.registerBlockDataProvider(new ProgressComponentProvider(), TradingStationBlockEntity.class);
}
@Override
public void registerClient(IWailaClientRegistration registration) {
registration.registerBlockComponent(new ProgressComponentProvider(), TradingStationBlock.class);
}
}

View File

@@ -0,0 +1,49 @@
package com.oierbravo.trading_station.compat.jei;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import com.oierbravo.trading_station.content.trading_station.TradingStationScreen;
import com.oierbravo.trading_station.registrate.ModBlocks;
import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.registration.IGuiHandlerRegistration;
import mezz.jei.api.registration.IRecipeCatalystRegistration;
import mezz.jei.api.registration.IRecipeCategoryRegistration;
import mezz.jei.api.registration.IRecipeRegistration;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeManager;
import java.util.List;
import java.util.Objects;
@JeiPlugin
public class JEIPlugin implements IModPlugin {
@Override
public ResourceLocation getPluginUid() {
return new ResourceLocation(TradingStation.MODID, "jei_plugin");
}
@Override
public void registerCategories(IRecipeCategoryRegistration registration) {
registration.addRecipeCategories(new
TradingRecipeCategory(registration.getJeiHelpers().getGuiHelper()));
}
@Override
public void registerRecipeCatalysts(IRecipeCatalystRegistration registration) {
registration.addRecipeCatalyst(new ItemStack(ModBlocks.TRADING_STATION.get()),new RecipeType<>(TradingRecipeCategory.UID, TradingRecipe.class));
}
@Override
public void registerRecipes(IRecipeRegistration registration) {
RecipeManager rm = Objects.requireNonNull(Minecraft.getInstance().level).getRecipeManager();
List<TradingRecipe> tradingRecipes = rm.getAllRecipesFor(TradingRecipe.Type.INSTANCE);
registration.addRecipes(new RecipeType<>(TradingRecipeCategory.UID, TradingRecipe.class), tradingRecipes);
}
}

View File

@@ -0,0 +1,128 @@
package com.oierbravo.trading_station.compat.jei;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.mojang.blaze3d.vertex.PoseStack;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.registrate.ModBlocks;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.gui.drawable.IDrawableAnimated;
import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.IFocusGroup;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import mezz.jei.common.Constants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import javax.annotation.Nonnull;
import java.util.Arrays;
public class TradingRecipeCategory implements IRecipeCategory<TradingRecipe> {
public final static ResourceLocation UID = new ResourceLocation(TradingStation.MODID, "trading");
private final LoadingCache<Integer, IDrawableAnimated> cachedArrows;
private final IDrawable background;
private final IDrawable icon;
public TradingRecipeCategory(IGuiHelper helper) {
this.cachedArrows = CacheBuilder.newBuilder()
.maximumSize(25)
.build(new CacheLoader<>() {
@Override
public IDrawableAnimated load(Integer cookTime) {
return helper.drawableBuilder(Constants.RECIPE_GUI_VANILLA, 82, 128, 24, 17)
.buildAnimated(cookTime, IDrawableAnimated.StartDirection.LEFT, false);
}
});
this.background = new IDrawable() {
@Override
public int getWidth() {
return 176;
}
@Override
public int getHeight() {
return 45;
}
@Override
public void draw(PoseStack poseStack, int xOffset, int yOffset) {
}
};
this.icon = helper.createDrawableIngredient(VanillaTypes.ITEM_STACK, new ItemStack(ModBlocks.TRADING_STATION.get()));
}
protected IDrawableAnimated getArrow() {
return this.cachedArrows.getUnchecked(50);
}
@Override
public RecipeType<TradingRecipe> getRecipeType() {
return RecipeType.create("trading_station","trading", TradingRecipe.class);
}
@Override
public Component getTitle() {
return ModLang.translate("trading.recipe");
}
@Override
public IDrawable getBackground() {
return this.background;
}
@Override
public IDrawable getIcon() {
return this.icon;
}
@Override
public void setRecipe(@Nonnull IRecipeLayoutBuilder builder, @Nonnull TradingRecipe recipe, @Nonnull IFocusGroup focusGroup) {
NonNullList<Ingredient> ingredients = recipe.getIngredients();
for(int index = 0; index < ingredients.size(); index++) {
Ingredient ing = ingredients.get(index);
builder.addSlot(RecipeIngredientRole.INPUT, 41 + index * 18, 11)
.addIngredients(ingredients.get(index));
//.addItemStacks(Arrays.asList(ingredients.get(0).getItems()));
}
builder.addSlot(RecipeIngredientRole.OUTPUT, 113, 11)
.addItemStack(recipe.getResultItem());
}
@Override
public void draw(TradingRecipe recipe, IRecipeSlotsView recipeSlotsView, PoseStack stack, double mouseX, double mouseY) {
IRecipeCategory.super.draw(recipe, recipeSlotsView, stack, mouseX, mouseY);
IDrawableAnimated arrow = getArrow();
arrow.draw(stack, 75, 14);
drawProcessingTime(recipe, stack, 81,4);
}
protected void drawProcessingTime(TradingRecipe recipe, PoseStack poseStack, int x, int y) {
int processingTime = recipe.getProcessingTime();
if (processingTime > 0) {
int cookTimeSeconds = processingTime / 20;
MutableComponent timeString = Component.translatable("gui.jei.category.smelting.time.seconds", cookTimeSeconds);
Minecraft minecraft = Minecraft.getInstance();
Font fontRenderer = minecraft.font;
fontRenderer.draw(poseStack, timeString, x, y, 0xFF808080);
}
}
}

View File

@@ -0,0 +1,12 @@
package com.oierbravo.trading_station.compat.kubejs;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import dev.latvian.mods.kubejs.recipe.schema.RegisterRecipeSchemasEvent;
public class KubeJSPlugin extends dev.latvian.mods.kubejs.KubeJSPlugin {
@Override
public void registerRecipeSchemas(RegisterRecipeSchemasEvent event) {
event.register(TradingRecipe.Serializer.ID, TradingRecipeSchema.SCHEMA);
}
}

View File

@@ -0,0 +1,29 @@
package com.oierbravo.trading_station.compat.kubejs;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import dev.latvian.mods.kubejs.item.InputItem;
import dev.latvian.mods.kubejs.item.OutputItem;
import dev.latvian.mods.kubejs.recipe.RecipeJS;
import dev.latvian.mods.kubejs.recipe.RecipeKey;
import dev.latvian.mods.kubejs.recipe.component.ItemComponents;
import dev.latvian.mods.kubejs.recipe.component.NumberComponent;
import dev.latvian.mods.kubejs.recipe.schema.RecipeSchema;
public interface TradingRecipeSchema {
RecipeKey<InputItem[]> INGREDIENTS = ItemComponents.INPUT_ARRAY.key("ingredients");
RecipeKey<OutputItem> RESULT = ItemComponents.OUTPUT.key("result");
RecipeKey<Integer> PROCESSING_TIME = NumberComponent.INT.key("processingTime").optional(1);
public class TradingRecipeJS extends RecipeJS{
@Override
public JsonElement writeInputItem(InputItem value) {
JsonObject json = super.writeInputItem(value).getAsJsonObject();
if(value.count > 1){
json.addProperty("count", value.count);
}
return (JsonElement) json;
}
}
RecipeSchema SCHEMA = new RecipeSchema(TradingRecipeJS.class, TradingRecipeJS::new, RESULT, INGREDIENTS, PROCESSING_TIME);
}

View File

@@ -0,0 +1,416 @@
package com.oierbravo.trading_station.content.trading_station;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.network.packets.ItemStackSyncS2CPacket;
import com.oierbravo.trading_station.registrate.ModMessages;
import com.oierbravo.trading_station.registrate.ModRecipes;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Containers;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
import java.util.Optional;
public abstract class AbstractTradingStationBlockEntity extends BlockEntity {
private CompoundTag updateTag;
public final ItemStackHandler inputItems = createInputItemHandler();
public final ItemStackHandler outputItems = createOutputItemHandler();
public final ItemStackHandler targetItemHandler = createTargetItemHandler();
private final LazyOptional<IItemHandler> inputItemHandler = LazyOptional.of(() -> inputItems);
private final LazyOptional<IItemHandler> outputItemHandler = LazyOptional.of(() -> outputItems);
public int progress = 0;
public int maxProgress = 1;
private BlockState lastBlockState;
protected final ContainerData containerData;
private Item preferedItem;
public AbstractTradingStationBlockEntity(BlockEntityType<?> pType, BlockPos pWorldPosition, BlockState pBlockState) {
super(pType, pWorldPosition, pBlockState);
updateTag = getPersistentData();
lastBlockState = this.getBlockState();
preferedItem = ItemStack.EMPTY.getItem();
containerData = AbstractTradingStationBlockEntity.createContainerData(this);
}
public static ContainerData createContainerData(AbstractTradingStationBlockEntity pBlockEntity){
return new ContainerData(){
@Override
public int get(int pIndex){
return switch (pIndex) {
case 0 -> pBlockEntity.progress;
case 1 -> pBlockEntity.maxProgress;
default -> 0;
};
}
@Override
public void set(int pIndex, int pValue) {
switch (pIndex) {
case 0 -> pBlockEntity.progress = pValue;
case 1 -> pBlockEntity.maxProgress = pValue;
}
}
@Override
public int getCount() {
return 2;
}
};
}
@NotNull
@Nonnull
private ItemStackHandler createTargetItemHandler() {
return new ItemStackHandler(1) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot,this.getStackInSlot(0), worldPosition, ItemStackSyncS2CPacket.SlotType.TARGET));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return true;
//return canProcess(stack) && super.isItemValid(slot, stack);
}
@Override
public @NotNull ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) {
return ItemStack.EMPTY;
}
@Override
public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) {
return ItemStack.EMPTY;
}
};
}
private ItemStackHandler createInputItemHandler() {
return new ItemStackHandler(2) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot,this.getStackInSlot(0), worldPosition, ItemStackSyncS2CPacket.SlotType.INPUT));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return true;
//return canProcess(stack) && super.isItemValid(slot, stack);
}
};
}
@NotNull
@Nonnull
private ItemStackHandler createOutputItemHandler() {
return new ItemStackHandler(1) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot, this.getStackInSlot(slot), worldPosition, ItemStackSyncS2CPacket.SlotType.OUTPUT));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return canProcess(stack) && super.isItemValid(slot, stack);
//return false;
}
};
}
@Override
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
if (cap == ForgeCapabilities.ITEM_HANDLER) {
return inputItemHandler.cast();
}
return super.getCapability(cap, side);
}
@Override
public void setRemoved() {
super.setRemoved();
inputItemHandler.invalidate();
outputItemHandler.invalidate();
}
public LazyOptional<IItemHandler> getInputItemHandler(){
return inputItemHandler;
}
public LazyOptional<IItemHandler> getOutputItemHandler(){
return outputItemHandler;
}
@Override
public void onLoad() {
super.onLoad();
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
inputItemHandler.invalidate();
outputItemHandler.invalidate();
}
@Override
protected void saveAdditional(@NotNull CompoundTag tag) {
super.saveAdditional(tag);
tag.put("input", inputItems.serializeNBT());
tag.put("output", outputItems.serializeNBT());
tag.put("target", targetItemHandler.serializeNBT());
tag.putInt("trading_station.progress", progress);
tag.putInt("trading_station.maxProgress", maxProgress);
String preferedItemString = ForgeRegistries.ITEMS.getKey(preferedItem).toString();
}
@Override
public void load(CompoundTag tag) {
super.load(tag);
inputItems.deserializeNBT(tag.getCompound("input"));
outputItems.deserializeNBT(tag.getCompound("output"));
targetItemHandler.deserializeNBT(tag.getCompound("target"));
progress = tag.getInt("trading_station.progress");
maxProgress = tag.getInt("trading_station.maxProgress");
String preferedItemString = tag.getString("trading_station.preferedItem");
preferedItem = ForgeRegistries.ITEMS.getValue( ResourceLocation.tryParse(preferedItemString));
}
public void drops() {
SimpleContainer inventory = new SimpleContainer(inputItems.getSlots() + 1);
for (int i = 0; i < inputItems.getSlots(); i++) {
inventory.setItem(i, inputItems.getStackInSlot(i));
}
inventory.setItem(inputItems.getSlots(), inputItems.getStackInSlot(0));
Containers.dropContents(this.level, this.worldPosition, inventory);
}
public void resetProgress() {
this.progress = 0;
this.maxProgress = 1;
}
protected static Optional<TradingRecipe> getRecipe(AbstractTradingStationBlockEntity pBlockEntity){
Level level = pBlockEntity.getLevel();
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
if(!pBlockEntity.targetItemHandler.getStackInSlot(0).isEmpty())
return ModRecipes.findByOutput(level,pBlockEntity.targetItemHandler.getStackInSlot(0));
return ModRecipes.find(inputInventory,level);
// return level.getRecipeManager().getRecipeFor(TradingRecipe.Type.INSTANCE, inputInventory, level);
}
protected int getProcessingTime(AbstractTradingStationBlockEntity pBlockEntity) {
return getRecipe(pBlockEntity).map(TradingRecipe::getProcessingTime).orElse(1);
}
public static void tick(Level pLevel, BlockPos pPos, BlockState pState, AbstractTradingStationBlockEntity pBlockEntity) {
if(pLevel.isClientSide()) {
return;
}
if(!isPowered(pBlockEntity))
return;
if (canCraftItem(pBlockEntity)) {
pBlockEntity.progress += 1;
BlockEntity.setChanged(pLevel, pPos, pState);
pBlockEntity.maxProgress = pBlockEntity.getProcessingTime(pBlockEntity);
if (pBlockEntity.progress > pBlockEntity.maxProgress) {
AbstractTradingStationBlockEntity.craftItem(pBlockEntity);
}
BlockEntity.setChanged(pLevel, pPos, pState);
} else {
pBlockEntity.resetProgress();
BlockEntity.setChanged(pLevel, pPos, pState);
}
}
protected static void updateProgress(AbstractTradingStationBlockEntity pBlockEntity){
pBlockEntity.progress += 1;
}
private static boolean isPowered(AbstractTradingStationBlockEntity pBlockEntity){
return pBlockEntity.getLevel().getBlockState(pBlockEntity.getBlockPos())
.getValue(BlockStateProperties.POWERED);
}
private static SimpleContainer getInputInventory(AbstractTradingStationBlockEntity pBlockEntity){
int containerSize = 0;
for(int index = 0; index < pBlockEntity.inputItems.getSlots(); index++) {
if (!pBlockEntity.inputItems.getStackInSlot(index).isEmpty())
containerSize++;
}
SimpleContainer inputInventory = new SimpleContainer(containerSize);
pBlockEntity.inputItemHandler.ifPresent(iItemHandler -> {
for(int slot = 0; slot < iItemHandler.getSlots(); slot++) {
if(!iItemHandler.getStackInSlot(slot).isEmpty()){
inputInventory.addItem(iItemHandler.getStackInSlot(slot));
}
}
});
return inputInventory;
}
private static void craftItem(AbstractTradingStationBlockEntity pBlockEntity) {
Level level = pBlockEntity.getLevel();
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
Optional<TradingRecipe> recipe = getRecipe(pBlockEntity);
if(recipe.isPresent()){
for (int i = 0; i < recipe.get().getIngredients().size(); i++) {
Ingredient ingredient = recipe.get().getIngredients().get(i);
for (int slot = 0; slot < pBlockEntity.inputItems.getSlots(); slot++) {
ItemStack itemStack = pBlockEntity.inputItems.getStackInSlot(slot);
if(ingredient.test(itemStack)){
pBlockEntity.inputItems.extractItem(slot,ingredient.getItems()[0].getCount(),false);
inputInventory.setChanged();
}
}
}
pBlockEntity.outputItems.insertItem(0, recipe.get().getResultItem(), false);
}
pBlockEntity.resetProgress();
pBlockEntity.setChanged();
}
static boolean canCraftItem(AbstractTradingStationBlockEntity pBlockEntity) {
Level level = pBlockEntity.getLevel();
if(level == null)
return false;
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
Optional<TradingRecipe> match = getRecipe(pBlockEntity);
if(match.isEmpty()) {
return false;
}
//return false;
return match.isPresent()
&& AbstractTradingStationBlockEntity.hasEnoughInputItems(inputInventory,match.get().getIngredients())
&& AbstractTradingStationBlockEntity.hasEnoughOutputSpace(pBlockEntity.outputItems,match.get().getResultItem());
}
private boolean canProcess(ItemStack stack) {
return getRecipe(this).isPresent();
}
protected static boolean hasEnoughInputItems(SimpleContainer inventory, NonNullList<Ingredient> ingredients){
int enough = 0;
for(int ingredientIndex = 0; ingredientIndex < ingredients.size();ingredientIndex ++){
Ingredient ingredient = ingredients.get(ingredientIndex);
for(int slot = 0; slot < inventory.getContainerSize(); slot++){
if(ingredient.test(inventory.getItem(slot))){
if(inventory.getItem(slot).getCount() >= ingredient.getItems()[0].getCount() )
enough++;
}
}
}
return ingredients.size() == enough;
}
protected static boolean hasEnoughOutputSpace(ItemStackHandler stackHandler,ItemStack resultItemStack){
return stackHandler.getStackInSlot(0).isEmpty() || stackHandler.getStackInSlot(0).is(resultItemStack.getItem()) && stackHandler.getStackInSlot(0).getMaxStackSize() - stackHandler.getStackInSlot(0).getCount() >= resultItemStack.getCount() ;
}
@Override
public CompoundTag getUpdateTag() {
this.saveAdditional(updateTag);
return updateTag;
}
@Nullable
@Override
public ClientboundBlockEntityDataPacket getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
@Override
public void handleUpdateTag(CompoundTag tag) {
this.load(tag);
}
@Override
public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) {
this.load(pkt.getTag());
}
public int getProgressPercent() {
return this.progress * 100 / this.maxProgress;
}
public void setItemStack(int slot, ItemStack itemStack,ItemStackSyncS2CPacket.SlotType slotType) {
if(slotType == ItemStackSyncS2CPacket.SlotType.INPUT)
inputItems.setStackInSlot(slot,itemStack);
else if (slotType == ItemStackSyncS2CPacket.SlotType.OUTPUT)
outputItems.setStackInSlot(slot,itemStack);
else if (slotType == ItemStackSyncS2CPacket.SlotType.TARGET)
targetItemHandler.setStackInSlot(slot,itemStack);
}
public void setPreferedItem(ItemStack itemStack) {
this.targetItemHandler.setStackInSlot(0,itemStack);
}
public ItemStack getPreferedItemStack() {
return targetItemHandler.getStackInSlot(0);
}
public ItemStackHandler getTargetItemHandler(){
return targetItemHandler;
}
}

View File

@@ -0,0 +1,149 @@
package com.oierbravo.trading_station.content.trading_station;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.platform.Lighting;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.ItemStack;
/**
* This class can be used to render a 2D ItemStack to the screen with optional transparency. The item being rendered
* doesn't need to represent a real ItemStack held in an inventory or container.
*/
@SuppressWarnings("unused")
public class FakeItemRenderer {
private static final Minecraft MINECRAFT = Minecraft.getInstance();
private static final ItemRenderer ITEM_RENDERER = MINECRAFT.getItemRenderer();
private static final TextureManager TEXTURE_MANAGER = MINECRAFT.getTextureManager();
public static void renderFakeItem(ItemStack pItemStack, int pX, int pY) {
renderFakeItem(pItemStack, pX, pY, 1.0F);
}
public static void renderFakeItem(ItemStack pItemStack, int pX, int pY, float pAlpha) {
if (!pItemStack.isEmpty()) {
BakedModel model = getBakedModel(pItemStack);
TEXTURE_MANAGER.getTexture(InventoryMenu.BLOCK_ATLAS).setFilter(true, false);
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
RenderSystem.enableBlend();
PoseStack modelViewStack = RenderSystem.getModelViewStack();
modelViewStack.pushPose();
modelViewStack.translate(pX + 8.0D, pY + 8.0D, 0F);
modelViewStack.scale(16.0F, -16.0F, 16.0F);
RenderSystem.applyModelViewMatrix();
if (!model.usesBlockLight()) {
Lighting.setupForFlatItems();
}
MultiBufferSource.BufferSource bufferSource = MINECRAFT.renderBuffers().bufferSource();
ITEM_RENDERER.render(pItemStack,
ItemTransforms.TransformType.GUI,
false,
new PoseStack(),
getWrappedBuffer(bufferSource, pAlpha),
LightTexture.FULL_BRIGHT,
OverlayTexture.NO_OVERLAY,
model);
bufferSource.endBatch();
RenderSystem.enableDepthTest();
if (!model.usesBlockLight()) {
Lighting.setupFor3DItems();
}
modelViewStack.popPose();
RenderSystem.applyModelViewMatrix();
}
}
private static MultiBufferSource getWrappedBuffer(MultiBufferSource pBufferSource, float pAlpha) {
return pRenderType -> new WrappedVertexConsumer(pBufferSource.getBuffer(RenderType.entityTranslucent(InventoryMenu.BLOCK_ATLAS)), 1F, 1F, 1F, pAlpha);
}
private static BakedModel getBakedModel(ItemStack pItemStack) {
return ITEM_RENDERER.getModel(pItemStack, null, MINECRAFT.player, 0);
}
}
class WrappedVertexConsumer implements VertexConsumer {
protected final VertexConsumer consumer;
protected final float red;
protected final float green;
protected final float blue;
protected final float alpha;
public WrappedVertexConsumer(VertexConsumer pConsumer, float pRed, float pGreen, float pBlue, float pAlpha) {
this.consumer = pConsumer;
this.red = pRed;
this.green = pGreen;
this.blue = pBlue;
this.alpha = pAlpha;
}
@Override
public VertexConsumer vertex(double pX, double pY, double pZ) {
return consumer.vertex(pX, pY, pZ);
}
@Override
public VertexConsumer color(int pRed, int pGreen, int pBlue, int pAlpha) {
return consumer.color((int)(pRed * red), (int)(pGreen * green), (int)(pBlue * blue), (int)(pAlpha * alpha));
}
@Override
public VertexConsumer uv(float pU, float pV) {
return consumer.uv(pU, pV);
}
@Override
public VertexConsumer overlayCoords(int pU, int pV) {
return consumer.overlayCoords(pU, pV);
}
@Override
public VertexConsumer uv2(int pU, int pV) {
return consumer.uv2(pU, pV);
}
@Override
public VertexConsumer normal(float pX, float pY, float pZ) {
return consumer.normal(pX, pY, pZ);
}
@Override
public void endVertex() {
consumer.endVertex();
}
@Override
public void defaultColor(int pDefaultR, int pDefaultG, int pDefaultB, int pDefaultA) {
consumer.defaultColor(pDefaultR, pDefaultG, pDefaultB, pDefaultA);
}
@Override
public void unsetDefaultColor() {
consumer.unsetDefaultColor();
}
}

View File

@@ -0,0 +1,181 @@
package com.oierbravo.trading_station.content.trading_station;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingRecipeBuilder.TradingRecipeParams;
import net.minecraft.core.NonNullList;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.*;
import net.minecraft.world.level.Level;
public class TradingRecipe implements Recipe<SimpleContainer> {
private final ResourceLocation id;
private final NonNullList<Ingredient> itemIngredients;
private final ItemStack result;
private final int processingTime;
public TradingRecipe(TradingRecipeParams params) {
this.id = params.id;
this.result = params.result;
this.itemIngredients = params.itemIngredients;
this.processingTime = params.processingTime;
}
@Override
public boolean matches(SimpleContainer pContainer, Level pLevel) {
if(pLevel.isClientSide)
return false;
if(pContainer.getContainerSize() != itemIngredients.size())
return false;
int matchedIngredients = 0;
for (int i = 0; i < itemIngredients.size(); i++) {
Ingredient ingredient = itemIngredients.get(i);
for (int slot = 0; slot < pContainer.getContainerSize(); slot++) {
ItemStack itemStack = pContainer.getItem(slot);
if(ingredient.test(pContainer.getItem(slot))){
matchedIngredients++;
}
}
return matchedIngredients == itemIngredients.size();
}
return false;
}
public boolean matches(SimpleContainer pContainer, Level pLevel, ItemStack preferedOutput){
return false;
}
public boolean matchesOutput(ItemStack targetItemStack){
return result.sameItem(targetItemStack);
}
@Override
public NonNullList<Ingredient> getIngredients() {
return itemIngredients;
}
@Override
public ItemStack assemble(SimpleContainer pContainer) {
return result.copy();
}
@Override
public boolean canCraftInDimensions(int pWidth, int pHeight) {
return true;
}
@Override
public ItemStack getResultItem() {
return result.copy();
}
public ItemStack getResult(){
return result.copy();
}
@Override
public ResourceLocation getId() {
return id;
}
@Override
public RecipeSerializer<?> getSerializer() {
return Serializer.INSTANCE;
}
@Override
public RecipeType<?> getType() {
return Type.INSTANCE;
}
public static class Type implements RecipeType<TradingRecipe> {
private Type() { }
public static final Type INSTANCE = new Type();
public static final String ID = "trading";
}
public static class Serializer implements RecipeSerializer<TradingRecipe> {
public static final Serializer INSTANCE = new Serializer();
public static final ResourceLocation ID =
new ResourceLocation(TradingStation.MODID,"trading");
@Override
public TradingRecipe fromJson(ResourceLocation id, JsonObject json) {
TradingRecipeBuilder builder = new TradingRecipeBuilder(id);
NonNullList<Ingredient> itemIngredients = NonNullList.create();
int processingTime = 1;
for (JsonElement je : GsonHelper.getAsJsonArray(json, "ingredients")) {
JsonObject jsonObject = je.getAsJsonObject();
Ingredient ingredient = Ingredient.fromJson(jsonObject);
if(jsonObject.has("count")){
ItemStack itemStack = ingredient.getItems()[0];
itemStack.setCount(jsonObject.get("count").getAsInt());
}
itemIngredients.add(ingredient);
}
ItemStack result = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "result"));
if(GsonHelper.isValidNode(json,"processingTime")){
processingTime = GsonHelper.getAsInt(json,"processingTime");
}
builder.withItemIngredients(itemIngredients)
.withSingleItemOutput(result)
.processingTime(processingTime);
return builder.build();
}
@Override
public TradingRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
TradingRecipeBuilder builder = new TradingRecipeBuilder(id);
NonNullList<Ingredient> itemIngredients = NonNullList.create();
int processingTime = 1;
int size = buffer.readVarInt();
for (int i = 0; i < size; i++)
itemIngredients.add(Ingredient.fromNetwork(buffer));
ItemStack result = buffer.readItem();
processingTime = buffer.readInt();
builder.withItemIngredients(itemIngredients)
.withSingleItemOutput(result)
.processingTime(processingTime);
return builder.build();
}
@Override
public void toNetwork(FriendlyByteBuf buffer, TradingRecipe recipe) {
NonNullList<Ingredient> itemIngredients = recipe.itemIngredients;
int processingTime = recipe.getProcessingTime();
buffer.writeVarInt(itemIngredients.size());
itemIngredients.forEach(i -> i.toNetwork(buffer));
buffer.writeItem(recipe.getResultItem());
buffer.writeInt(processingTime);
}
}
public int getProcessingTime() {
return processingTime;
}
}

View File

@@ -0,0 +1,66 @@
package com.oierbravo.trading_station.content.trading_station;
import net.minecraft.core.NonNullList;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraftforge.common.crafting.conditions.ICondition;
import java.util.ArrayList;
import java.util.List;
public class TradingRecipeBuilder {
protected TradingRecipeParams params;
protected List<ICondition> recipeConditions;
public TradingRecipeBuilder(ResourceLocation recipeId) {
params = new TradingRecipeParams(recipeId);
recipeConditions = new ArrayList<>();
}
public TradingRecipeBuilder withItemIngredients(Ingredient... itemIngredients) {
return withItemIngredients(NonNullList.of(Ingredient.EMPTY, itemIngredients));
}
public TradingRecipeBuilder withItemIngredients(NonNullList<Ingredient> itemIngredients) {
params.itemIngredients = itemIngredients;
return this;
}
public TradingRecipeBuilder withSingleItemOutput(ItemStack output) {
params.result = output;
return this;
}
public TradingRecipeBuilder processingTime(int time) {
params.processingTime = time;
return this;
}
public TradingRecipe build(){
return new TradingRecipe(params);
}
public static class TradingRecipeParams {
protected ResourceLocation id;
protected NonNullList<Ingredient> itemIngredients;
protected ItemStack result;
protected int fuelConsumed;
protected int processingTime;
protected TradingRecipeParams(ResourceLocation id) {
this.id = id;
itemIngredients = NonNullList.create();
result = ItemStack.EMPTY;
fuelConsumed = 0;
processingTime = 1;
}
}
}

View File

@@ -0,0 +1,135 @@
package com.oierbravo.trading_station.content.trading_station;
import com.oierbravo.trading_station.registrate.ModBlockEntities;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
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.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
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.BooleanProperty;
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.minecraftforge.network.NetworkHooks;
import org.jetbrains.annotations.Nullable;
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING;
public class TradingStationBlock extends BaseEntityBlock {
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
private static final VoxelShape RENDER_SHAPE = Shapes.box(0, 0, 0, 1, 1, 1);
//public static final BooleanProperty BOTTOM = BlockStateProperties.BOTTOM;
@SuppressWarnings("deprecation")
@Override
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
return RENDER_SHAPE;
}
@Override
public VoxelShape getCollisionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
return RENDER_SHAPE;
}
public TradingStationBlock(Properties pProperties) {
super(pProperties);
registerDefaultState(getStateDefinition().any().setValue(HORIZONTAL_FACING, Direction.NORTH).setValue(POWERED,false));
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
if (!context.getLevel().getBlockState(context.getClickedPos().above()).canBeReplaced(context))
return null;
return super.getStateForPlacement(context)
.setValue(HORIZONTAL_FACING, context.getHorizontalDirection().getOpposite())
.setValue(POWERED, context.getLevel().hasNeighborSignal(context.getClickedPos()));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HORIZONTAL_FACING).add(POWERED);
}
@Override
public RenderShape getRenderShape(BlockState pState) {
return RenderShape.MODEL;
}
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {
return ModBlockEntities.TRADING_STATION.create(pPos, pState);
}
@Override
public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, RandomSource r) {
boolean previouslyPowered = state.getValue(POWERED);
if (previouslyPowered != worldIn.hasNeighborSignal(pos))
worldIn.setBlock(pos, state.cycle(POWERED), 2);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level pLevel, BlockState pState, BlockEntityType<T> pBlockEntityType) {
return createTickerHelper(pBlockEntityType, ModBlockEntities.TRADING_STATION.get(),
TradingStationBlockEntity::tick);
}
@Override
public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
boolean isMoving) {
super.neighborChanged(state, worldIn, pos, blockIn, fromPos, isMoving);
if (worldIn.isClientSide)
return;
if (!worldIn.getBlockTicks()
.willTickThisTick(pos, this))
worldIn.scheduleTick(pos, this, 0);
}
@Override
public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) {
if (pState.getBlock() != pNewState.getBlock()) {
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
if (blockEntity instanceof TradingStationBlockEntity) {
((TradingStationBlockEntity) blockEntity).drops();
}
}
super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving);
}
@Override
public InteractionResult use(BlockState state, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand handIn, BlockHitResult hit) {
if (!pLevel.isClientSide()) {
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
if(blockEntity instanceof TradingStationBlockEntity) {
NetworkHooks.openScreen(((ServerPlayer)pPlayer), (TradingStationBlockEntity)blockEntity, pPos);
} else {
throw new IllegalStateException("Our Container provider is missing!");
}
}
return InteractionResult.sidedSuccess(pLevel.isClientSide());
}
}

View File

@@ -0,0 +1,434 @@
package com.oierbravo.trading_station.content.trading_station;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.network.packets.ItemStackSyncS2CPacket;
import com.oierbravo.trading_station.registrate.ModMessages;
import com.oierbravo.trading_station.registrate.ModRecipes;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Containers;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.ShapelessRecipe;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.registries.ForgeRegistries;
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.Optional;
public class TradingStationBlockEntity extends BlockEntity implements MenuProvider {
//private final int FLUID_CAPACITY = TradingStationConfig.trading_station_CAPACITY.get();
//private static final int FLIUD_PER_TICK = TradingStationConfig.trading_statio_FLUID_PER_TICK.get();
private CompoundTag updateTag;
public final ItemStackHandler inputItems = createInputItemHandler();
public final ItemStackHandler outputItems = createOutputItemHandler();
public final ItemStackHandler targetItemHandler = createTargetItemHandler();
private final LazyOptional<IItemHandler> inputItemHandler = LazyOptional.of(() -> inputItems);
private final LazyOptional<IItemHandler> outputItemHandler = LazyOptional.of(() -> outputItems);
public int progress = 0;
public int maxProgress = 1;
private BlockState lastBlockState;
protected final ContainerData containerData;
private Item preferedItem;
public TradingStationBlockEntity(BlockEntityType<?> pType, BlockPos pWorldPosition, BlockState pBlockState) {
super(pType, pWorldPosition, pBlockState);
updateTag = getPersistentData();
lastBlockState = this.getBlockState();
preferedItem = ItemStack.EMPTY.getItem();
containerData = TradingStationBlockEntity.createContainerData(this);
}
public static ContainerData createContainerData(TradingStationBlockEntity pBlockEntity){
return new ContainerData(){
@Override
public int get(int pIndex){
return switch (pIndex) {
case 0 -> pBlockEntity.progress;
case 1 -> pBlockEntity.maxProgress;
default -> 0;
};
}
@Override
public void set(int pIndex, int pValue) {
switch (pIndex) {
case 0 -> pBlockEntity.progress = pValue;
case 1 -> pBlockEntity.maxProgress = pValue;
}
}
@Override
public int getCount() {
return 2;
}
};
}
@NotNull
@Nonnull
private ItemStackHandler createTargetItemHandler() {
return new ItemStackHandler(1) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot,this.getStackInSlot(0), worldPosition, ItemStackSyncS2CPacket.SlotType.TARGET));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return true;
//return canProcess(stack) && super.isItemValid(slot, stack);
}
@Override
public @NotNull ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) {
return ItemStack.EMPTY;
}
@Override
public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) {
return ItemStack.EMPTY;
}
};
}
private ItemStackHandler createInputItemHandler() {
return new ItemStackHandler(2) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot,this.getStackInSlot(0), worldPosition, ItemStackSyncS2CPacket.SlotType.INPUT));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return true;
//return canProcess(stack) && super.isItemValid(slot, stack);
}
};
}
@NotNull
@Nonnull
private ItemStackHandler createOutputItemHandler() {
return new ItemStackHandler(1) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot, this.getStackInSlot(slot), worldPosition, ItemStackSyncS2CPacket.SlotType.OUTPUT));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return canProcess(stack) && super.isItemValid(slot, stack);
//return false;
}
};
}
@Override
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
if (cap == ForgeCapabilities.ITEM_HANDLER) {
return inputItemHandler.cast();
}
return super.getCapability(cap, side);
}
@Override
public void setRemoved() {
super.setRemoved();
inputItemHandler.invalidate();
outputItemHandler.invalidate();
}
public LazyOptional<IItemHandler> getInputItemHandler(){
return inputItemHandler;
}
public LazyOptional<IItemHandler> getOutputItemHandler(){
return outputItemHandler;
}
@Override
public void onLoad() {
super.onLoad();
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
inputItemHandler.invalidate();
outputItemHandler.invalidate();
}
@Override
protected void saveAdditional(@NotNull CompoundTag tag) {
super.saveAdditional(tag);
tag.put("input", inputItems.serializeNBT());
tag.put("output", outputItems.serializeNBT());
tag.put("target", targetItemHandler.serializeNBT());
tag.putInt("trading_station.progress", progress);
tag.putInt("trading_station.maxProgress", maxProgress);
String preferedItemString = ForgeRegistries.ITEMS.getKey(preferedItem).toString();
}
@Override
public void load(CompoundTag tag) {
super.load(tag);
inputItems.deserializeNBT(tag.getCompound("input"));
outputItems.deserializeNBT(tag.getCompound("output"));
targetItemHandler.deserializeNBT(tag.getCompound("target"));
progress = tag.getInt("trading_station.progress");
maxProgress = tag.getInt("trading_station.maxProgress");
String preferedItemString = tag.getString("trading_station.preferedItem");
preferedItem = ForgeRegistries.ITEMS.getValue( ResourceLocation.tryParse(preferedItemString));
}
public void drops() {
SimpleContainer inventory = new SimpleContainer(inputItems.getSlots() + 1);
for (int i = 0; i < inputItems.getSlots(); i++) {
inventory.setItem(i, inputItems.getStackInSlot(i));
}
inventory.setItem(inputItems.getSlots(), inputItems.getStackInSlot(0));
Containers.dropContents(this.level, this.worldPosition, inventory);
}
public void resetProgress() {
this.progress = 0;
this.maxProgress = 1;
}
protected static Optional<TradingRecipe> getRecipe(TradingStationBlockEntity pBlockEntity){
Level level = pBlockEntity.getLevel();
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
if(!pBlockEntity.targetItemHandler.getStackInSlot(0).isEmpty())
return ModRecipes.findByOutput(level,pBlockEntity.targetItemHandler.getStackInSlot(0));
return ModRecipes.find(inputInventory,level);
// return level.getRecipeManager().getRecipeFor(TradingRecipe.Type.INSTANCE, inputInventory, level);
}
protected int getProcessingTime(TradingStationBlockEntity pBlockEntity) {
return getRecipe(pBlockEntity).map(TradingRecipe::getProcessingTime).orElse(1);
}
public static void tick(Level pLevel, BlockPos pPos, BlockState pState, TradingStationBlockEntity pBlockEntity) {
if(pLevel.isClientSide()) {
return;
}
if(!isPowered(pBlockEntity))
return;
if (canCraftItem(pBlockEntity)) {
pBlockEntity.progress += 1;
BlockEntity.setChanged(pLevel, pPos, pState);
pBlockEntity.maxProgress = pBlockEntity.getProcessingTime(pBlockEntity);
if (pBlockEntity.progress > pBlockEntity.maxProgress) {
TradingStationBlockEntity.craftItem(pBlockEntity);
}
BlockEntity.setChanged(pLevel, pPos, pState);
} else {
pBlockEntity.resetProgress();
BlockEntity.setChanged(pLevel, pPos, pState);
}
}
protected static void updateProgress(TradingStationBlockEntity pBlockEntity){
pBlockEntity.progress += 1;
}
private static boolean isPowered(TradingStationBlockEntity pBlockEntity){
return pBlockEntity.getLevel().getBlockState(pBlockEntity.getBlockPos())
.getValue(BlockStateProperties.POWERED);
}
private static SimpleContainer getInputInventory(TradingStationBlockEntity pBlockEntity){
int containerSize = 0;
for(int index = 0; index < pBlockEntity.inputItems.getSlots(); index++) {
if (!pBlockEntity.inputItems.getStackInSlot(index).isEmpty())
containerSize++;
}
SimpleContainer inputInventory = new SimpleContainer(containerSize);
pBlockEntity.inputItemHandler.ifPresent(iItemHandler -> {
for(int slot = 0; slot < iItemHandler.getSlots(); slot++) {
if(!iItemHandler.getStackInSlot(slot).isEmpty()){
inputInventory.addItem(iItemHandler.getStackInSlot(slot));
}
}
});
return inputInventory;
}
private static void craftItem(TradingStationBlockEntity pBlockEntity) {
Level level = pBlockEntity.getLevel();
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
Optional<TradingRecipe> recipe = getRecipe(pBlockEntity);
if(recipe.isPresent()){
for (int i = 0; i < recipe.get().getIngredients().size(); i++) {
Ingredient ingredient = recipe.get().getIngredients().get(i);
for (int slot = 0; slot < pBlockEntity.inputItems.getSlots(); slot++) {
ItemStack itemStack = pBlockEntity.inputItems.getStackInSlot(slot);
if(ingredient.test(itemStack)){
pBlockEntity.inputItems.extractItem(slot,ingredient.getItems()[0].getCount(),false);
inputInventory.setChanged();
}
}
}
pBlockEntity.outputItems.insertItem(0, recipe.get().getResultItem(), false);
}
pBlockEntity.resetProgress();
pBlockEntity.setChanged();
}
static boolean canCraftItem(TradingStationBlockEntity pBlockEntity) {
Level level = pBlockEntity.getLevel();
if(level == null)
return false;
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
Optional<TradingRecipe> match = getRecipe(pBlockEntity);
if(match.isEmpty()) {
return false;
}
//return false;
return match.isPresent()
&& TradingStationBlockEntity.hasEnoughInputItems(inputInventory,match.get().getIngredients())
&& TradingStationBlockEntity.hasEnoughOutputSpace(pBlockEntity.outputItems,match.get().getResultItem());
}
private boolean canProcess(ItemStack stack) {
return getRecipe(this).isPresent();
}
protected static boolean hasEnoughInputItems(SimpleContainer inventory, NonNullList<Ingredient> ingredients){
int enough = 0;
for(int ingredientIndex = 0; ingredientIndex < ingredients.size();ingredientIndex ++){
Ingredient ingredient = ingredients.get(ingredientIndex);
for(int slot = 0; slot < inventory.getContainerSize(); slot++){
if(ingredient.test(inventory.getItem(slot))){
if(inventory.getItem(slot).getCount() >= ingredient.getItems()[0].getCount() )
enough++;
}
}
}
return ingredients.size() == enough;
}
protected static boolean hasEnoughOutputSpace(ItemStackHandler stackHandler,ItemStack resultItemStack){
return stackHandler.getStackInSlot(0).isEmpty() || stackHandler.getStackInSlot(0).is(resultItemStack.getItem()) && stackHandler.getStackInSlot(0).getMaxStackSize() - stackHandler.getStackInSlot(0).getCount() >= resultItemStack.getCount() ;
}
@Override
public CompoundTag getUpdateTag() {
this.saveAdditional(updateTag);
return updateTag;
}
@Nullable
@Override
public ClientboundBlockEntityDataPacket getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
@Override
public void handleUpdateTag(CompoundTag tag) {
this.load(tag);
}
@Override
public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) {
this.load(pkt.getTag());
}
public int getProgressPercent() {
return this.progress * 100 / this.maxProgress;
}
public void setItemStack(int slot, ItemStack itemStack,ItemStackSyncS2CPacket.SlotType slotType) {
if(slotType == ItemStackSyncS2CPacket.SlotType.INPUT)
inputItems.setStackInSlot(slot,itemStack);
else if (slotType == ItemStackSyncS2CPacket.SlotType.OUTPUT)
outputItems.setStackInSlot(slot,itemStack);
else if (slotType == ItemStackSyncS2CPacket.SlotType.TARGET)
targetItemHandler.setStackInSlot(slot,itemStack);
}
@Override
public Component getDisplayName() {
return ModLang.translate("block.display");
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int pContainerId, Inventory pPlayerInventory, Player pPlayer) {
return new TradingStationMenu(pContainerId, pPlayerInventory, this, this.containerData);
}
public void setPreferedItem(ItemStack itemStack) {
this.targetItemHandler.setStackInSlot(0,itemStack);
}
public ItemStack getPreferedItemStack() {
return targetItemHandler.getStackInSlot(0);
}
public ItemStackHandler getTargetItemHandler(){
return targetItemHandler;
}
}

View File

@@ -0,0 +1,31 @@
package com.oierbravo.trading_station.content.trading_station;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.NotNull;
public class TradingStationBlockRenderer implements BlockEntityRenderer<TradingStationBlockEntity> {
public TradingStationBlockRenderer(BlockEntityRendererProvider.Context context) {
}
@Override
public void render(TradingStationBlockEntity pBlockEntity, float pPartialTick, @NotNull PoseStack pPoseStack, @NotNull MultiBufferSource pBufferSource, int pPackedLight, int pPackedOverlay) {
if(!pBlockEntity.getPreferedItemStack().isEmpty()){
pPoseStack.pushPose();
pPoseStack.translate(0.5d, 1.1d, 0.5d);
renderBlock(pPoseStack,pBufferSource, LightTexture.FULL_BRIGHT,pPackedOverlay,pBlockEntity.getPreferedItemStack());
pPoseStack.popPose();
}
}
protected void renderBlock(PoseStack ms, MultiBufferSource buffer, int light, int overlay, ItemStack stack) {
Minecraft.getInstance()
.getItemRenderer()
.renderStatic(stack, ItemTransforms.TransformType.GROUND, light, overlay, ms, buffer, 0);
}
}

View File

@@ -0,0 +1,19 @@
package com.oierbravo.trading_station.content.trading_station;
import net.minecraftforge.common.ForgeConfigSpec;
public class TradingStationConfig {
//public static ForgeConfigSpec.IntValue MELTER_CAPACITY;
//public static ForgeConfigSpec.IntValue MELTER_FLUID_PER_TICK;
public static void registerServerConfig(ForgeConfigSpec.Builder COMMON_BUILDER) {
/* SERVER_BUILDER.comment("Settings for the trading_station").push("trading_station");
MELTER_CAPACITY = SERVER_BUILDER
.comment("How much liquid fits into the trading_station, in mB")
.defineInRange("capacity", 1000, 1, Integer.MAX_VALUE);
MELTER_FLUID_PER_TICK = SERVER_BUILDER
.comment("How much liquid generates per tick, in mB")
.defineInRange("liquidPerTick", 2, 1, Integer.MAX_VALUE);
SERVER_BUILDER.pop();*/
}
}

View File

@@ -0,0 +1,142 @@
package com.oierbravo.trading_station.content.trading_station;
import com.oierbravo.trading_station.registrate.ModBlocks;
import com.oierbravo.trading_station.registrate.ModMenus;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.*;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.SlotItemHandler;
import org.jetbrains.annotations.Nullable;
public class TradingStationMenu extends AbstractContainerMenu {
public final TradingStationBlockEntity blockEntity;
public final Inventory inventory;
private final Level level;
private final ContainerData containerData;
public ItemStackHandler ghostInventory;
public TradingStationMenu(int pContainerId, Inventory inv, FriendlyByteBuf extraData){
this(pContainerId, inv, inv.player.level.getBlockEntity(extraData.readBlockPos()), new SimpleContainerData(2));
}
public TradingStationMenu(int pContainerId, Inventory pInv, BlockEntity pBlockEntity, ContainerData pData){
super(ModMenus.TRADING_STATION.get(), pContainerId);
checkContainerSize(pInv, 3);
blockEntity = (TradingStationBlockEntity) pBlockEntity;
this.level = pInv.player.getLevel();
this.containerData = pData;
this.inventory = pInv;
addPlayerHotbar(pInv);
addPlayerInventory(pInv);
this.addDataSlots(pData);
//this.blockEntity.inputItems
this.blockEntity.getInputItemHandler().ifPresent(itemHandler -> {
this.addSlot(new SlotItemHandler(itemHandler,0,TradingStationScreen.inputSlotX[0],TradingStationScreen.inputSlotY));
this.addSlot(new SlotItemHandler(itemHandler,1,TradingStationScreen.inputSlotX[1],TradingStationScreen.inputSlotY));
});
this.blockEntity.getOutputItemHandler().ifPresent(itemHandler -> {
this.addSlot(new SlotItemHandler(itemHandler,0,TradingStationScreen.outputSlotX,TradingStationScreen.outputSlotY));
});
this.addSlot(new SlotItemHandler(this.blockEntity.getTargetItemHandler(),0,87,28));
}
public TradingStationMenu(int pContainerId, Inventory pInventory, BlockPos sourcePos) {
this(pContainerId, pInventory, Minecraft.getInstance().level.getBlockEntity(sourcePos), TradingStationBlockEntity.createContainerData((TradingStationBlockEntity) Minecraft.getInstance().level.getBlockEntity(sourcePos)));
}
public static TradingStationMenu factory(@Nullable MenuType<TradingStationMenu> pMenuType, int pContainerId, Inventory inventory, FriendlyByteBuf buf) {
return new TradingStationMenu(pContainerId, inventory, buf);
}
public int getScaledProgress() {
int progress = this.containerData.get(0);
int maxProgress = this.containerData.get(1); // Max Progress
int progressArrowSize = 34; // This is the height in pixels of your arrow
return maxProgress != 0 && progress != 0 ? progress * progressArrowSize / maxProgress : 0;
}
public boolean isCrafting() {
return containerData.get(0) > 0;
}
private static final int HOTBAR_SLOT_COUNT = 9;
private static final int PLAYER_INVENTORY_ROW_COUNT = 3;
private static final int PLAYER_INVENTORY_COLUMN_COUNT = 9;
private static final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_COLUMN_COUNT * PLAYER_INVENTORY_ROW_COUNT;
private static final int VANILLA_SLOT_COUNT = HOTBAR_SLOT_COUNT + PLAYER_INVENTORY_SLOT_COUNT;
private static final int VANILLA_FIRST_SLOT_INDEX = 0;
private static final int TE_INVENTORY_FIRST_SLOT_INDEX = VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT;
// THIS YOU HAVE TO DEFINE!
private static final int TE_INVENTORY_SLOT_COUNT = 2; // must be the number of slots you have!
@Override
public ItemStack quickMoveStack(Player playerIn, int pIndex) {
Slot sourceSlot = slots.get(pIndex);
if (sourceSlot == null || !sourceSlot.hasItem()) return ItemStack.EMPTY; //EMPTY_ITEM
ItemStack sourceStack = sourceSlot.getItem();
ItemStack copyOfSourceStack = sourceStack.copy();
// Check if the slot clicked is one of the vanilla container slots
if (pIndex < VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT) {
// This is a vanilla container slot so merge the stack into the tile inventory
if (!moveItemStackTo(sourceStack, TE_INVENTORY_FIRST_SLOT_INDEX, TE_INVENTORY_FIRST_SLOT_INDEX
+ TE_INVENTORY_SLOT_COUNT, false)) {
return ItemStack.EMPTY; // EMPTY_ITEM
}
} else if (pIndex < TE_INVENTORY_FIRST_SLOT_INDEX + TE_INVENTORY_SLOT_COUNT) {
// This is a TE slot so merge the stack into the players inventory
if (!moveItemStackTo(sourceStack, VANILLA_FIRST_SLOT_INDEX, VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) {
return ItemStack.EMPTY;
}
} else if (pIndex == TE_INVENTORY_FIRST_SLOT_INDEX + TE_INVENTORY_SLOT_COUNT) {
// This is a TE Outpu slot so merge the stack into the players inventory
if (!moveItemStackTo(sourceStack, VANILLA_FIRST_SLOT_INDEX, VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) {
return ItemStack.EMPTY;
}
} else {
System.out.println("Invalid slotIndex:" + pIndex);
return ItemStack.EMPTY;
}
// If stack size == 0 (the entire stack was moved) set slot contents to null
if (sourceStack.getCount() == 0) {
sourceSlot.set(ItemStack.EMPTY);
} else {
sourceSlot.setChanged();
}
sourceSlot.onTake(playerIn, sourceStack);
return copyOfSourceStack;
}
@Override
public boolean stillValid(Player pPlayer) {
return stillValid(ContainerLevelAccess.create(level, blockEntity.getBlockPos()), pPlayer, ModBlocks.TRADING_STATION.get());
}
private static final int PLAYER_INVENTORY_Y = 64;
private void addPlayerInventory(Inventory playerInventory) {
for (int i = 0; i < 3; ++i) {
for (int l = 0; l < 9; ++l) {
this.addSlot(new Slot(playerInventory, l + i * 9 + 9, 8 + l * 18, PLAYER_INVENTORY_Y + i * 18));
}
}
}
private static final int HOTBAR_Y = 122;
private void addPlayerHotbar(Inventory playerInventory) {
for (int i = 0; i < 9; ++i) {
this.addSlot(new Slot(playerInventory, i, 8 + i * 18, HOTBAR_Y));
}
}
}

View File

@@ -0,0 +1,91 @@
package com.oierbravo.trading_station.content.trading_station;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.registrate.ModRecipes;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraftforge.client.gui.widget.ExtendedButton;
import java.util.ArrayList;
import java.util.Optional;
public class TradingStationScreen extends AbstractContainerScreen<TradingStationMenu> {
private static final ResourceLocation TEXTURE = TradingStation.asResource("textures/gui/trading_station.png");
private int progressArrowX = 79;
private int progressArrowY = 47;
private int targetSelectButtonX = 131;
private int targetSelectButtonY = 18;
public static int inputSlotX[] = {19,42};
public static int inputSlotY = 38;
public static int outputSlotX = 131;
public static int outputSlotY = 38;
@Override
protected void init() {
super.init();
this.titleLabelX = 4;
this.titleLabelY = 4;
this.inventoryLabelY = 100000;
this.addRenderableWidget(new ExtendedButton(leftPos + targetSelectButtonX,topPos + targetSelectButtonY,16,16, ModLang.translate("select_target.button"), btn ->{
TradingStationTargetSelectScreen screen = new TradingStationTargetSelectScreen( this.menu.blockEntity);
Minecraft.getInstance().pushGuiLayer(screen);
}));
}
public TradingStationScreen(TradingStationMenu pMenu, Inventory pPlayerInventory, Component pTitle) {
super(pMenu, pPlayerInventory, pTitle);
}
@Override
protected void renderBg(PoseStack pPoseStack, float pPartialTick, int pMouseX, int pMouseY) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
RenderSystem.setShaderTexture(0, TEXTURE);
this.fillGradient(pPoseStack, 0, 0, this.width, this.height, -1072689136, -804253680);
int x = (width - imageWidth) / 2;
int y = (height - imageHeight) / 2;
this.blit(pPoseStack, x, y, 0, 0, imageWidth, imageHeight);
if (menu.isCrafting()) {
this.blit(pPoseStack, x + progressArrowX, y + progressArrowY, 179, 0, menu.getScaledProgress(), 7);
}
if(!menu.blockEntity.getPreferedItemStack().isEmpty()){
Optional<TradingRecipe> recipe = ModRecipes.findByOutput(menu.blockEntity.getLevel(),menu.blockEntity.getPreferedItemStack());
if(recipe.isPresent()){
renderFakeRecipe(recipe.get(), pPoseStack);
}
}
}
private void renderFakeRecipe(TradingRecipe recipe, PoseStack pPoseStack){
for(int index = 0; index < recipe.getIngredients().size(); index++){
Ingredient ingredient = recipe.getIngredients().get(index);
if(!ingredient.isEmpty())
FakeItemRenderer.renderFakeItem(ingredient.getItems()[0],getGuiLeft() + TradingStationScreen.inputSlotX[index],getGuiTop() + TradingStationScreen.inputSlotY, .5f);
}
FakeItemRenderer.renderFakeItem(recipe.getResultItem(),getGuiLeft() + TradingStationScreen.outputSlotX,getGuiTop() + TradingStationScreen.outputSlotY, .5f);
}
@Override
public void render(PoseStack pPoseStack, int pMouseX, int pMouseY, float pPartialTick) {
super.render(pPoseStack, pMouseX, pMouseY, pPartialTick);
}
}

View File

@@ -0,0 +1,246 @@
package com.oierbravo.trading_station.content.trading_station;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.network.packets.GhostItemSyncC2SPacket;
import com.oierbravo.trading_station.registrate.ModMessages;
import com.oierbravo.trading_station.registrate.ModRecipes;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
import java.util.LinkedList;
import java.util.List;
/**
* Scroll code and loop adapted from Alchemistry/src/main/java/com/smashingmods/alchemistry/client/container/RecipeSelectorScreen.java
*/
public class TradingStationTargetSelectScreen extends Screen {
private static final ResourceLocation TEXTURE = TradingStation.asResource("textures/gui/trade_select.png");
private TradingStationBlockEntity blockEntity;
private List<ItemStack> allPossibleOutputs;
private LinkedList<ItemStack> displayedItemStacks = new LinkedList<>();
private float scrollOffset;
private boolean scrolling;
private int startIndex;
private static int MAX_DISPLAYED_RECIPES = 24;
private static final int COLUMNS = 8;
private static final int TARGET_BOX_SIZE = 17;
private int targetBoxLeftPosOffset = 7;
private int targetBoxTopPosOffset = 19;
private int scrollBarXOffset = 148;
private int scrollBarYOffset = 22;
protected int titleLabelX;
protected int titleLabelY;
protected int imageWidth = 165;
protected int imageHeight = 83;
protected int leftPos;
protected int topPos;
protected TradingStationTargetSelectScreen(Component pTitle) {
super(pTitle);
}
public TradingStationTargetSelectScreen(TradingStationBlockEntity pBlockEntity) {
this(ModLang.translate("select_target.title"));
this.blockEntity = pBlockEntity;
this.allPossibleOutputs = ModRecipes.getAllOutputs(pBlockEntity.getLevel());
resetDisplayedTargets();
}
@Override
protected void init() {
super.init();
this.titleLabelX = 4;
this.titleLabelY = 4;
this.leftPos = (this.width - this.imageWidth) / 2;
this.topPos = (this.height - this.imageHeight) / 2;
addRenderableWidget(new Button(getGuiLeft() - 25, getGuiTop() + 1, 25, 20, Component.literal("<--"), (button) -> {
Minecraft.getInstance().popGuiLayer();
}));
addRenderableWidget(new Button(getGuiLeft() - 25, getGuiTop() + 30, 25, 20, ModLang.translate("select_target.clear"), (button) -> {
ModMessages.sendToServer(new GhostItemSyncC2SPacket(ItemStack.EMPTY,this.blockEntity.getBlockPos()));
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_STONECUTTER_SELECT_RECIPE, 1.0f));
Minecraft.getInstance().popGuiLayer();
}));
}
public int getGuiLeft() { return leftPos; }
public int getGuiTop() { return topPos; }
@Override
public void tick() {
if (displayedItemStacks.size() < MAX_DISPLAYED_RECIPES) {
mouseScrolled(0, 0, 0);
scrollOffset = 0.0f;
}
if (displayedItemStacks.size() <= MAX_DISPLAYED_RECIPES) {
startIndex = 0;
scrollOffset = 0;
}
super.tick();
}
@Override
public void render(PoseStack pPoseStack, int pMouseX, int pMouseY, float pPartialTick) {
renderBackground(pPoseStack);
int lastDisplayedIndex = startIndex + MAX_DISPLAYED_RECIPES;
renderScrollbar(pPoseStack);
renderSelectedTarget(pPoseStack, pMouseX, pMouseY, lastDisplayedIndex);
renderTargetItems(pPoseStack, pMouseX, pMouseY, lastDisplayedIndex);
renderLabels(pPoseStack, pMouseX, pMouseY);
super.render(pPoseStack, pMouseX, pMouseY, pPartialTick);
}
protected void renderLabels(PoseStack pPoseStack, int pMouseX, int pMouseY) {
this.font.draw(pPoseStack, this.title, (float)this.titleLabelX + getGuiLeft(), (float)this.titleLabelY + getGuiTop(), 4210752);
}
private void renderSelectedTarget(PoseStack pPoseStack, int pMouseX, int pMouseY, int pLastDisplayedIndex) {
LinkedList<ItemStack> displayedRecipes = getDisplayedItemStacks();
ItemStack selectedTarget = this.blockEntity.getTargetItemHandler().getStackInSlot(0);
for (int index = startIndex; index >= 0 && index < pLastDisplayedIndex && index < displayedRecipes.size(); index++) {
int firstDisplayedIndex = index - startIndex;
ItemStack target = allPossibleOutputs.get(index);
int xStart = getGuiLeft() + targetBoxLeftPosOffset + firstDisplayedIndex % COLUMNS * TARGET_BOX_SIZE + 1;
int yStart = getGuiTop() + targetBoxTopPosOffset + (firstDisplayedIndex / COLUMNS) * TARGET_BOX_SIZE + 3;
if(target.sameItem(selectedTarget))
blit(pPoseStack, xStart, yStart, 0, imageHeight + 19, TARGET_BOX_SIZE, TARGET_BOX_SIZE);
}
}
private void renderTargetItems(PoseStack pPoseStack, int pMouseX, int pMouseY, int pLastDisplayedIndex) {
LinkedList<ItemStack> displayedRecipes = getDisplayedItemStacks();
for (int index = startIndex; index >= 0 && index < pLastDisplayedIndex && index < displayedRecipes.size(); index++) {
int firstDisplayedIndex = index - startIndex;
ItemStack target = allPossibleOutputs.get(index);
int xStart = getGuiLeft() + targetBoxLeftPosOffset + firstDisplayedIndex % COLUMNS * TARGET_BOX_SIZE + 1;
int yStart = getGuiTop() + targetBoxTopPosOffset + (firstDisplayedIndex / COLUMNS) * TARGET_BOX_SIZE + 3;
renderFloatingItem(target, xStart, yStart);
if (pMouseX >= xStart - 1 && pMouseX <= xStart + 16 && pMouseY >= yStart - 1 && pMouseY <= yStart + 16) {
renderTooltip(pPoseStack, target, pMouseX, pMouseY);
}
}
}
private LinkedList<ItemStack> getDisplayedItemStacks() {
return displayedItemStacks;
}
private void renderFloatingItem(ItemStack pItemStack, int pX, int pY) {
RenderSystem.applyModelViewMatrix();
setBlitOffset(2000);
itemRenderer.blitOffset = 2000.0f;
itemRenderer.renderAndDecorateItem(pItemStack, pX, pY);
itemRenderer.renderGuiItemDecorations(font, pItemStack, pX, pY, "");
setBlitOffset(0);
itemRenderer.blitOffset = 0.0f;
}
@Override
public void renderBackground(PoseStack pPoseStack) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
RenderSystem.setShaderTexture(0, TEXTURE);
this.fillGradient(pPoseStack, 0, 0, this.width, this.height, -1072689136, -804253680);
this.blit(pPoseStack, getGuiLeft(), getGuiTop(), 0, 0, imageWidth, imageHeight);
}
private void renderScrollbar(PoseStack pPoseStack) {
int scrollPosition = (int) (43.0f * scrollOffset);
blit(pPoseStack, getGuiLeft() + scrollBarXOffset, getGuiTop() + scrollBarYOffset + scrollPosition, 0, imageHeight + 1 + (isScrollBarActive() ? 0 : 9), 7, 9);
}
@Override
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
scrolling = false;
int lastDisplayedIndex = startIndex + MAX_DISPLAYED_RECIPES;
for (int index = startIndex; index < lastDisplayedIndex; index++) {
int currentIndex = index - startIndex;
double boxX = pMouseX - (double)(getGuiLeft() + targetBoxLeftPosOffset + currentIndex % COLUMNS * TARGET_BOX_SIZE);
double boxY = pMouseY - (double)(getGuiTop() + targetBoxTopPosOffset + currentIndex / COLUMNS * TARGET_BOX_SIZE);
if (boxX > 0 && boxX <= TARGET_BOX_SIZE + 1 && boxY > 0 && boxY <= TARGET_BOX_SIZE + 1 && isValidRecipeIndex(index)) {
ItemStack itemStack = getDisplayedItemStacks().get(index);
ModMessages.sendToServer(new GhostItemSyncC2SPacket(itemStack,this.blockEntity.getBlockPos()));
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_STONECUTTER_SELECT_RECIPE, 1.0f));
Minecraft.getInstance().popGuiLayer();
return true;
}
int scrollMinX = leftPos + 148;
int scrollMinY = topPos + 9;
int scrollMaxX = scrollMinX + 6;
int scrollMaxY = scrollMinY + 60;
if (pMouseX >= scrollMinX && pMouseX < scrollMaxX && pMouseY >= scrollMinY && pMouseY < scrollMaxY) {
scrolling = true;
}
}
return super.mouseClicked(pMouseX, pMouseY, pButton);
}
private boolean isValidRecipeIndex(int pSlot) {
return pSlot >= 0 && pSlot < getDisplayedItemStacks().size();
}
@Override
public boolean isPauseScreen() {
return false;
}
public void resetDisplayedTargets() {
this.displayedItemStacks.clear();
this.displayedItemStacks.addAll(allPossibleOutputs);
}
@Override
public boolean mouseDragged(double pMouseX, double pMouseY, int pButton, double pDragX, double pDragY) {
if (scrolling && isScrollBarActive()) {
int scrollbarTopPos = getGuiTop() + 9;
int scrollbarBottomPos = scrollbarTopPos + 51;
scrollOffset = ((float) pMouseY - (float) scrollbarTopPos - 7.5f) / ((float) (scrollbarBottomPos - scrollbarTopPos) - 9.0f);
scrollOffset = Mth.clamp(scrollOffset, 0.0f, 1.0f);
startIndex = (int) ((double) (scrollOffset * (float) getOffscreenRows()) + 0.5d) * COLUMNS;
return true;
} else {
return super.mouseDragged(pMouseX, pMouseY, pButton, pDragX, pDragY);
}
}
@Override
public boolean mouseScrolled(double pMouseX, double pMouseY, double pDelta) {
if (pMouseX >= leftPos && pMouseX < leftPos + imageWidth && pMouseY >= topPos && pMouseY < topPos + imageHeight && isScrollBarActive()) {
scrollOffset = Mth.clamp(scrollOffset - (float) pDelta / (float) getOffscreenRows(), 0.0f, 1.0f);
startIndex = (int) ((double) (scrollOffset * (float) getOffscreenRows()) + 0.5d) * COLUMNS;
}
return true;
}
private int getOffscreenRows() {
return (displayedItemStacks.size() + 6 - 1) / 6 - 3;
}
private boolean isScrollBarActive() {
return displayedItemStacks.size() > MAX_DISPLAYED_RECIPES;
}
}

View File

@@ -0,0 +1,33 @@
package com.oierbravo.trading_station.content.trading_station.powered;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlock;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import com.oierbravo.trading_station.registrate.ModBlockEntities;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
public class PoweredTradingStationBlock extends TradingStationBlock {
public PoweredTradingStationBlock(Properties pProperties) {
super(pProperties);
}
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {
return ModBlockEntities.POWERED_TRADING_STATION.create(pPos, pState);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level pLevel, BlockState pState, BlockEntityType<T> pBlockEntityType) {
return createTickerHelper(pBlockEntityType, ModBlockEntities.POWERED_TRADING_STATION.get(),
TradingStationBlockEntity::tick);
}
}

View File

@@ -0,0 +1,12 @@
package com.oierbravo.trading_station.content.trading_station.powered;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
public class PoweredTradingStationBlockEntity extends TradingStationBlockEntity {
public PoweredTradingStationBlockEntity(BlockEntityType<?> pType, BlockPos pWorldPosition, BlockState pBlockState) {
super(pType, pWorldPosition, pBlockState);
}
}

View File

@@ -0,0 +1,18 @@
package com.oierbravo.trading_station.foundation.gui;
import com.oierbravo.trading_station.content.trading_station.TradingStationScreen;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.network.chat.Component;
import net.minecraftforge.client.gui.widget.ExtendedButton;
public class BackButton extends ExtendedButton {
public BackButton(int pX, int pY, int pWidth, int pHeight, Component pMessage, OnPress pOnPress) {
super(pX, pY, pWidth, pHeight, pMessage, pOnPress);
}
/* public BackButton(int pX, int pY, AbstractContainerScreen<TradingStationScreen> parentScreen){
this(pX,pY,16,16,Component.literal("Back"), btn->{
this.
})
}*/
}

View File

@@ -0,0 +1,148 @@
package com.oierbravo.trading_station.foundation.render;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.oierbravo.trading_station.TradingStation;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RegisterShadersEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import java.io.IOException;
// TODO 1.17: use custom shaders instead of vanilla ones
public class RenderTypes extends RenderStateShard {
public static final ShaderStateShard GLOWING_SHADER = new ShaderStateShard(() -> Shaders.glowingShader);
public static RenderType getOutlineTranslucent(ResourceLocation texture, boolean cull) {
return RenderType.create(createLayerName("outline_translucent" + (cull ? "_cull" : "")),
DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, RenderType.CompositeState.builder()
.setShaderState(cull ? RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER : RENDERTYPE_ENTITY_TRANSLUCENT_SHADER)
.setTextureState(new TextureStateShard(texture, false, false))
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setCullState(cull ? CULL : NO_CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.setWriteMaskState(COLOR_WRITE)
.createCompositeState(false));
}
public static RenderType getGlowingSolid(ResourceLocation texture) {
return RenderType.create(createLayerName("glowing_solid"), DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256,
true, false, RenderType.CompositeState.builder()
.setShaderState(GLOWING_SHADER)
.setTextureState(new TextureStateShard(texture, false, false))
.setCullState(CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
}
private static final RenderType GLOWING_SOLID_DEFAULT = getGlowingSolid(InventoryMenu.BLOCK_ATLAS);
public static RenderType getGlowingSolid() {
return GLOWING_SOLID_DEFAULT;
}
public static RenderType getGlowingTranslucent(ResourceLocation texture) {
return RenderType.create(createLayerName("glowing_translucent"), DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS,
256, true, true, RenderType.CompositeState.builder()
.setShaderState(GLOWING_SHADER)
.setTextureState(new TextureStateShard(texture, false, false))
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
}
private static final RenderType ADDITIVE = RenderType.create(createLayerName("additive"), DefaultVertexFormat.BLOCK,
VertexFormat.Mode.QUADS, 256, true, true, RenderType.CompositeState.builder()
.setShaderState(BLOCK_SHADER)
.setTextureState(new TextureStateShard(InventoryMenu.BLOCK_ATLAS, false, false))
.setTransparencyState(ADDITIVE_TRANSPARENCY)
.setCullState(NO_CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getAdditive() {
return ADDITIVE;
}
private static final RenderType GLOWING_TRANSLUCENT_DEFAULT = getGlowingTranslucent(InventoryMenu.BLOCK_ATLAS);
public static RenderType getGlowingTranslucent() {
return GLOWING_TRANSLUCENT_DEFAULT;
}
private static final RenderType ITEM_PARTIAL_SOLID =
RenderType.create(createLayerName("item_partial_solid"), DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true,
false, RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_ENTITY_SOLID_SHADER)
.setTextureState(BLOCK_SHEET)
.setCullState(CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getItemPartialSolid() {
return ITEM_PARTIAL_SOLID;
}
private static final RenderType ITEM_PARTIAL_TRANSLUCENT = RenderType.create(createLayerName("item_partial_translucent"),
DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true, true, RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER)
.setTextureState(BLOCK_SHEET)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getItemPartialTranslucent() {
return ITEM_PARTIAL_TRANSLUCENT;
}
private static final RenderType FLUID = RenderType.create(createLayerName("fluid"),
DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER)
.setTextureState(BLOCK_SHEET_MIPPED)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getFluid() {
return FLUID;
}
private static String createLayerName(String name) {
return TradingStation.MODID + ":" + name;
}
// Mmm gimme those protected fields
private RenderTypes() {
super(null, null, null);
}
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD)
private static class Shaders {
private static ShaderInstance glowingShader;
/*@SubscribeEvent
public static void onRegisterShaders(RegisterShadersEvent event) throws IOException {
ResourceManager resourceManager = event.getResourceManager();
event.registerShader(new ShaderInstance(resourceManager, TradingStation.asResource("glowing_shader"), DefaultVertexFormat.NEW_ENTITY), shader -> glowingShader = shader);
}*/
}
}

View File

@@ -0,0 +1,14 @@
package com.oierbravo.trading_station.foundation.util;
import com.oierbravo.trading_station.TradingStation;
import net.minecraft.network.chat.Component;
public class ModLang {
public static Component translate(String key){
return Component.translatable(TradingStation.MODID + '.' + key);
}
public static String key(String key){
return TradingStation.MODID + '.' + key;
}
}

View File

@@ -0,0 +1,56 @@
package com.oierbravo.trading_station.network.packets;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class GhostItemSyncC2SPacket {
private final ItemStack itemStack;
private final BlockPos pos;
public GhostItemSyncC2SPacket(ItemStack itemStack, BlockPos pos) {
this.itemStack = itemStack;
this.pos = pos;
}
public GhostItemSyncC2SPacket(FriendlyByteBuf buf) {
this.itemStack = buf.readItem();
this.pos = buf.readBlockPos();
}
public void toBytes(FriendlyByteBuf buf) {
buf.writeItem(itemStack);
buf.writeBlockPos(pos);
}
public static void handle(GhostItemSyncC2SPacket message, Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
ServerPlayer sender = context.getSender();
if (sender == null)
return;
AbstractContainerMenu container = sender.containerMenu;
if (container == null)
return;
if(sender.getLevel().getBlockEntity(message.pos) instanceof TradingStationBlockEntity blockEntity) {
blockEntity.setPreferedItem(message.itemStack);
//blockEntity.setChanged();
}
});
context.setPacketHandled(true);
}
}

View File

@@ -0,0 +1,54 @@
package com.oierbravo.trading_station.network.packets;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class ItemStackSyncS2CPacket {
private final int slot;
private final ItemStack itemStack;
private final BlockPos pos;
public enum SlotType {
INPUT, OUTPUT, TARGET;
}
private final SlotType slotType;
public ItemStackSyncS2CPacket(int slot, ItemStack itemStack, BlockPos pos,SlotType slotType) {
this.slot = slot;
this.itemStack = itemStack;
this.pos = pos;
this.slotType = slotType;
}
public ItemStackSyncS2CPacket(FriendlyByteBuf buf) {
this.slot = buf.readInt();
this.itemStack = buf.readItem();
this.pos = buf.readBlockPos();
this.slotType = SlotType.values()[buf.readInt()];
}
public void toBytes(FriendlyByteBuf buf) {
buf.writeInt(slot);
buf.writeItem(itemStack);
buf.writeBlockPos(pos);
buf.writeInt(slotType.ordinal());
}
public static boolean handle(ItemStackSyncS2CPacket message, Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
if(Minecraft.getInstance().level.getBlockEntity(message.pos) instanceof TradingStationBlockEntity blockEntity) {
blockEntity.setItemStack(message.slot,message.itemStack,message.slotType);
}
});
return true;
}
}

View File

@@ -0,0 +1,50 @@
package com.oierbravo.trading_station.network.packets;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import com.oierbravo.trading_station.content.trading_station.TradingStationMenu;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.network.NetworkHooks;
import java.util.function.Supplier;
public class OpenTargetSelectPacket {
private BlockPos sourcePos;
public OpenTargetSelectPacket(BlockPos pSourcePos){
this.sourcePos = pSourcePos;
}
public OpenTargetSelectPacket(FriendlyByteBuf buf){
this(buf.readBlockPos());
}
public void toBytes(FriendlyByteBuf buf) {
buf.writeBlockPos(sourcePos);
}
public static boolean handle(OpenTargetSelectPacket message, Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
ServerPlayer sender = context.getSender();
if (sender == null)
return;
TradingStationMenu container = (TradingStationMenu) sender.containerMenu;
if (container == null)
return;
/*NetworkHooks.openScreen(sender, new SimpleMenuProvider(
(windowId, playerInventory, playerEntity) -> new TradingTradeSelectMenu(windowId, message.sourcePos), Component.translatable("")), (buf -> {
buf.writeBlockPos(message.sourcePos);
}));*/
NetworkHooks.openScreen(((ServerPlayer)sender), (TradingStationBlockEntity)container.blockEntity, message.sourcePos);
});
return true;
}
}

View File

@@ -0,0 +1,52 @@
package com.oierbravo.trading_station.network.packets;
import com.oierbravo.trading_station.content.trading_station.TradingStationMenu;
import dev.latvian.mods.rhino.ast.Block;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.network.NetworkHooks;
import java.util.function.Supplier;
public class OpenTradingMenuPacket {
protected BlockPos sourcePos;
public OpenTradingMenuPacket(BlockPos pSourcePos){
this.sourcePos = pSourcePos;
}
public OpenTradingMenuPacket(FriendlyByteBuf buf){
this(buf.readBlockPos());
}
public void toBytes(FriendlyByteBuf buf) {
buf.writeBlockPos(sourcePos);
}
public BlockPos getSourcePos(){
return sourcePos;
}
public static boolean handle(OpenTradingMenuPacket message, Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
ServerPlayer sender = context.getSender();
if (sender == null)
return;
AbstractContainerMenu container = sender.containerMenu;
if (container == null)
return;
NetworkHooks.openScreen(sender, new SimpleMenuProvider(
(windowId, playerInventory, playerEntity) -> new TradingStationMenu(windowId,playerInventory,message.sourcePos), Component.translatable("trading_station.block.display")), (buf -> {
buf.writeBlockPos(message.sourcePos);
}));
});
return true;
}
}

View File

@@ -0,0 +1,30 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.content.trading_station.TradingStationConfig;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.config.ModConfig;
//From https://github.com/McJty/TutorialV3/blob/1.19/src/main/java/com/example/tutorialv3/setup/Config.java
public class Config {
public static void register() {
registerServerConfigs();
//registerCommonConfigs();
//registerClientConfigs();
}
private static void registerClientConfigs() {
ForgeConfigSpec.Builder CLIENT_BUILDER = new ForgeConfigSpec.Builder();
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, CLIENT_BUILDER.build());
}
private static void registerCommonConfigs() {
ForgeConfigSpec.Builder COMMON_BUILDER = new ForgeConfigSpec.Builder();
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, COMMON_BUILDER.build());
}
private static void registerServerConfigs() {
ForgeConfigSpec.Builder SERVER_BUILDER = new ForgeConfigSpec.Builder();
TradingStationConfig.registerServerConfig(SERVER_BUILDER);
ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, SERVER_BUILDER.build());
}
}

View File

@@ -0,0 +1,24 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockRenderer;
import com.oierbravo.trading_station.content.trading_station.powered.PoweredTradingStationBlockEntity;
import com.tterrag.registrate.util.entry.BlockEntityEntry;
public class ModBlockEntities {
public static final BlockEntityEntry<TradingStationBlockEntity> TRADING_STATION = TradingStation.registrate()
.blockEntity("trading_station", TradingStationBlockEntity::new)
.validBlocks(ModBlocks.TRADING_STATION)
.renderer(() -> TradingStationBlockRenderer::new)
.register();
public static final BlockEntityEntry<PoweredTradingStationBlockEntity> POWERED_TRADING_STATION = TradingStation.registrate()
.blockEntity("powered_trading_station", PoweredTradingStationBlockEntity::new)
.validBlocks(ModBlocks.POWERED_TRADING_STATION)
.renderer(() -> TradingStationBlockRenderer::new)
.register();
public static void register() {
}
}

View File

@@ -0,0 +1,55 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlock;
import com.oierbravo.trading_station.content.trading_station.powered.PoweredTradingStationBlock;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import com.oierbravo.trading_station.content.trading_station.powered.PoweredTradingStationBlockEntity;
import com.tterrag.registrate.Registrate;
import com.tterrag.registrate.util.entry.BlockEntry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.client.model.generators.ConfiguredModel;
public class ModBlocks {
private static final Registrate REGISTRATE = TradingStation.registrate()
.creativeModeTab(() -> ModCreativeTab.MAIN);
public static final BlockEntry<TradingStationBlock> TRADING_STATION = TradingStation.registrate()
.block("trading_station", TradingStationBlock::new)
.lang("Trading Station")
.blockstate((ctx, prov) ->
prov.getVariantBuilder(ctx.getEntry()).forAllStates(state -> {
String modelFileName = "trading_station:block/trading_station";
if(state.getValue(BlockStateProperties.POWERED))
modelFileName += "_powered";
return ConfiguredModel.builder().modelFile(prov.models().getExistingFile(ResourceLocation.tryParse(modelFileName)))
.rotationY(((int) state.getValue(BlockStateProperties.HORIZONTAL_FACING).toYRot() + 180) % 360).build();
})
)
.simpleItem()
.blockEntity(TradingStationBlockEntity::new)
.build()
.register();
public static final BlockEntry<PoweredTradingStationBlock> POWERED_TRADING_STATION = TradingStation.registrate()
.block("powered_trading_station", PoweredTradingStationBlock::new)
.lang("Powered Trading Station")
.blockstate((ctx, prov) ->
prov.getVariantBuilder(ctx.getEntry()).forAllStates(state -> {
String modelFileName = "trading_station:block/powered_trading_station";
if(state.getValue(BlockStateProperties.POWERED))
modelFileName += "_powered";
return ConfiguredModel.builder().modelFile(prov.models().getExistingFile(ResourceLocation.tryParse(modelFileName)))
.rotationY(((int) state.getValue(BlockStateProperties.HORIZONTAL_FACING).toYRot() + 180) % 360).build();
})
)
.simpleItem()
.blockEntity(PoweredTradingStationBlockEntity::new)
.build()
.register();
public static void register() {
}
}

View File

@@ -0,0 +1,21 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
public class ModCreativeTab extends CreativeModeTab {
public static ModCreativeTab MAIN;
public ModCreativeTab() {
super(TradingStation.DISPLAY_NAME);
MAIN = this;
}
@Override
public ItemStack makeIcon() {
return new ItemStack(ModBlocks.TRADING_STATION.get());
}
}

View File

@@ -0,0 +1,25 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingStationMenu;
import com.oierbravo.trading_station.content.trading_station.TradingStationScreen;
import com.tterrag.registrate.util.entry.MenuEntry;
import com.tterrag.registrate.util.entry.RegistryEntry;
import net.minecraft.client.gui.screens.inventory.ContainerScreen;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.inventory.MenuType;
public class ModMenus {
public static final MenuEntry<TradingStationMenu> TRADING_STATION = TradingStation.registrate()
.menu("trading_station",TradingStationMenu::factory, () -> TradingStationScreen::new)
.register();
public static final MenuEntry<TradingStationMenu> TRADING_STATION_TRADE_SELECT = TradingStation.registrate()
.menu("trading_station_trade_select",TradingStationMenu::factory, () -> TradingStationScreen::new)
.register();
public static void register() {
}
}

View File

@@ -0,0 +1,70 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.network.packets.GhostItemSyncC2SPacket;
import com.oierbravo.trading_station.network.packets.ItemStackSyncS2CPacket;
import com.oierbravo.trading_station.network.packets.OpenTargetSelectPacket;
import com.oierbravo.trading_station.network.packets.OpenTradingMenuPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.PacketDistributor;
import net.minecraftforge.network.simple.SimpleChannel;
public class ModMessages {
private static SimpleChannel INSTANCE;
private static int packetId = 0;
private static int id() {
return packetId++;
}
public static void register() {
SimpleChannel net = NetworkRegistry.ChannelBuilder
.named(new ResourceLocation(TradingStation.MODID, "messages"))
.networkProtocolVersion(() -> "1.0")
.clientAcceptedVersions(s -> true)
.serverAcceptedVersions(s -> true)
.simpleChannel();
INSTANCE = net;
net.messageBuilder(ItemStackSyncS2CPacket.class, id(), NetworkDirection.PLAY_TO_CLIENT)
.decoder(ItemStackSyncS2CPacket::new)
.encoder(ItemStackSyncS2CPacket::toBytes)
.consumerMainThread(ItemStackSyncS2CPacket::handle)
.add();
net.messageBuilder(GhostItemSyncC2SPacket.class, id(), NetworkDirection.PLAY_TO_SERVER)
.decoder(GhostItemSyncC2SPacket::new)
.encoder(GhostItemSyncC2SPacket::toBytes)
.consumerMainThread(GhostItemSyncC2SPacket::handle)
.add();
net.messageBuilder(OpenTradingMenuPacket.class, id(), NetworkDirection.PLAY_TO_SERVER)
.decoder(OpenTradingMenuPacket::new)
.encoder(OpenTradingMenuPacket::toBytes)
.consumerMainThread(OpenTradingMenuPacket::handle)
.add();
net.messageBuilder(OpenTargetSelectPacket.class, id(), NetworkDirection.PLAY_TO_SERVER)
.decoder(OpenTargetSelectPacket::new)
.encoder(OpenTargetSelectPacket::toBytes)
.consumerMainThread(OpenTargetSelectPacket::handle)
.add();
}
public static <MSG> void sendToServer(MSG message) {
INSTANCE.sendToServer(message);
}
public static <MSG> void sendToPlayer(MSG message, ServerPlayer player) {
INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), message);
}
public static <MSG> void sendToClients(MSG message) {
INSTANCE.send(PacketDistributor.ALL.noArg(), message);
}
}

View File

@@ -0,0 +1,70 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class ModRecipes {
public static final DeferredRegister<RecipeSerializer<?>> SERIALIZERS =
DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, TradingStation.MODID);
public static final DeferredRegister<RecipeType<?>> RECIPE_TYPES = DeferredRegister.create(ForgeRegistries.RECIPE_TYPES, TradingStation.MODID);
public static final RegistryObject<RecipeType<TradingRecipe>> TRADING_TYPE =
RECIPE_TYPES.register("trading",() -> TradingRecipe.Type.INSTANCE);
public static final RegistryObject<RecipeSerializer<TradingRecipe>> TRADING_SERIALIZER =
SERIALIZERS.register("trading", () -> TradingRecipe.Serializer.INSTANCE);
public static Optional<TradingRecipe> find(SimpleContainer pInv, Level pLevel) {
if(pLevel.isClientSide())
return Optional.empty();
return pLevel.getRecipeManager().getRecipeFor(TradingRecipe.Type.INSTANCE,pInv,pLevel);
}
/*public static List<ItemStack> getAllOutputs(Level pLevel){
List<ItemStack> allOutputs = pLevel.getRecipeManager().getAllRecipesFor(TradingRecipe.Type.INSTANCE).stream()
.map(TradingRecipe::getResult).toList();
allOutputs.add(ItemStack.EMPTY);
return allOutputs;
}*/
public static List<ItemStack> getAllOutputs(Level pLevel){
return pLevel.getRecipeManager().getAllRecipesFor(TradingRecipe.Type.INSTANCE).stream()
.map(TradingRecipe::getResult).toList();
}
public static Optional<TradingRecipe> findByOutput(Level pLevel,ItemStack targetedOutput){
//if(pLevel.isClientSide())
// return Optional.empty();
return pLevel.getRecipeManager().getAllRecipesFor(TradingRecipe.Type.INSTANCE).stream()
.filter(recipe -> recipe.matchesOutput(targetedOutput)).findFirst();
}
/*public static Optional<TradingRecipe> findWithPreferdOutput(SimpleContainer pInv, Level pLevel, ItemStack preferedOutput){
if(pLevel.isClientSide())
return Optional.empty();
List<TradingRecipe> allTradingRecipes = pLevel.getRecipeManager().getAllRecipesFor(TradingRecipe.Type.INSTANCE);
return allTradingRecipes.stream().filter(extrudingRecipe -> TradingRecipe.matches(tradingStation,tradingRecipe)).findFirst();
}*/
public static void register(IEventBus eventBus) {
SERIALIZERS.register(eventBus);
RECIPE_TYPES.register(eventBus);
}
}

View File

@@ -0,0 +1,28 @@
modLoader="javafml"
loaderVersion="[43,)"
issueTrackerURL="https://github.com/oierbravo/trading-station-mod/issues"
license="MIT"
[[mods]]
modId="trading_station"
version="${file.jarVersion}"
displayName="Trading Station"
logoFile="logo.png"
credits="Code inspirtation from the amazing Create mod"
authors="oierbravo"
description='''
Trading made simple
'''
# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
[[dependencies.trading_station]] #optional
modId="forge"
mandatory=true
versionRange="[43.2.3,)"
ordering="NONE"
side="BOTH"
[[dependencies.trading_station]]
modId="minecraft"
mandatory=true
versionRange="[1.19.2,1.20)"
ordering="NONE"
side="BOTH"

View File

@@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench",
"parent": "trading_station:block/trading_station",
"textures": {
"3": "trading_station:block/powered_trading_station"
}
}

View File

@@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench",
"parent": "trading_station:block/powered_trading_station",
"textures": {
"3": "trading_station:block/powered_trading_station_powered"
}
}

View File

@@ -0,0 +1 @@
{"meta":{"format_version":"4.5","model_format":"java_block","box_uv":false},"name":"trading_station","parent":"minecraft/block","ambientocclusion":true,"front_gui_light":false,"visible_box":[1,1,0],"variable_placeholders":"","variable_placeholder_buttons":[],"unhandled_root_fields":{},"resolution":{"width":16,"height":16},"elements":[{"name":"cube","box_uv":false,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[0,0,0],"to":[16,16,17],"autouv":1,"color":0,"origin":[0,0,0],"faces":{"north":{"uv":[0,0,16,16],"texture":2},"east":{"uv":[0,0,16,16],"texture":1},"south":{"uv":[0,0,16,16],"texture":1},"west":{"uv":[0,0,16,16],"texture":1},"up":{"uv":[0,0,16,16],"texture":0},"down":{"uv":[0,0,16,16],"texture":0}},"type":"cube","uuid":"01e24cac-cecb-3dde-0f23-731a20048b15"}],"outliner":["01e24cac-cecb-3dde-0f23-731a20048b15"],"textures":[{"path":"/home/oier/projects/mc-mods/trading-station/src/main/resources/assets/trading_station/textures/block/trading_station_top.png","name":"trading_station_top.png","folder":"block","namespace":"trading_station","id":"0","particle":true,"render_mode":"default","render_sides":"auto","frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"mode":"bitmap","saved":true,"uuid":"097851dc-7e0f-9ce3-3e13-13cd0cc603b9","relative_path":"../../../textures/block/trading_station_top.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAhJJREFUOE99Uz1vE0EQfZv4Pnznu3C2sUFYCQI3iAIqkFAkFChpkFCgiETNPyDUINHDT0gN/Aj+QJp0lCEQEyfmfF97Z3vR7GWcOwmYZndmn2b2vZkRD2911Kq5CjJLrOiTTaoF5vm8FnMsQ/v05tsmBCWgYNBt6YciKWA4JYh9vlPcshxImWAaZYjTHOLp/YHyWzYyOcNwvYsky2sVq45jm7BMAwfffqDX8TAaTyGeb15X5Dx59Q77n95rfD4TMBtKn2zks9199gafP7xGks0gdraGqhc0oXABJiBVY+Nfccy2TByPp4jiBOLRnZ5ymya6nbbmxhy1qOd86ayJKxNEsURRKIiXj28oz3Xhu2VF370QkOlkMocQAp7TwNlU4jSeo0gTRCTiztZNFfgOLgdlF2Re6JPE4jtRCHwXlCiVBZSCFjuMZCmibTUw6F9adoDAZ2GMfttZCsnJKPliscDRrxBhlJVtXLFsrHcdtNdaSNKZ/oEQc5BYrD51hJJSckp2MokRp0U5SP5aE17LrglVFY7FrQJOxqcIf6dlG92mgUE/WFYjoCKiFeOZYCqHx5OSwvbmhup3fD1IX/feLnX41xyQuPde7OLLx11MwhRi+8GGGlzx8X00xe3h1Xq/zztCweqIH41CXOt5OPwZloNEW0jLxIv0P/6kB+GiROqN1CLSOv9tlakyr3N1jfmbRsPEH0RYCWjadlbnAAAAAElFTkSuQmCC"},{"path":"/home/oier/projects/mc-mods/trading-station/src/main/resources/assets/trading_station/textures/block/trading_station_side.png","name":"trading_station_side.png","folder":"block","namespace":"trading_station","id":"1","particle":false,"render_mode":"default","render_sides":"auto","frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"mode":"bitmap","saved":true,"uuid":"dd0f02fb-6a8f-e0ba-b5ef-3411622545be","relative_path":"../../../textures/block/trading_station_side.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAASJJREFUOE/Fk81LAzEQxV8oLCYpCF1rL61fh6r0sgeptJcV/Af8u6WHXgTxIEp78KsIQpK6WCITGNyKu+nNueb9XuZNJuLqvOvbrSa0TNDabsK6LyyLJepKbSX4MJ+YP71D5KepJ3EjaQQT44pamA5ZtypWEOOLS9/eTXF7cxcFy4KTQR+vLwuIbDjySikoLWGN28iEtdZaiONB5qWWYJMqh9nDHL2Dbjimiwh2xlUbEPC7ZYpJJlEDgvN8tGbw/LZAZyfF/eOs3oBhEpbraL8X4GiEKgMCeQ7RCFqr8Kw8NIYpVjQCi+mdy7vBcDQCCSgvD43nUJ7JWgRapOFZFlqj1rlo4mTyVxljwyXXkynE3mE//AWpfuBN1tFZG2Ti33/jN0IY5K3kdLtoAAAAAElFTkSuQmCC"},{"path":"/home/oier/projects/mc-mods/trading-station/src/main/resources/assets/trading_station/textures/block/trading_station.png","name":"trading_station.png","folder":"block","namespace":"trading_station","id":"2","particle":false,"render_mode":"default","render_sides":"auto","frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"mode":"bitmap","saved":true,"uuid":"821f2390-40fb-97d8-e5dc-9207618506a7","relative_path":"../../../textures/block/trading_station.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAWdJREFUOE/FU1tLAkEYPYO0uTOG5mIQaG7SBQ3KhzDqpaA/0O+OHqoHeyhkRaGLbdplZmxLJmZoxEVdemtezu5855yds9835OygqAr5DJjrIJ/NQMhvDKMhkhZNO3jjn+g+9EGOq57S5JSTMiZcRoliXbS8UTQCOTo5VYUVD8xNI8MYPjgHl8PYu93X+Pgcmprm9J5CkHrjUFFKIYSAxr8sy9VoDBr7dZxfXEJy+Rc9XObCasja+pZyKYUUwogrwS0YgCUAfRAsQ8Xwxt8wPKsZR6DMRSfowm9eG9H7r8kkcgD3tT2U/CIElyY22d6pK30knT/shXAcB2r0NRWFpBbMXhRF8AqeEevIUwa2+NILUSyXDHHyWYvmGnTbnZmiJLPYCbRBNpdLjPA6GIw/MhVBG1SDu8Sf2PI34wZ2DlrtjunCavMKizPaZ9sZ1HZNFyrlkpkdMwe2rxrtPMybKN3/SR7599v4Aw5hBdkgFY5mAAAAAElFTkSuQmCC"}]}

View File

@@ -0,0 +1,63 @@
{
"credit": "Made with Blockbench",
"parent": "minecraft/block",
"render_type": "minecraft:translucent",
"textures": {
"3": "trading_station:block/trading_station"
},
"elements": [
{
"from": [0, 0, 0],
"to": [16, 16, 17],
"faces": {
"north": {"uv": [0, 0, 8, 8], "texture": "#3"},
"east": {"uv": [0, 8, 8, 16], "texture": "#3"},
"south": {"uv": [0, 8, 8, 16], "texture": "#3"},
"west": {"uv": [0, 8, 8, 16], "texture": "#3"},
"up": {"uv": [8, 0, 16, 8], "texture": "#3"},
"down": {"uv": [8, 8, 16, 16], "texture": "#3"}
}
},
{
"from": [3, 16, 4],
"to": [13, 18, 13],
"faces": {
"north": {"uv": [9.5, 5, 14.5, 6], "texture": "#3"},
"east": {"uv": [9.5, 5, 14.5, 6], "texture": "#3"},
"south": {"uv": [9.5, 5, 14.5, 6], "texture": "#3"},
"west": {"uv": [9.5, 5, 14.5, 6], "texture": "#3"},
"up": {"uv": [9.5, 2, 14.5, 6], "texture": "#3"},
"down": {"uv": [0, 0, 0, 0], "texture": "#3"}
}
}
],
"display": {
"thirdperson_righthand": {
"scale": [0.3, 0.3, 0.3]
},
"thirdperson_lefthand": {
"scale": [0.3, 0.3, 0.3]
},
"firstperson_righthand": {
"scale": [0.3, 0.3, 0.3]
},
"firstperson_lefthand": {
"scale": [0.3, 0.3, 0.3]
},
"ground": {
"scale": [0.5, 0.5, 0.5]
},
"gui": {
"rotation": [23, 135, 0],
"scale": [0.61, 0.61, 0.61]
},
"head": {
"scale": [0.89, 0.89, 0.89]
},
"fixed": {
"rotation": [0, -45, 0],
"translation": [0, 0, -2.5],
"scale": [0.72, 0.72, 0.72]
}
}
}

View File

@@ -0,0 +1,7 @@
{
"credit": "Made with Blockbench",
"parent": "trading_station:block/trading_station",
"textures": {
"3": "trading_station:block/trading_station_powered"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,11 @@
{
"type": "trading_station:trading",
"ingredients": [
{"item": "minecraft:emerald", "count": 5}
],
"result": {
"item": "minecraft:diamond",
"count": 5
},
"processingTime": 500
}

View File

@@ -0,0 +1,11 @@
{
"type": "trading_station:trading",
"ingredients": [
{"item": "minecraft:diamond", "count": 5}
],
"result": {
"item": "minecraft:enchanted_book",
"nbt": "{StoredEnchantments: [{id:\"looting\",lvl:3s}]}"
},
"processingTime": 100
}

View File

@@ -0,0 +1,19 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"S S",
"S S",
"NSN"
],
"key": {
"N": {
"item": "minecraft:iron_nugget"
},
"S": {
"tag": "forge:stone"
}
},
"result": {
"item": "trading_station:trading_station"
}
}

View File

@@ -0,0 +1 @@
com.oierbravo.trading_station.compat.kubejs.KubeJSPlugin

BIN
src/main/resources/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -0,0 +1,8 @@
{
"pack": {
"description": "TradingStation resources",
"pack_format": 9,
"forge:resource_pack_format": 8,
"forge:data_pack_format": 9
}
}

View File

@@ -0,0 +1,12 @@
{
"required": true,
"package": "com.oierbravo.trading_station.mixin",
"compatibilityLevel": "JAVA_17",
"refmap": "trading_station.refmap.json",
"mixins": [
],
"injectors": {
"defaultRequire": 1
},
"minVersion": "0.8"
}