mirror of
https://github.com/MineLittlePony/MineLittlePony.git
synced 2025-02-13 08:14:23 +01:00
Merge branch '1.14-fabric'
# Conflicts: # gradle.properties # src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java # src/hdskins/java/com/voxelmodpack/hdskins/SkinUploader.java # src/hdskins/java/com/voxelmodpack/hdskins/server/BethlehemSkinServer.java # src/hdskins/java/com/voxelmodpack/hdskins/server/LegacySkinServer.java # src/hdskins/java/com/voxelmodpack/hdskins/server/SkinServer.java # src/hdskins/java/com/voxelmodpack/hdskins/server/ValhallaSkinServer.java # src/main/java/com/minelittlepony/model/components/ModelBugWing.java
This commit is contained in:
commit
477ba58245
460 changed files with 8549 additions and 13680 deletions
|
@ -1,7 +1,7 @@
|
|||
language: java
|
||||
install: true
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- openjdk8
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
|
||||
|
|
|
@ -6,7 +6,7 @@ http://minelittlepony-mod.com
|
|||
|
||||
## Building
|
||||
|
||||
1. JDK 8 is required. Install it using https://docs.oracle.com/javase/8/docs/technotes/guides/install/windows_jdk_install.html
|
||||
1. JDK 8 is required. Install it using https://adoptopenjdk.net/
|
||||
|
||||
2. Open a terminal window in the same directory as the sources (git clone or extracted from zip). Run the following command (windows).
|
||||
|
||||
|
|
190
build.gradle
190
build.gradle
|
@ -1,37 +1,46 @@
|
|||
// Frabric build script
|
||||
// 24/05/2019
|
||||
// https://github.com/FabricMC/fabric-example-mod/blob/master/build.gradle
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven {
|
||||
name 'forge'
|
||||
url 'http://files.minecraftforge.net/maven'
|
||||
}
|
||||
maven {
|
||||
name = 'sponge'
|
||||
url = 'https://repo.spongepowered.org/maven'
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
jcenter()
|
||||
maven {
|
||||
name = 'Fabric'
|
||||
url = 'https://maven.fabricmc.net/'
|
||||
}
|
||||
gradlePluginPortal()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
|
||||
classpath 'org.spongepowered:mixingradle:0.6-SNAPSHOT'
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
|
||||
classpath 'fabric-loom:fabric-loom.gradle.plugin:0.2.2-SNAPSHOT'
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
|
||||
classpath 'org.ajoberstar.grgit:grgit-gradle:3.1.1'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'org.ajoberstar.grgit' version '1.7.2'
|
||||
repositories {
|
||||
maven {
|
||||
name = 'Jit'
|
||||
url = 'https://jitpack.io'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'net.minecraftforge.gradle.liteloader'
|
||||
apply plugin: 'org.spongepowered.mixin'
|
||||
apply plugin: 'fabric-loom'
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
apply plugin: 'org.ajoberstar.grgit'
|
||||
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
ext {
|
||||
revision = grgit.log().size()
|
||||
hash = grgit.head().abbreviatedId
|
||||
if (file('.git/shallow').exists()) {
|
||||
// don't clone with --depth
|
||||
revision = -1
|
||||
hash += " shallow"
|
||||
if (grgit == null) {
|
||||
revision = "nogit"
|
||||
} else {
|
||||
revision = "${grgit.log().size()}-${grgit.head().abbreviatedId}"
|
||||
if (file('.git/shallow').exists()) {
|
||||
// don't clone with --depth
|
||||
revision = "-1-${shallow}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,83 +50,64 @@ if (project.release != 'RELEASE') {
|
|||
version += "-${project.release}"
|
||||
}
|
||||
if (project.release == 'SNAPSHOT') {
|
||||
version += "-${project.revision}-${project.hash}"
|
||||
version += "-${project.revision}"
|
||||
}
|
||||
|
||||
group = project.group
|
||||
description = project.displayname
|
||||
|
||||
minecraft {
|
||||
version = project.minecraft_version
|
||||
mappings = project.mappings_version
|
||||
runDir = 'run'
|
||||
replace '@VERSION@', project.version
|
||||
}
|
||||
|
||||
mixin {
|
||||
defaultObfuscationEnv notch
|
||||
}
|
||||
|
||||
targetCompatibility = 1.8
|
||||
sourceCompatibility = 1.8
|
||||
sourceSets {
|
||||
hdskins {
|
||||
compileClasspath += main.compileClasspath
|
||||
ext.refMap = 'hdskins.mixin.refmap.json'
|
||||
}
|
||||
main {
|
||||
compileClasspath += hdskins.output
|
||||
ext.refMap = 'minelp.mixin.refmap.json'
|
||||
}
|
||||
}
|
||||
archivesBaseName = project.name
|
||||
|
||||
dependencies {
|
||||
// use the same version as httpclient
|
||||
compile('org.apache.httpcomponents:httpmime:4.3.2') {
|
||||
transitive = false
|
||||
}
|
||||
compile('org.spongepowered:mixin:0.7.11-SNAPSHOT') {
|
||||
transitive = false
|
||||
}
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}"
|
||||
modCompile "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
compileOnly "com.google.code.findbugs:jsr305:3.0.2"
|
||||
|
||||
modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
|
||||
modCompile "com.github.MineLittlePony:Kirin:${project.kirin_version}"
|
||||
include "com.github.MineLittlePony:Kirin:${project.kirin_version}"
|
||||
|
||||
// TODO: HD Skins can be made optional later
|
||||
modCompile "com.github.MineLittlePony:HDSkins:${project.hd_skins_version}"
|
||||
include "com.github.MineLittlePony:HDSkins:${project.hd_skins_version}"
|
||||
}
|
||||
|
||||
manifest {
|
||||
attributes 'Implementation-Version': "${project.version} (git-${project.hash})"
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include "fabric.mod.json"
|
||||
expand "version": project.version
|
||||
}
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
exclude "fabric.mod.json"
|
||||
}
|
||||
}
|
||||
|
||||
litemod.json {
|
||||
mcversion = project.minecraft_version
|
||||
displayName = project.displayname
|
||||
author = project.authors
|
||||
revision = project.revision
|
||||
description = project.description
|
||||
description.minelittlepony = project.description_mlp
|
||||
description.hdskinsmod = project.description_hd
|
||||
mixinConfigs += [
|
||||
'minelp.mixin.json',
|
||||
'hdskins.mixin.json'
|
||||
]
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
archivesBaseName = "mod-${project.name.toLowerCase()}"
|
||||
|
||||
afterEvaluate {
|
||||
file('build.number').delete()
|
||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
classifier = "sources"
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
|
||||
jar {
|
||||
from sourceSets.hdskins.output
|
||||
from litemod
|
||||
classifier 'base'
|
||||
extension 'jar'
|
||||
from "LICENSE"
|
||||
}
|
||||
|
||||
//
|
||||
// Imports the Background Ponies from the MLP Community Skin Pack
|
||||
//
|
||||
task copyBGPones(type: Copy) {
|
||||
|
||||
def illegals = /[^a-z0-9_\/.-]/
|
||||
|
||||
from "skins/Background Ponies"
|
||||
// TODO: What is tempDir????
|
||||
into temporaryDir
|
||||
|
||||
eachFile {
|
||||
|
@ -127,47 +117,3 @@ task copyBGPones(type: Copy) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
extension 'litemod'
|
||||
classifier "mc$minecraft.version"
|
||||
|
||||
from sourceSets.hdskins.output
|
||||
from litemod
|
||||
|
||||
exclude "/assets/minelittlepony/textures/entity/pony"
|
||||
from(copyBGPones) {
|
||||
into "/assets/minelittlepony/textures/entity/pony"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
exclude dependency('deobf.com.mumfrey:liteloader:')
|
||||
exclude dependency('deobf.org.ow2.asm:')
|
||||
exclude dependency('org.spongepowered:mixin:')
|
||||
exclude 'META-INF/**'
|
||||
}
|
||||
|
||||
relocate 'org.apache.http.entity.mime', 'com.voxelmodpack.repack.org.apache.http.entity.mime'
|
||||
exclude 'dummyThing'
|
||||
doLast {
|
||||
file('build/libs/' + archivesBaseName + '-' + version + '-base.jar').delete();
|
||||
}
|
||||
}
|
||||
|
||||
task srgJar(type: Jar) {
|
||||
from sourceSets.main.output
|
||||
from sourceSets.hdskins.output
|
||||
from litemod
|
||||
|
||||
classifier "mc$minecraft.version-srg"
|
||||
}
|
||||
|
||||
sourceJar.enabled = false
|
||||
|
||||
reobf {
|
||||
srgJar {
|
||||
mappingType = 'SEARGE'
|
||||
}
|
||||
|
||||
shadowJar{}
|
||||
}
|
||||
|
|
70
code_cleanup.xml
Normal file
70
code_cleanup.xml
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="2">
|
||||
<profile kind="CleanUpProfile" name="MineLP Cleanup" version="2">
|
||||
<setting id="cleanup.qualify_static_method_accesses_with_declaring_class" value="false"/>
|
||||
<setting id="cleanup.always_use_this_for_non_static_method_access" value="false"/>
|
||||
<setting id="cleanup.organize_imports" value="true"/>
|
||||
<setting id="cleanup.remove_trailing_whitespaces_ignore_empty" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
|
||||
<setting id="cleanup.format_source_code_changes_only" value="false"/>
|
||||
<setting id="cleanup.qualify_static_field_accesses_with_declaring_class" value="false"/>
|
||||
<setting id="cleanup.add_generated_serial_version_id" value="true"/>
|
||||
<setting id="cleanup.remove_redundant_semicolons" value="false"/>
|
||||
<setting id="cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class" value="true"/>
|
||||
<setting id="cleanup.remove_redundant_type_arguments" value="true"/>
|
||||
<setting id="cleanup.remove_unused_imports" value="true"/>
|
||||
<setting id="cleanup.insert_inferred_type_arguments" value="false"/>
|
||||
<setting id="cleanup.make_private_fields_final" value="true"/>
|
||||
<setting id="cleanup.use_lambda" value="true"/>
|
||||
<setting id="cleanup.always_use_blocks" value="true"/>
|
||||
<setting id="cleanup.use_this_for_non_static_field_access_only_if_necessary" value="true"/>
|
||||
<setting id="cleanup.sort_members_all" value="false"/>
|
||||
<setting id="cleanup.remove_trailing_whitespaces_all" value="true"/>
|
||||
<setting id="cleanup.add_missing_annotations" value="true"/>
|
||||
<setting id="cleanup.always_use_this_for_non_static_field_access" value="false"/>
|
||||
<setting id="cleanup.make_parameters_final" value="false"/>
|
||||
<setting id="cleanup.sort_members" value="false"/>
|
||||
<setting id="cleanup.remove_private_constructors" value="true"/>
|
||||
<setting id="cleanup.always_use_parentheses_in_expressions" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.source" value="11"/>
|
||||
<setting id="cleanup.remove_unused_local_variables" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.release" value="enabled"/>
|
||||
<setting id="cleanup.convert_to_enhanced_for_loop" value="true"/>
|
||||
<setting id="cleanup.remove_unused_private_fields" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.compliance" value="11"/>
|
||||
<setting id="cleanup.remove_redundant_modifiers" value="true"/>
|
||||
<setting id="cleanup.never_use_blocks" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
|
||||
<setting id="cleanup.add_missing_deprecated_annotations" value="true"/>
|
||||
<setting id="cleanup.use_this_for_non_static_field_access" value="false"/>
|
||||
<setting id="cleanup.remove_unnecessary_nls_tags" value="true"/>
|
||||
<setting id="cleanup.qualify_static_member_accesses_through_instances_with_declaring_class" value="true"/>
|
||||
<setting id="cleanup.add_missing_nls_tags" value="false"/>
|
||||
<setting id="cleanup.remove_unnecessary_casts" value="true"/>
|
||||
<setting id="cleanup.use_blocks_only_for_return_and_throw" value="false"/>
|
||||
<setting id="cleanup.format_source_code" value="true"/>
|
||||
<setting id="cleanup.convert_functional_interfaces" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="11"/>
|
||||
<setting id="cleanup.add_default_serial_version_id" value="false"/>
|
||||
<setting id="cleanup.remove_unused_private_methods" value="true"/>
|
||||
<setting id="cleanup.remove_trailing_whitespaces" value="true"/>
|
||||
<setting id="cleanup.make_type_abstract_if_missing_method" value="false"/>
|
||||
<setting id="cleanup.add_serial_version_id" value="true"/>
|
||||
<setting id="cleanup.use_this_for_non_static_method_access" value="false"/>
|
||||
<setting id="cleanup.use_this_for_non_static_method_access_only_if_necessary" value="true"/>
|
||||
<setting id="cleanup.use_anonymous_class_creation" value="false"/>
|
||||
<setting id="cleanup.add_missing_override_annotations_interface_methods" value="true"/>
|
||||
<setting id="cleanup.remove_unused_private_members" value="false"/>
|
||||
<setting id="cleanup.make_local_variable_final" value="true"/>
|
||||
<setting id="cleanup.add_missing_methods" value="false"/>
|
||||
<setting id="cleanup.never_use_parentheses_in_expressions" value="true"/>
|
||||
<setting id="cleanup.qualify_static_member_accesses_with_declaring_class" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
||||
<setting id="cleanup.use_parentheses_in_expressions" value="true"/>
|
||||
<setting id="cleanup.add_missing_override_annotations" value="true"/>
|
||||
<setting id="cleanup.use_blocks" value="true"/>
|
||||
<setting id="cleanup.make_variable_declarations_final" value="false"/>
|
||||
<setting id="cleanup.correct_indentation" value="true"/>
|
||||
<setting id="cleanup.remove_unused_private_types" value="true"/>
|
||||
</profile>
|
||||
</profiles>
|
355
code_style.xml
Normal file
355
code_style.xml
Normal file
|
@ -0,0 +1,355 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="16">
|
||||
<profile kind="CodeFormatterProfile" name="MineLP Codestyle" version="16">
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.release" value="enabled"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="3"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.source" value="11"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="11"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.compliance" value="11"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="600"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
</profile>
|
||||
</profiles>
|
|
@ -1,10 +1,22 @@
|
|||
group=com.minelittlepony
|
||||
displayname=Mine Little Pony
|
||||
authors=Verdana, Rene_Z, Mumfrey, Killjoy1221, Sollace
|
||||
description=Mine Little Pony turns players and mobs into ponies
|
||||
description_mlp=Mine Little Pony turns players and mobs into ponies. Press F9 ingame to access settings.
|
||||
description_hd=Separate skin server for Mine Little Pony that also supports HD skins. Access via button on the main menu.
|
||||
version=3.2.1
|
||||
release=SNAPSHOT
|
||||
minecraft_version=1.12.2
|
||||
mappings_version=stable_39
|
||||
org.gradle.jvmargs=-Xmx3G
|
||||
org.gradle.daemon=false
|
||||
|
||||
# Fabric Properties
|
||||
# check these on https://fabricmc.net/use
|
||||
minecraft_version=1.14.1
|
||||
yarn_mappings=1.14.1+build.5
|
||||
loader_version=0.4.7+build.147
|
||||
|
||||
# Mod Properties
|
||||
group=com.minelittlepony
|
||||
displayname=Mine Little Pony
|
||||
authors=Verdana, Rene_Z, Mumfrey, Killjoy1221, Sollace
|
||||
description=Mine Little Pony turns players and mobs into ponies. Press F9 ingame to access settings.
|
||||
version=3.2.1
|
||||
release=SNAPSHOT
|
||||
|
||||
# Dependencies
|
||||
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric
|
||||
fabric_version=0.3.0-pre+build.156
|
||||
kirin_version=1.14-fabric-SNAPSHOT
|
||||
hd_skins_version=1.14-fabric-SNAPSHOT
|
||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,5 +1,6 @@
|
|||
#Mon Apr 15 20:00:20 CAT 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package mcp;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.meta.TypeQualifierDefault;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* This annotation can be applied to a package, class or method to indicate that
|
||||
* the method in that element are nonnull by default unless there is:
|
||||
* <ul>
|
||||
* <li>An explicit nullness annotation
|
||||
* <li>The method overrides a method in a superclass (in which case the
|
||||
* annotation of the corresponding method in the superclass applies)
|
||||
* <li> there is a default parameter annotation applied to a more tightly nested
|
||||
* element.
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
@Documented
|
||||
@Nonnull
|
||||
@TypeQualifierDefault(ElementType.METHOD) // Note: This is a copy of javax.annotation.ParametersAreNonnullByDefault with target changed to METHOD
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MethodsReturnNonnullByDefault {}
|
|
@ -1,20 +0,0 @@
|
|||
package net.minecraftforge.client;
|
||||
|
||||
import net.minecraft.client.model.ModelBiped;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
// stub
|
||||
public class ForgeHooksClient {
|
||||
|
||||
public static String getArmorTexture(Entity entity, ItemStack armor, String def, EntityEquipmentSlot slot, String type) {
|
||||
return def;
|
||||
}
|
||||
|
||||
public static ModelBiped getArmorModel(EntityLivingBase entity, ItemStack item, EntityEquipmentSlot slot, ModelBiped def) {
|
||||
return def;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
|
||||
public class Button extends GuiButton implements IGuiTooltipped<Button> {
|
||||
|
||||
private int tipX = 0;
|
||||
private int tipY = 0;
|
||||
|
||||
protected IGuiAction<Button> action;
|
||||
|
||||
private List<String> tooltip = null;
|
||||
|
||||
public Button(int x, int y, String label, IGuiAction<? extends Button> callback) {
|
||||
this(x, y, 200, 20, label, callback);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Button(int x, int y, int width, int height, String label, IGuiAction<? extends Button> callback) {
|
||||
super(5000, x, y, width, height, GameGui.format(label));
|
||||
action = (IGuiAction<Button>)callback;
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
action.perform(this);
|
||||
}
|
||||
|
||||
public Button setEnabled(boolean enable) {
|
||||
enabled = enable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Button setTooltip(List<String> tooltip) {
|
||||
this.tooltip = tooltip;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected List<String> getTooltip() {
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderToolTip(Minecraft mc, int mouseX, int mouseY) {
|
||||
List<String> tooltip = getTooltip();
|
||||
|
||||
if (visible && isMouseOver() && tooltip != null) {
|
||||
mc.currentScreen.drawHoveringText(tooltip, mouseX + tipX, mouseY + tipY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Button setTooltipOffset(int x, int y) {
|
||||
tipX = x;
|
||||
tipY = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
||||
if (super.mousePressed(mc, mouseX, mouseY)) {
|
||||
perform();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
import com.mumfrey.liteloader.client.gui.GuiCheckbox;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
/**
|
||||
* Checkbox that supports a gui action when it changes.
|
||||
*
|
||||
* @author Sollace
|
||||
*
|
||||
*/
|
||||
public class Checkbox extends GuiCheckbox implements IGuiTooltipped<Checkbox> {
|
||||
|
||||
private int tipX = 0;
|
||||
private int tipY = 0;
|
||||
|
||||
private List<String> tooltip = null;
|
||||
|
||||
private final IGuiCallback<Boolean> action;
|
||||
|
||||
public Checkbox(int x, int y, String displayString, boolean value, IGuiCallback<Boolean> callback) {
|
||||
super(0, x, y, I18n.format(displayString));
|
||||
action = callback;
|
||||
checked = value;
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
checked = action.perform(!checked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Checkbox setTooltip(List<String> tooltip) {
|
||||
this.tooltip = tooltip;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderToolTip(Minecraft mc, int mouseX, int mouseY) {
|
||||
if (visible && isMouseOver() && tooltip != null) {
|
||||
mc.currentScreen.drawHoveringText(tooltip, mouseX + tipX, mouseY + tipY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Checkbox setTooltipOffset(int x, int y) {
|
||||
tipX = x;
|
||||
tipY = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
||||
if (super.mousePressed(mc, mouseX, mouseY)) {
|
||||
perform();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
import org.apache.commons.lang3.text.WordUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
|
||||
public abstract class GameGui extends GuiScreen {
|
||||
|
||||
protected static String format(String string, Object... pars) {
|
||||
return string == null ? null : I18n.format(string, pars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a translation string and returns it in a list wrapped to a given width.
|
||||
* This can be safely used in initGui, where the fontRenderer is often still null.
|
||||
*/
|
||||
protected List<String> formatMultiLine(String string, int width, Object...pars) {
|
||||
FontRenderer fr = fontRenderer;
|
||||
|
||||
if (fr == null) {
|
||||
fr = Minecraft.getMinecraft().fontRenderer;
|
||||
}
|
||||
|
||||
return fr.listFormattedStringToWidth(format(string, pars), width);
|
||||
}
|
||||
|
||||
protected void playSound(SoundEvent event) {
|
||||
mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(event, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given string to title case regardless of initial case.
|
||||
*/
|
||||
protected static String toTitleCase(String string) {
|
||||
return WordUtils.capitalize(string.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||
drawContents(mouseX, mouseY, partialTicks);
|
||||
postDrawContents(mouseX, mouseY, partialTicks);
|
||||
}
|
||||
|
||||
protected void drawContents(int mouseX, int mouseY, float partialTicks) {
|
||||
super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
}
|
||||
|
||||
protected void postDrawContents(int mouseX, int mouseY, float partialTicks) {
|
||||
buttonList.forEach(button -> {
|
||||
if (button instanceof IGuiTooltipped) {
|
||||
((IGuiTooltipped<?>)button).renderToolTip(mc, mouseX, mouseY);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
/**
|
||||
* Response actions for UI events.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IGuiAction<T> {
|
||||
/**
|
||||
* Performs this action now.
|
||||
*
|
||||
* @param value New Value of the field being changed
|
||||
* @return Adjusted value the field must take on
|
||||
*/
|
||||
void perform(T sender);
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
/**
|
||||
* Response actions for UI events.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IGuiCallback<T> {
|
||||
/**
|
||||
* Performs this action now.
|
||||
*
|
||||
* @param value New Value of the field being changed
|
||||
* @return Adjusted value the field must take on
|
||||
*/
|
||||
T perform(T value);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface element that renders a tooltip when hovered.
|
||||
*
|
||||
* @author Sollace
|
||||
*
|
||||
* @param <T> The subclass element.
|
||||
*/
|
||||
public interface IGuiTooltipped<T extends IGuiTooltipped<T>> {
|
||||
|
||||
/**
|
||||
* Sets the tooltip text with a multi-line value.
|
||||
*/
|
||||
T setTooltip(List<String> tooltip);
|
||||
|
||||
/**
|
||||
* Sets the tooltip offset from the original mouse position.
|
||||
*/
|
||||
T setTooltipOffset(int x, int y);
|
||||
|
||||
/**
|
||||
* Sets the tooltip. The passed in value will be automatically
|
||||
* translated and split into separate lines.
|
||||
*
|
||||
* @param tooltip A tooltip translation string.
|
||||
*/
|
||||
default T setTooltip(String tooltip) {
|
||||
return setTooltip(Splitter.onPattern("\r?\n|\\\\n").splitToList(GameGui.format(tooltip)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws this element's tooltip.
|
||||
*/
|
||||
void renderToolTip(Minecraft mc, int mouseX, int mouseY);
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface IStyleFactory {
|
||||
Style getStyle();
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class IconicButton extends Button {
|
||||
|
||||
private ItemStack itemStack = ItemStack.EMPTY;
|
||||
|
||||
public IconicButton(int x, int y, IGuiAction<? extends IconicButton> callback) {
|
||||
super(x, y, 20, 20, "", callback);
|
||||
}
|
||||
|
||||
public IconicButton setIcon(ItemStack stack) {
|
||||
itemStack = stack;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IconicButton setIcon(ItemStack stack, int colour) {
|
||||
Items.LEATHER_LEGGINGS.setColor(stack, colour);
|
||||
return setIcon(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks) {
|
||||
super.drawButton(mc, mouseX, mouseY, partialTicks);
|
||||
|
||||
mc.getRenderItem().renderItemIntoGUI(itemStack, x + 2, y + 2);
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
import com.voxelmodpack.hdskins.util.MoreStreams;
|
||||
|
||||
public class IconicToggle extends IconicButton {
|
||||
|
||||
private Style[] styles;
|
||||
|
||||
private int value;
|
||||
|
||||
public IconicToggle(int x, int y, int states, IGuiAction<IconicToggle> callback) {
|
||||
super(x, y, callback);
|
||||
styles = new Style[states];
|
||||
for (int i = 0; i < styles.length; i++) {
|
||||
styles[i] = new Style();
|
||||
}
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public IconicToggle setValue(int value) {
|
||||
if (this.value != value) {
|
||||
this.value = value % styles.length;
|
||||
styles[this.value].apply(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IconicToggle setStyles(IStyleFactory... styles) {
|
||||
this.styles = MoreStreams.map(styles, IStyleFactory::getStyle, Style[]::new);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IconicToggle setStyles(Style... styles) {
|
||||
this.styles = styles;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IconicToggle setStyle(Style style, int value) {
|
||||
value %= styles.length;
|
||||
|
||||
styles[value] = style;
|
||||
|
||||
if (this.value == value) {
|
||||
style.apply(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() {
|
||||
setValue(value + 1);
|
||||
super.perform();
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
|
||||
/**
|
||||
* A simple label for drawing text to a gui screen.
|
||||
*
|
||||
* @author Sollace
|
||||
*
|
||||
*/
|
||||
public class Label extends GuiButton {
|
||||
|
||||
private boolean center;
|
||||
|
||||
private int color;
|
||||
|
||||
private String text;
|
||||
|
||||
public Label(int x, int y, String translationString, int color) {
|
||||
this(x, y, translationString, color, false);
|
||||
}
|
||||
|
||||
public Label(int x, int y, String translationString, int color, boolean center) {
|
||||
super(0, x, y, "");
|
||||
this.color = color;
|
||||
this.center = center;
|
||||
this.text = translationString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks) {
|
||||
if (center) {
|
||||
drawCenteredString(mc.fontRenderer, GameGui.format(text), x, y, color);
|
||||
} else {
|
||||
drawString(mc.fontRenderer, GameGui.format(text), x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.mumfrey.liteloader.gl.GLClippingPlanes;
|
||||
import com.mumfrey.liteloader.modconfig.ConfigPanel;
|
||||
import com.mumfrey.liteloader.modconfig.ConfigPanelHost;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
|
||||
/**
|
||||
* A GuiScreen that doubles as a liteloader panel. What is this madness!?
|
||||
*/
|
||||
public abstract class SettingsPanel extends GameGui implements ConfigPanel {
|
||||
|
||||
private boolean isInPanel = false;
|
||||
|
||||
private int contentHeight;
|
||||
|
||||
@Override
|
||||
public String getPanelTitle() {
|
||||
return format(getTitle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentHeight() {
|
||||
return contentHeight + 40;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T extends GuiButton> T addButton(T button) {
|
||||
if (button.y > contentHeight) {
|
||||
contentHeight = button.y;
|
||||
}
|
||||
return super.addButton(button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelShown(ConfigPanelHost host) {
|
||||
mc = Minecraft.getMinecraft();
|
||||
width = host.getWidth();
|
||||
buttonList.clear();
|
||||
initGui();
|
||||
isInPanel = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelResize(ConfigPanelHost host) {
|
||||
width = host.getWidth();
|
||||
buttonList.clear();
|
||||
initGui();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelHidden() {
|
||||
isInPanel = false;
|
||||
onGuiClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick(ConfigPanelHost host) {
|
||||
updateScreen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPanel(ConfigPanelHost host, int mouseX, int mouseY, float partialTicks) {
|
||||
drawContents(mouseX, mouseY, partialTicks);
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GLClippingPlanes.glDisableClipping();
|
||||
|
||||
postDrawContents(mouseX, mouseY, partialTicks);
|
||||
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(ConfigPanelHost host, int mouseX, int mouseY, int mouseButton) {
|
||||
try {
|
||||
mouseClicked(mouseX, mouseY, mouseButton);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(ConfigPanelHost host, int mouseX, int mouseY, int mouseButton) {
|
||||
mouseReleased(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(ConfigPanelHost host, int mouseX, int mouseY) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(ConfigPanelHost host, char keyChar, int keyCode) {
|
||||
try {
|
||||
keyTyped(keyChar, keyCode);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawWorldBackground(int tint) {
|
||||
if (!isInPanel) {
|
||||
super.drawWorldBackground(tint);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean mustScroll() {
|
||||
return isInPanel;
|
||||
}
|
||||
|
||||
protected abstract String getTitle();
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
import net.minecraft.client.gui.GuiSlider;
|
||||
import net.minecraft.client.gui.GuiPageButtonList.GuiResponder;
|
||||
|
||||
/**
|
||||
* A slider for sliding.
|
||||
*
|
||||
* @author Sollace
|
||||
*
|
||||
*/
|
||||
public class Slider extends GuiSlider {
|
||||
|
||||
private static Responder callback;
|
||||
|
||||
public Slider(int x, int y, float minIn, float maxIn, float defaultValue, GuiSlider.FormatHelper formatter, IGuiCallback<Float> action) {
|
||||
super(callback = new Responder(action), 0, x, y, "", minIn, maxIn, defaultValue, formatter);
|
||||
callback.owner = this;
|
||||
callback = null;
|
||||
}
|
||||
|
||||
private static final class Responder implements GuiResponder {
|
||||
|
||||
private final IGuiCallback<Float> action;
|
||||
|
||||
private Slider owner;
|
||||
|
||||
private Responder(IGuiCallback<Float> callback) {
|
||||
action = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntryValue(int id, boolean value) { }
|
||||
|
||||
@Override
|
||||
public void setEntryValue(int id, float value) {
|
||||
owner.setSliderValue(action.perform(value), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntryValue(int id, String value) { }
|
||||
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package com.minelittlepony.gui;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Style implements IGuiTooltipped<Style> {
|
||||
ItemStack icon = ItemStack.EMPTY;
|
||||
|
||||
private boolean hasOffset = false;
|
||||
private int toolTipX = 0;
|
||||
private int toolTipY = 0;
|
||||
|
||||
private List<String> tooltip;
|
||||
|
||||
public Style setIcon(ItemStack stack) {
|
||||
icon = stack;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Style setIcon(ItemStack stack, int colour) {
|
||||
Items.LEATHER_LEGGINGS.setColor(stack, colour);
|
||||
return setIcon(stack);
|
||||
}
|
||||
|
||||
protected void apply(IconicToggle button) {
|
||||
button.setIcon(icon)
|
||||
.setTooltip(tooltip);
|
||||
if (hasOffset) {
|
||||
button.setTooltipOffset(toolTipX, toolTipY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Style setTooltip(List<String> tooltip) {
|
||||
this.tooltip = tooltip;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Style setTooltipOffset(int x, int y) {
|
||||
hasOffset = true;
|
||||
toolTipX = x;
|
||||
toolTipY = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderToolTip(Minecraft mc, int mouseX, int mouseY) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,345 +0,0 @@
|
|||
package com.voxelmodpack.hdskins;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||
import com.mumfrey.liteloader.core.LiteLoader;
|
||||
import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
|
||||
import com.voxelmodpack.hdskins.ducks.INetworkPlayerInfo;
|
||||
import com.voxelmodpack.hdskins.gui.GuiSkins;
|
||||
import com.voxelmodpack.hdskins.resources.SkinResourceManager;
|
||||
import com.voxelmodpack.hdskins.resources.TextureLoader;
|
||||
import com.voxelmodpack.hdskins.resources.texture.ImageBufferDownloadHD;
|
||||
import com.voxelmodpack.hdskins.server.BethlehemSkinServer;
|
||||
import com.voxelmodpack.hdskins.server.LegacySkinServer;
|
||||
import com.voxelmodpack.hdskins.server.ServerType;
|
||||
import com.voxelmodpack.hdskins.server.SkinServer;
|
||||
import com.voxelmodpack.hdskins.server.ValhallaSkinServer;
|
||||
import com.voxelmodpack.hdskins.util.CallableFutures;
|
||||
import com.voxelmodpack.hdskins.util.MoreStreams;
|
||||
import com.voxelmodpack.hdskins.util.PlayerUtil;
|
||||
import com.voxelmodpack.hdskins.util.ProfileTextureUtil;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.AbstractClientPlayer;
|
||||
import net.minecraft.client.network.NetworkPlayerInfo;
|
||||
import net.minecraft.client.renderer.ThreadDownloadImageData;
|
||||
import net.minecraft.client.renderer.texture.ITextureObject;
|
||||
import net.minecraft.client.resources.DefaultPlayerSkin;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
||||
import net.minecraft.client.resources.SkinManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class HDSkinManager implements IResourceManagerReloadListener {
|
||||
|
||||
public static final Logger logger = LogManager.getLogger();
|
||||
|
||||
public static final ExecutorService skinUploadExecutor = Executors.newSingleThreadExecutor();
|
||||
public static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8);
|
||||
public static final CloseableHttpClient httpClient = HttpClients.createSystem();
|
||||
|
||||
public static final HDSkinManager INSTANCE = new HDSkinManager();
|
||||
|
||||
private List<ISkinCacheClearListener> clearListeners = Lists.newArrayList();
|
||||
|
||||
private BiMap<String, Class<? extends SkinServer>> skinServerTypes = HashBiMap.create(2);
|
||||
private List<SkinServer> skinServers = Lists.newArrayList();
|
||||
|
||||
private LoadingCache<GameProfile, CompletableFuture<Map<Type, MinecraftProfileTexture>>> skins = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(15, TimeUnit.SECONDS)
|
||||
.build(CacheLoader.from(this::loadProfileData));
|
||||
|
||||
private List<ISkinModifier> skinModifiers = Lists.newArrayList();
|
||||
private List<ISkinParser> skinParsers = Lists.newArrayList();
|
||||
|
||||
private SkinResourceManager resources = new SkinResourceManager();
|
||||
|
||||
private Function<List<SkinServer>, GuiSkins> skinsGuiFunc = GuiSkins::new;
|
||||
|
||||
private HDSkinManager() {
|
||||
|
||||
// register default skin server types
|
||||
addSkinServerType(LegacySkinServer.class);
|
||||
addSkinServerType(ValhallaSkinServer.class);
|
||||
addSkinServerType(BethlehemSkinServer.class);
|
||||
}
|
||||
|
||||
public void setSkinsGui(Function<List<SkinServer>, GuiSkins> skinsGuiFunc) {
|
||||
Preconditions.checkNotNull(skinsGuiFunc, "skinsGuiFunc");
|
||||
this.skinsGuiFunc = skinsGuiFunc;
|
||||
}
|
||||
|
||||
public GuiSkins createSkinsGui() {
|
||||
return skinsGuiFunc.apply(ImmutableList.copyOf(this.skinServers));
|
||||
}
|
||||
|
||||
private CompletableFuture<Map<Type, MinecraftProfileTexture>> loadProfileData(GameProfile profile) {
|
||||
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
if (profile.getId() == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<Type, MinecraftProfileTexture> textureMap = Maps.newEnumMap(Type.class);
|
||||
|
||||
for (SkinServer server : skinServers) {
|
||||
try {
|
||||
server.loadProfileData(profile).getTextures().forEach(textureMap::putIfAbsent);
|
||||
if (textureMap.size() == Type.values().length) {
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.trace(e);
|
||||
}
|
||||
|
||||
}
|
||||
return textureMap;
|
||||
}, skinDownloadExecutor);
|
||||
}
|
||||
|
||||
public CompletableFuture<Map<Type, MinecraftProfileTexture>> loadProfileTextures(GameProfile profile) {
|
||||
try {
|
||||
// try to recreate a broken gameprofile
|
||||
// happens when server sends a random profile with skin and displayname
|
||||
Property textures = Iterables.getFirst(profile.getProperties().get("textures"), null);
|
||||
if (textures != null) {
|
||||
String json = new String(Base64.getDecoder().decode(textures.getValue()), StandardCharsets.UTF_8);
|
||||
MinecraftTexturesPayload texturePayload = SkinServer.gson.fromJson(json, MinecraftTexturesPayload.class);
|
||||
if (texturePayload != null) {
|
||||
// name is optional
|
||||
String name = texturePayload.getProfileName();
|
||||
UUID uuid = texturePayload.getProfileId();
|
||||
// uuid is required
|
||||
if (uuid != null) {
|
||||
profile = new GameProfile(uuid, name);
|
||||
}
|
||||
|
||||
// probably uses this texture for a reason. Don't mess with it.
|
||||
if (!texturePayload.getTextures().isEmpty() && texturePayload.getProfileId() == null) {
|
||||
return CompletableFuture.completedFuture(Collections.emptyMap());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (profile.getId() == null) {
|
||||
// Something broke server-side probably
|
||||
logger.warn("{} had a null UUID and was unable to recreate it from texture profile.", profile.getName(), e);
|
||||
return CompletableFuture.completedFuture(Collections.emptyMap());
|
||||
}
|
||||
}
|
||||
return skins.getUnchecked(profile);
|
||||
}
|
||||
|
||||
public void fetchAndLoadSkins(GameProfile profile, SkinManager.SkinAvailableCallback callback) {
|
||||
loadProfileTextures(profile).thenAcceptAsync(m -> m.forEach((type, pp) -> {
|
||||
loadTexture(type, pp, (typeIn, location, profileTexture) -> {
|
||||
parseSkin(profile, typeIn, location, profileTexture)
|
||||
.thenRun(() -> callback.skinAvailable(typeIn, location, profileTexture));
|
||||
});
|
||||
}), Minecraft.getMinecraft()::addScheduledTask);
|
||||
}
|
||||
|
||||
public ResourceLocation loadTexture(Type type, MinecraftProfileTexture texture, @Nullable SkinManager.SkinAvailableCallback callback) {
|
||||
String skinDir = type.toString().toLowerCase() + "s/";
|
||||
|
||||
final ResourceLocation resource = new ResourceLocation("hdskins", skinDir + texture.getHash());
|
||||
ITextureObject texObj = Minecraft.getMinecraft().getTextureManager().getTexture(resource);
|
||||
|
||||
//noinspection ConstantConditions
|
||||
if (texObj != null) {
|
||||
if (callback != null) {
|
||||
callback.skinAvailable(type, resource, texture);
|
||||
}
|
||||
} else {
|
||||
|
||||
// schedule texture loading on the main thread.
|
||||
TextureLoader.loadTexture(resource, new ThreadDownloadImageData(
|
||||
new File(LiteLoader.getAssetsDirectory(), "hd/" + skinDir + texture.getHash().substring(0, 2) + "/" + texture.getHash()),
|
||||
texture.getUrl(),
|
||||
DefaultPlayerSkin.getDefaultSkinLegacy(),
|
||||
new ImageBufferDownloadHD(type, () -> {
|
||||
if (callback != null) {
|
||||
callback.skinAvailable(type, resource, texture);
|
||||
}
|
||||
})));
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
public Map<Type, ResourceLocation> getTextures(GameProfile profile) {
|
||||
Map<Type, ResourceLocation> map = new HashMap<>();
|
||||
|
||||
for (Map.Entry<Type, MinecraftProfileTexture> e : loadProfileTextures(profile).getNow(Collections.emptyMap()).entrySet()) {
|
||||
map.put(e.getKey(), loadTexture(e.getKey(), e.getValue(), null));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private void addSkinServerType(Class<? extends SkinServer> type) {
|
||||
Preconditions.checkArgument(!type.isInterface(), "type cannot be an interface");
|
||||
Preconditions.checkArgument(!Modifier.isAbstract(type.getModifiers()), "type cannot be abstract");
|
||||
|
||||
ServerType st = type.getAnnotation(ServerType.class);
|
||||
|
||||
if (st == null) {
|
||||
throw new IllegalArgumentException("class is not annotated with @ServerType");
|
||||
}
|
||||
|
||||
this.skinServerTypes.put(st.value(), type);
|
||||
}
|
||||
|
||||
public Class<? extends SkinServer> getSkinServerClass(String type) {
|
||||
return this.skinServerTypes.get(type);
|
||||
}
|
||||
|
||||
void addSkinServer(SkinServer skinServer) {
|
||||
this.skinServers.add(skinServer);
|
||||
}
|
||||
|
||||
public void addClearListener(ISkinCacheClearListener listener) {
|
||||
clearListeners.add(listener);
|
||||
}
|
||||
|
||||
public void clearSkinCache() {
|
||||
LiteLoaderLogger.info("Clearing local player skin cache");
|
||||
|
||||
FileUtils.deleteQuietly(new File(LiteLoader.getAssetsDirectory(), "hd"));
|
||||
|
||||
skins.invalidateAll();
|
||||
parseSkins();
|
||||
clearListeners.removeIf(this::onSkinCacheCleared);
|
||||
}
|
||||
|
||||
private boolean onSkinCacheCleared(ISkinCacheClearListener callback) {
|
||||
try {
|
||||
return !callback.onSkinCacheCleared();
|
||||
} catch (Exception e) {
|
||||
logger.warn("Exception encountered calling skin listener '{}'. It will be removed.", callback.getClass().getName(), e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void addSkinModifier(ISkinModifier modifier) {
|
||||
skinModifiers.add(modifier);
|
||||
}
|
||||
|
||||
public void addSkinParser(ISkinParser parser) {
|
||||
skinParsers.add(parser);
|
||||
}
|
||||
|
||||
public ResourceLocation getConvertedSkin(ResourceLocation res) {
|
||||
ResourceLocation loc = resources.getConvertedResource(res);
|
||||
return loc == null ? res : loc;
|
||||
}
|
||||
|
||||
public void convertSkin(BufferedImage image, Graphics dest) {
|
||||
for (ISkinModifier skin : skinModifiers) {
|
||||
skin.convertSkin(image, dest);
|
||||
}
|
||||
}
|
||||
|
||||
public void parseSkins() {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
Streams.concat(getNPCs(mc), getPlayers(mc))
|
||||
|
||||
// filter nulls
|
||||
.filter(Objects::nonNull)
|
||||
.map(INetworkPlayerInfo.class::cast)
|
||||
.distinct()
|
||||
|
||||
// and clear skins
|
||||
.forEach(INetworkPlayerInfo::reloadTextures);
|
||||
|
||||
}
|
||||
|
||||
private Stream<NetworkPlayerInfo> getNPCs(Minecraft mc) {
|
||||
return MoreStreams.ofNullable(mc.world)
|
||||
.flatMap(w -> w.playerEntities.stream())
|
||||
.filter(AbstractClientPlayer.class::isInstance)
|
||||
.map(AbstractClientPlayer.class::cast)
|
||||
.map(PlayerUtil::getInfo);
|
||||
}
|
||||
|
||||
private Stream<NetworkPlayerInfo> getPlayers(Minecraft mc) {
|
||||
return MoreStreams.ofNullable(mc.getConnection())
|
||||
.flatMap(a -> a.getPlayerInfoMap().stream());
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> parseSkin(GameProfile profile, Type type, ResourceLocation resource, MinecraftProfileTexture texture) {
|
||||
|
||||
return CallableFutures.scheduleTask(() -> {
|
||||
|
||||
// grab the metadata object via reflection. Object is live.
|
||||
Map<String, String> metadata = ProfileTextureUtil.getMetadata(texture);
|
||||
|
||||
boolean wasNull = metadata == null;
|
||||
|
||||
if (wasNull) {
|
||||
metadata = new HashMap<>();
|
||||
} else if (metadata.containsKey("model")) {
|
||||
// try to reset the model.
|
||||
metadata.put("model", VanillaModels.of(metadata.get("model")));
|
||||
}
|
||||
|
||||
for (ISkinParser parser : skinParsers) {
|
||||
try {
|
||||
parser.parse(profile, type, resource, metadata);
|
||||
} catch (Throwable t) {
|
||||
logger.error("Exception thrown while parsing skin: ", t);
|
||||
}
|
||||
}
|
||||
|
||||
if (wasNull && !metadata.isEmpty()) {
|
||||
ProfileTextureUtil.setMetadata(texture, metadata);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager) {
|
||||
this.resources.onResourceManagerReload(resourceManager);
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package com.voxelmodpack.hdskins;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ISkinCacheClearListener {
|
||||
boolean onSkinCacheCleared();
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package com.voxelmodpack.hdskins;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ISkinModifier {
|
||||
|
||||
void convertSkin(BufferedImage skin, Graphics dest);
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package com.voxelmodpack.hdskins;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SkinParser is used to parse metadata (e.g. trigger pixels) from a texture.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ISkinParser {
|
||||
|
||||
/**
|
||||
* Parses the texture for metadata. Any discovered data should be put into
|
||||
* the metadata Map parameter.
|
||||
*
|
||||
* @param profile The profile whose skin is being parsed.
|
||||
* @param type The texture type
|
||||
* @param resource The texture location
|
||||
* @param metadata The metadata previously parsed
|
||||
*/
|
||||
void parse(GameProfile profile, Type type, ResourceLocation resource, Map<String, String> metadata);
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
package com.voxelmodpack.hdskins;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.mumfrey.liteloader.Configurable;
|
||||
import com.mumfrey.liteloader.InitCompleteListener;
|
||||
import com.mumfrey.liteloader.ViewportListener;
|
||||
import com.mumfrey.liteloader.core.LiteLoader;
|
||||
import com.mumfrey.liteloader.modconfig.AdvancedExposable;
|
||||
import com.mumfrey.liteloader.modconfig.ConfigPanel;
|
||||
import com.mumfrey.liteloader.modconfig.ConfigStrategy;
|
||||
import com.mumfrey.liteloader.modconfig.ExposableOptions;
|
||||
import com.mumfrey.liteloader.util.ModUtilities;
|
||||
import com.voxelmodpack.hdskins.gui.EntityPlayerModel;
|
||||
import com.voxelmodpack.hdskins.gui.HDSkinsConfigPanel;
|
||||
import com.voxelmodpack.hdskins.gui.RenderPlayerModel;
|
||||
import com.voxelmodpack.hdskins.server.SkinServer;
|
||||
import com.voxelmodpack.hdskins.server.SkinServerSerializer;
|
||||
import com.voxelmodpack.hdskins.upload.GLWindow;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.resources.IReloadableResourceManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
@ExposableOptions(strategy = ConfigStrategy.Unversioned, filename = "hdskins")
|
||||
public class LiteModHDSkins implements InitCompleteListener, ViewportListener, Configurable, AdvancedExposable {
|
||||
|
||||
private static LiteModHDSkins instance;
|
||||
|
||||
public static LiteModHDSkins instance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Expose
|
||||
public List<SkinServer> skin_servers = SkinServer.defaultServers;
|
||||
|
||||
@Expose
|
||||
public boolean experimentalSkinDrop = false;
|
||||
|
||||
@Expose
|
||||
public String lastChosenFile = "";
|
||||
|
||||
public LiteModHDSkins() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "HD Skins";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "4.0.0";
|
||||
}
|
||||
|
||||
public void writeConfig() {
|
||||
LiteLoader.getInstance().writeConfig(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(File configPath) {
|
||||
|
||||
// register config
|
||||
LiteLoader.getInstance().registerExposable(this, null);
|
||||
|
||||
IReloadableResourceManager irrm = (IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager();
|
||||
irrm.registerReloadListener(HDSkinManager.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upgradeSettings(String version, File configPath, File oldConfigPath) {
|
||||
HDSkinManager.INSTANCE.clearSkinCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupGsonSerialiser(GsonBuilder gsonBuilder) {
|
||||
gsonBuilder.registerTypeAdapter(SkinServer.class, new SkinServerSerializer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getConfigFile(File configFile, File configFileLocation, String defaultFileName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ConfigPanel> getConfigPanelClass() {
|
||||
return HDSkinsConfigPanel.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitCompleted(Minecraft minecraft, LiteLoader loader) {
|
||||
ModUtilities.addRenderer(EntityPlayerModel.class, new RenderPlayerModel<>(minecraft.getRenderManager()));
|
||||
|
||||
// register skin servers.
|
||||
skin_servers.forEach(HDSkinManager.INSTANCE::addSkinServer);
|
||||
|
||||
if (experimentalSkinDrop) {
|
||||
GLWindow.create();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewportResized(ScaledResolution resolution, int displayWidth, int displayHeight) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFullScreenToggled(boolean fullScreen) {
|
||||
GLWindow.current().refresh(fullScreen);
|
||||
}
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
package com.voxelmodpack.hdskins;
|
||||
|
||||
import com.voxelmodpack.hdskins.upload.IFileDialog;
|
||||
import com.voxelmodpack.hdskins.upload.ThreadOpenFilePNG;
|
||||
import com.voxelmodpack.hdskins.upload.ThreadSaveFilePNG;
|
||||
import com.voxelmodpack.hdskins.util.MoreHttpResponses;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
public class SkinChooser {
|
||||
|
||||
public static final int MAX_SKIN_DIMENSION = 1024;
|
||||
|
||||
public static final String ERR_UNREADABLE = "hdskins.error.unreadable";
|
||||
public static final String ERR_EXT = "hdskins.error.ext";
|
||||
public static final String ERR_OPEN = "hdskins.error.open";
|
||||
public static final String ERR_INVALID = "hdskins.error.invalid";
|
||||
|
||||
public static final String MSG_CHOOSE = "hdskins.choose";
|
||||
|
||||
static {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPowerOfTwo(int number) {
|
||||
return number != 0 && (number & number - 1) == 0;
|
||||
}
|
||||
|
||||
private IFileDialog openFileThread;
|
||||
|
||||
private final SkinUploader uploader;
|
||||
|
||||
|
||||
private volatile String status = MSG_CHOOSE;
|
||||
|
||||
|
||||
public SkinChooser(SkinUploader uploader) {
|
||||
this.uploader = uploader;
|
||||
}
|
||||
|
||||
public boolean pickingInProgress() {
|
||||
return openFileThread != null;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void openBrowsePNG(Minecraft mc, String title) {
|
||||
openFileThread = new ThreadOpenFilePNG(mc, title, (file, dialogResult) -> {
|
||||
openFileThread = null;
|
||||
if (dialogResult == 0) {
|
||||
selectFile(file);
|
||||
}
|
||||
});
|
||||
openFileThread.start();
|
||||
}
|
||||
|
||||
public void openSavePNG(Minecraft mc, String title) {
|
||||
openFileThread = new ThreadSaveFilePNG(mc, title, mc.getSession().getUsername() + ".png", (file, dialogResult) -> {
|
||||
if (dialogResult == 0) {
|
||||
try (MoreHttpResponses response = uploader.downloadSkin().get()) {
|
||||
if (response.ok()) {
|
||||
FileUtils.copyInputStreamToFile(response.getInputStream(), file);
|
||||
}
|
||||
} catch (IOException | InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
openFileThread = null;
|
||||
});
|
||||
openFileThread.start();
|
||||
}
|
||||
|
||||
public void selectFile(File skinFile) {
|
||||
status = evaluateAndSelect(skinFile);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String evaluateAndSelect(File skinFile) {
|
||||
if (!skinFile.exists()) {
|
||||
return ERR_UNREADABLE;
|
||||
}
|
||||
|
||||
if (!FilenameUtils.isExtension(skinFile.getName(), new String[]{"png", "PNG"})) {
|
||||
return ERR_EXT;
|
||||
}
|
||||
|
||||
try {
|
||||
BufferedImage chosenImage = ImageIO.read(skinFile);
|
||||
|
||||
if (chosenImage == null) {
|
||||
return ERR_OPEN;
|
||||
}
|
||||
|
||||
if (!acceptsSkinDimensions(chosenImage.getWidth(), chosenImage.getHeight())) {
|
||||
return ERR_INVALID;
|
||||
}
|
||||
|
||||
uploader.setLocalSkin(skinFile);
|
||||
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return ERR_OPEN;
|
||||
}
|
||||
|
||||
protected boolean acceptsSkinDimensions(int w, int h) {
|
||||
return isPowerOfTwo(w) && w == h * 2 || w == h && w <= MAX_SKIN_DIMENSION && h <= MAX_SKIN_DIMENSION;
|
||||
}
|
||||
}
|
|
@ -1,300 +0,0 @@
|
|||
package com.voxelmodpack.hdskins;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
|
||||
import com.voxelmodpack.hdskins.gui.EntityPlayerModel;
|
||||
import com.voxelmodpack.hdskins.gui.Feature;
|
||||
import com.voxelmodpack.hdskins.resources.PreviewTextureManager;
|
||||
import com.voxelmodpack.hdskins.server.HttpException;
|
||||
import com.voxelmodpack.hdskins.server.SkinServer;
|
||||
import com.voxelmodpack.hdskins.server.SkinUpload;
|
||||
import com.voxelmodpack.hdskins.util.MoreHttpResponses;
|
||||
import com.voxelmodpack.hdskins.util.NetClient;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class SkinUploader implements Closeable {
|
||||
|
||||
private final Iterator<SkinServer> skinServers;
|
||||
|
||||
public static final String ERR_NO_SERVER = "hdskins.error.noserver";
|
||||
public static final String ERR_OFFLINE = "hdskins.error.offline";
|
||||
|
||||
public static final String ERR_MOJANG = "hdskins.error.mojang";
|
||||
public static final String ERR_WAIT = "hdskins.error.mojang.wait";
|
||||
|
||||
public static final String STATUS_FETCH = "hdskins.fetch";
|
||||
|
||||
private SkinServer gateway;
|
||||
|
||||
private String status;
|
||||
|
||||
private Type skinType;
|
||||
|
||||
private Map<String, String> skinMetadata = new HashMap<String, String>();
|
||||
|
||||
private volatile boolean fetchingSkin = false;
|
||||
private volatile boolean throttlingNeck = false;
|
||||
private volatile boolean offline = false;
|
||||
|
||||
private volatile boolean sendingSkin = false;
|
||||
|
||||
private int reloadCounter = 0;
|
||||
private int retries = 1;
|
||||
|
||||
private final EntityPlayerModel remotePlayer;
|
||||
private final EntityPlayerModel localPlayer;
|
||||
|
||||
private final Object skinLock = new Object();
|
||||
|
||||
private File pendingLocalSkin;
|
||||
private File localSkin;
|
||||
|
||||
private final ISkinUploadHandler listener;
|
||||
|
||||
private final Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
private static <T> Iterator<T> cycle(List<T> list, Predicate<T> filter) {
|
||||
return Iterables.cycle(Iterables.filter(list, filter::test)).iterator();
|
||||
}
|
||||
|
||||
public SkinUploader(List<SkinServer> servers, EntityPlayerModel local, EntityPlayerModel remote, ISkinUploadHandler listener) {
|
||||
|
||||
localPlayer = local;
|
||||
remotePlayer = remote;
|
||||
|
||||
skinType = Type.SKIN;
|
||||
skinMetadata.put("model", "default");
|
||||
|
||||
this.listener = listener;
|
||||
skinServers = cycle(servers, SkinServer::verifyGateway);
|
||||
cycleGateway();
|
||||
}
|
||||
|
||||
public void cycleGateway() {
|
||||
if (skinServers.hasNext()) {
|
||||
gateway = skinServers.next();
|
||||
fetchRemote();
|
||||
} else {
|
||||
setError(ERR_NO_SERVER);
|
||||
}
|
||||
}
|
||||
|
||||
public String getGateway() {
|
||||
return gateway == null ? "" : gateway.toString();
|
||||
}
|
||||
|
||||
public boolean supportsFeature(Feature feature) {
|
||||
return gateway != null && gateway.supportsFeature(feature);
|
||||
}
|
||||
|
||||
protected void setError(String er) {
|
||||
status = er;
|
||||
sendingSkin = false;
|
||||
}
|
||||
|
||||
public void setSkinType(Type type) {
|
||||
skinType = type;
|
||||
|
||||
ItemStack stack = type == Type.ELYTRA ? new ItemStack(Items.ELYTRA) : ItemStack.EMPTY;
|
||||
// put on or take off the elytra
|
||||
localPlayer.setItemStackToSlot(EntityEquipmentSlot.CHEST, stack);
|
||||
remotePlayer.setItemStackToSlot(EntityEquipmentSlot.CHEST, stack);
|
||||
|
||||
listener.onSkinTypeChanged(type);
|
||||
}
|
||||
|
||||
public boolean uploadInProgress() {
|
||||
return sendingSkin;
|
||||
}
|
||||
|
||||
public boolean downloadInProgress() {
|
||||
return fetchingSkin;
|
||||
}
|
||||
|
||||
public boolean isThrottled() {
|
||||
return throttlingNeck;
|
||||
}
|
||||
|
||||
public boolean isOffline() {
|
||||
return offline;
|
||||
}
|
||||
|
||||
public int getRetries() {
|
||||
return retries;
|
||||
}
|
||||
|
||||
public boolean canUpload() {
|
||||
return !isOffline() && !hasStatus() && !uploadInProgress() && pendingLocalSkin == null && localSkin != null && localPlayer.isUsingLocalTexture();
|
||||
}
|
||||
|
||||
public boolean canClear() {
|
||||
return !isOffline() && !hasStatus() && !downloadInProgress() && remotePlayer.isUsingRemoteTexture();
|
||||
}
|
||||
|
||||
public boolean hasStatus() {
|
||||
return status != null;
|
||||
}
|
||||
|
||||
public String getStatusMessage() {
|
||||
return hasStatus() ? status : "";
|
||||
}
|
||||
|
||||
public void setMetadataField(String field, String value) {
|
||||
localPlayer.releaseTextures();
|
||||
skinMetadata.put(field, value);
|
||||
}
|
||||
|
||||
public String getMetadataField(String field) {
|
||||
return skinMetadata.getOrDefault(field, "");
|
||||
}
|
||||
|
||||
public Type getSkinType() {
|
||||
return skinType;
|
||||
}
|
||||
|
||||
public boolean tryClearStatus() {
|
||||
if (!hasStatus() || !uploadInProgress()) {
|
||||
status = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> uploadSkin(String statusMsg) {
|
||||
sendingSkin = true;
|
||||
status = statusMsg;
|
||||
|
||||
return gateway.uploadSkin(new SkinUpload(mc.getSession(), skinType, localSkin == null ? null : localSkin.toURI(), skinMetadata)).handle((response, throwable) -> {
|
||||
if (throwable == null) {
|
||||
LiteLoaderLogger.info("Upload completed with: %s", response);
|
||||
setError(null);
|
||||
} else {
|
||||
setError(Throwables.getRootCause(throwable).toString());
|
||||
}
|
||||
|
||||
fetchRemote();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<MoreHttpResponses> downloadSkin() {
|
||||
String loc = remotePlayer.getLocal(skinType).getRemote().getUrl();
|
||||
|
||||
return new NetClient("GET", loc).async(HDSkinManager.skinDownloadExecutor);
|
||||
}
|
||||
|
||||
protected void fetchRemote() {
|
||||
fetchingSkin = true;
|
||||
throttlingNeck = false;
|
||||
offline = false;
|
||||
|
||||
remotePlayer.reloadRemoteSkin(this, (type, location, profileTexture) -> {
|
||||
fetchingSkin = false;
|
||||
listener.onSetRemoteSkin(type, location, profileTexture);
|
||||
}).handle((a, throwable) -> {
|
||||
fetchingSkin = false;
|
||||
|
||||
if (throwable != null) {
|
||||
throwable = throwable.getCause();
|
||||
|
||||
throwable.printStackTrace();
|
||||
|
||||
if (throwable instanceof AuthenticationUnavailableException) {
|
||||
offline = true;
|
||||
} else if (throwable instanceof AuthenticationException) {
|
||||
throttlingNeck = true;
|
||||
} else if (throwable instanceof HttpException) {
|
||||
HttpException ex = (HttpException)throwable;
|
||||
|
||||
HDSkinManager.logger.error(ex.getReasonPhrase(), ex);
|
||||
|
||||
int code = ex.getStatusCode();
|
||||
|
||||
if (code >= 500) {
|
||||
setError(String.format("A fatal server error has ocurred (check logs for details): \n%s", ex.getReasonPhrase()));
|
||||
} else if (code >= 400 && code != 403 && code != 404) {
|
||||
setError(ex.getReasonPhrase());
|
||||
}
|
||||
} else {
|
||||
setError(throwable.toString());
|
||||
}
|
||||
}
|
||||
return a;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
localPlayer.releaseTextures();
|
||||
remotePlayer.releaseTextures();
|
||||
}
|
||||
|
||||
public void setLocalSkin(File skinFile) {
|
||||
mc.addScheduledTask(localPlayer::releaseTextures);
|
||||
|
||||
synchronized (skinLock) {
|
||||
pendingLocalSkin = skinFile;
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
localPlayer.updateModel();
|
||||
remotePlayer.updateModel();
|
||||
|
||||
synchronized (skinLock) {
|
||||
if (pendingLocalSkin != null) {
|
||||
System.out.println("Set " + skinType + " " + pendingLocalSkin);
|
||||
localPlayer.setLocalTexture(pendingLocalSkin, skinType);
|
||||
localSkin = pendingLocalSkin;
|
||||
pendingLocalSkin = null;
|
||||
listener.onSetLocalSkin(skinType);
|
||||
}
|
||||
}
|
||||
|
||||
if (isThrottled()) {
|
||||
reloadCounter = (reloadCounter + 1) % (200 * retries);
|
||||
if (reloadCounter == 0) {
|
||||
retries++;
|
||||
fetchRemote();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<PreviewTextureManager> loadTextures(GameProfile profile) {
|
||||
return gateway.getPreviewTextures(profile).thenApply(PreviewTextureManager::new);
|
||||
}
|
||||
|
||||
public interface ISkinUploadHandler {
|
||||
default void onSetRemoteSkin(Type type, ResourceLocation location, MinecraftProfileTexture profileTexture) {
|
||||
}
|
||||
|
||||
default void onSetLocalSkin(Type type) {
|
||||
}
|
||||
|
||||
default void onSkinTypeChanged(Type newType) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package com.voxelmodpack.hdskins;
|
||||
|
||||
public class VanillaModels {
|
||||
public static final String SLIM = "slim";
|
||||
public static final String DEFAULT = "default";
|
||||
|
||||
public static String of(String model) {
|
||||
return model != null && model.contains(SLIM) ? SLIM : DEFAULT;
|
||||
}
|
||||
|
||||
public static String nonNull(String model) {
|
||||
return model == null ? DEFAULT : SLIM;
|
||||
}
|
||||
|
||||
public static boolean isSlim(String model) {
|
||||
return SLIM.equals(model);
|
||||
}
|
||||
|
||||
public static boolean isFat(String model) {
|
||||
return DEFAULT.equals(model);
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.ducks;
|
||||
|
||||
public interface INetworkPlayerInfo {
|
||||
|
||||
void reloadTextures();
|
||||
}
|
|
@ -1,246 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.gui;
|
||||
|
||||
import static net.minecraft.client.renderer.GlStateManager.color;
|
||||
import static net.minecraft.client.renderer.GlStateManager.colorMask;
|
||||
import static net.minecraft.client.renderer.GlStateManager.depthMask;
|
||||
import static net.minecraft.client.renderer.GlStateManager.disableAlpha;
|
||||
import static net.minecraft.client.renderer.GlStateManager.disableCull;
|
||||
import static net.minecraft.client.renderer.GlStateManager.disableFog;
|
||||
import static net.minecraft.client.renderer.GlStateManager.enableAlpha;
|
||||
import static net.minecraft.client.renderer.GlStateManager.enableBlend;
|
||||
import static net.minecraft.client.renderer.GlStateManager.enableCull;
|
||||
import static net.minecraft.client.renderer.GlStateManager.enableDepth;
|
||||
import static net.minecraft.client.renderer.GlStateManager.glTexParameteri;
|
||||
import static net.minecraft.client.renderer.GlStateManager.loadIdentity;
|
||||
import static net.minecraft.client.renderer.GlStateManager.matrixMode;
|
||||
import static net.minecraft.client.renderer.GlStateManager.popMatrix;
|
||||
import static net.minecraft.client.renderer.GlStateManager.pushMatrix;
|
||||
import static net.minecraft.client.renderer.GlStateManager.rotate;
|
||||
import static net.minecraft.client.renderer.GlStateManager.translate;
|
||||
import static net.minecraft.client.renderer.GlStateManager.tryBlendFuncSeparate;
|
||||
import static net.minecraft.client.renderer.GlStateManager.viewport;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.util.glu.Project;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
public class CubeMap {
|
||||
|
||||
private int updateCounter = 0;
|
||||
|
||||
private float lastPartialTick;
|
||||
|
||||
private float zLevel;
|
||||
|
||||
private ResourceLocation viewportTexture;
|
||||
|
||||
private ResourceLocation[] cubemapTextures;
|
||||
|
||||
private Minecraft mc;
|
||||
|
||||
private final GuiScreen owner;
|
||||
|
||||
public CubeMap(GuiScreen owner) {
|
||||
this.owner = owner;
|
||||
mc = Minecraft.getMinecraft();
|
||||
}
|
||||
|
||||
public float getDelta(float partialTick) {
|
||||
return updateCounter + partialTick - lastPartialTick;
|
||||
}
|
||||
|
||||
public void setSource(String source) {
|
||||
cubemapTextures = new ResourceLocation[] {
|
||||
new ResourceLocation(String.format(source, 0)),
|
||||
new ResourceLocation(String.format(source, 1)),
|
||||
new ResourceLocation(String.format(source, 2)),
|
||||
new ResourceLocation(String.format(source, 3)),
|
||||
new ResourceLocation(String.format(source, 4)),
|
||||
new ResourceLocation(String.format(source, 5))
|
||||
};
|
||||
}
|
||||
|
||||
public void init() {
|
||||
viewportTexture = mc.getTextureManager().getDynamicTextureLocation("skinpanorama", new DynamicTexture(256, 256));
|
||||
}
|
||||
|
||||
public void update() {
|
||||
updateCounter++;
|
||||
}
|
||||
|
||||
public void render(float partialTick, float z) {
|
||||
zLevel = z;
|
||||
lastPartialTick = updateCounter + partialTick;
|
||||
|
||||
disableFog();
|
||||
mc.entityRenderer.disableLightmap();
|
||||
disableAlpha();
|
||||
renderPanorama(partialTick);
|
||||
enableAlpha();
|
||||
}
|
||||
|
||||
private void setupCubemapCamera() {
|
||||
matrixMode(GL11.GL_PROJECTION);
|
||||
pushMatrix();
|
||||
loadIdentity();
|
||||
Project.gluPerspective(120, 1, 0.05F, 10);
|
||||
matrixMode(GL11.GL_MODELVIEW);
|
||||
pushMatrix();
|
||||
loadIdentity();
|
||||
}
|
||||
|
||||
private void revertPanoramaMatrix() {
|
||||
matrixMode(GL11.GL_PROJECTION);
|
||||
popMatrix();
|
||||
matrixMode(GL11.GL_MODELVIEW);
|
||||
popMatrix();
|
||||
}
|
||||
|
||||
private void renderCubeMapTexture(float partialTick) {
|
||||
this.setupCubemapCamera();
|
||||
color(1, 1, 1, 1);
|
||||
rotate(180, 1, 0, 0);
|
||||
|
||||
enableBlend();
|
||||
disableAlpha();
|
||||
disableCull();
|
||||
depthMask(false);
|
||||
tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO);
|
||||
byte blendIterations = 8;
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder vb = tessellator.getBuffer();
|
||||
|
||||
for (int blendPass = 0; blendPass < blendIterations * blendIterations; ++blendPass) {
|
||||
pushMatrix();
|
||||
float offsetX = ((float) (blendPass % blendIterations) / (float) blendIterations - 0.5F) / 64;
|
||||
float offsetY = ((float) (blendPass / blendIterations) / (float) blendIterations - 0.5F) / 64;
|
||||
|
||||
translate(offsetX, offsetY, 0);
|
||||
rotate(MathHelper.sin(lastPartialTick / 400) * 25 + 20, 1, 0, 0);
|
||||
rotate(-lastPartialTick / 10, 0, 1, 0);
|
||||
|
||||
for (int cubeSide = 0; cubeSide < 6; ++cubeSide) {
|
||||
pushMatrix();
|
||||
if (cubeSide == 1) {
|
||||
rotate(90, 0, 1, 0);
|
||||
}
|
||||
|
||||
if (cubeSide == 2) {
|
||||
rotate(180, 0, 1, 0);
|
||||
}
|
||||
|
||||
if (cubeSide == 3) {
|
||||
rotate(-90, 0, 1, 0);
|
||||
}
|
||||
|
||||
if (cubeSide == 4) {
|
||||
rotate(90, 1, 0, 0);
|
||||
}
|
||||
|
||||
if (cubeSide == 5) {
|
||||
rotate(-90, 1, 0, 0);
|
||||
}
|
||||
|
||||
mc.getTextureManager().bindTexture(cubemapTextures[cubeSide]);
|
||||
|
||||
vb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
|
||||
int l = 255 / (blendPass + 1);
|
||||
|
||||
vb.pos(-1, -1, 1).tex(0, 0).color(255, 255, 255, l).endVertex();
|
||||
vb.pos(1, -1, 1).tex(1, 0).color(255, 255, 255, l).endVertex();
|
||||
vb.pos(1, 1, 1).tex(1, 1).color(255, 255, 255, l).endVertex();
|
||||
vb.pos(-1, 1, 1).tex(0, 1).color(255, 255, 255, l).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
popMatrix();
|
||||
}
|
||||
|
||||
popMatrix();
|
||||
colorMask(true, true, true, false);
|
||||
}
|
||||
|
||||
vb.setTranslation(0.0D, 0.0D, 0.0D);
|
||||
colorMask(true, true, true, true);
|
||||
depthMask(true);
|
||||
enableCull();
|
||||
enableAlpha();
|
||||
enableDepth();
|
||||
this.revertPanoramaMatrix();
|
||||
}
|
||||
|
||||
private void rotateAndBlurCubemap() {
|
||||
mc.getTextureManager().bindTexture(viewportTexture);
|
||||
|
||||
glTexParameteri(3553, 10241, 9729);
|
||||
glTexParameteri(3553, 10240, 9729);
|
||||
GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, 256, 256);
|
||||
enableBlend();
|
||||
tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO);
|
||||
colorMask(true, true, true, false);
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder vb = tessellator.getBuffer();
|
||||
vb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
disableAlpha();
|
||||
|
||||
byte blurPasses = 3;
|
||||
|
||||
for (int blurPass = 0; blurPass < blurPasses; ++blurPass) {
|
||||
float f = 1 / (float)(blurPass + 1);
|
||||
float var7 = (blurPass - 1) / 256F;
|
||||
|
||||
vb.pos(owner.width, owner.height, zLevel).tex(var7, 1).color(1, 1, 1, f).endVertex();
|
||||
vb.pos(owner.width, 0, zLevel).tex(1 + var7, 1).color(1, 1, 1, f).endVertex();
|
||||
vb.pos(0, 0, zLevel).tex(1 + var7, 0).color(1, 1, 1, f).endVertex();
|
||||
vb.pos(0, owner.height, zLevel).tex(var7, 0).color(1, 1, 1, f).endVertex();
|
||||
}
|
||||
|
||||
tessellator.draw();
|
||||
enableAlpha();
|
||||
colorMask(true, true, true, true);
|
||||
}
|
||||
|
||||
private void renderPanorama(float partialTicks) {
|
||||
mc.getFramebuffer().unbindFramebuffer();
|
||||
|
||||
viewport(0, 0, 256, 256);
|
||||
renderCubeMapTexture(partialTicks);
|
||||
|
||||
for (int tessellator = 0; tessellator < 8; ++tessellator) {
|
||||
rotateAndBlurCubemap();
|
||||
}
|
||||
|
||||
mc.getFramebuffer().bindFramebuffer(true);
|
||||
|
||||
viewport(0, 0, mc.displayWidth, mc.displayHeight);
|
||||
|
||||
float aspect = owner.width > owner.height ? 120F / owner.width : 120F / owner.height;
|
||||
float uSample = owner.height * aspect / 256F;
|
||||
float vSample = owner.width * aspect / 256F;
|
||||
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder vb = tessellator.getBuffer();
|
||||
vb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
vb.pos(0, owner.height, zLevel).tex(0.5F - uSample, 0.5F + vSample).endVertex();
|
||||
vb.pos(owner.width, owner.height, zLevel).tex(0.5F - uSample, 0.5F - vSample).endVertex();
|
||||
vb.pos(owner.width, 0, zLevel).tex(0.5F + uSample, 0.5F - vSample).endVertex();
|
||||
vb.pos(0, 0, zLevel).tex(0.5F + uSample, 0.5F + vSample).endVertex();
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.gui;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.GameType;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldProviderSurface;
|
||||
import net.minecraft.world.WorldSettings;
|
||||
import net.minecraft.world.WorldType;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
import net.minecraft.world.storage.WorldInfo;
|
||||
|
||||
public class DummyWorld extends World {
|
||||
|
||||
public static final World INSTANCE = new DummyWorld();
|
||||
|
||||
private final Chunk chunk = new Chunk(this, 0, 0);
|
||||
|
||||
private DummyWorld() {
|
||||
super(null,
|
||||
new WorldInfo(new WorldSettings(0, GameType.NOT_SET, false, false, WorldType.DEFAULT), "MpServer"),
|
||||
new WorldProviderSurface(),
|
||||
null,
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IChunkProvider createChunkProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isChunkLoaded(int x, int z, boolean allowEmpty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk(int chunkX, int chunkZ) {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getBlockState(BlockPos pos) {
|
||||
return Blocks.AIR.getDefaultState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getLightBrightness(BlockPos pos) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getSpawnPoint() {
|
||||
return BlockPos.ORIGIN;
|
||||
}
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.gui;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.voxelmodpack.hdskins.SkinUploader;
|
||||
import com.voxelmodpack.hdskins.resources.LocalTexture;
|
||||
import com.voxelmodpack.hdskins.resources.LocalTexture.IBlankSkinSupplier;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.SkinManager;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumHandSide;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@SuppressWarnings("EntityConstructor")
|
||||
public class EntityPlayerModel extends EntityLivingBase implements IBlankSkinSupplier {
|
||||
|
||||
public static final ResourceLocation NO_SKIN = new ResourceLocation("hdskins", "textures/mob/noskin.png");
|
||||
public static final ResourceLocation NO_ELYTRA = new ResourceLocation("textures/entity/elytra.png");
|
||||
|
||||
private final Map<EntityEquipmentSlot, ItemStack> armour = Maps.newEnumMap(ImmutableMap.of(
|
||||
EntityEquipmentSlot.HEAD, ItemStack.EMPTY,
|
||||
EntityEquipmentSlot.CHEST, ItemStack.EMPTY,
|
||||
EntityEquipmentSlot.LEGS, ItemStack.EMPTY,
|
||||
EntityEquipmentSlot.FEET, ItemStack.EMPTY,
|
||||
EntityEquipmentSlot.MAINHAND, ItemStack.EMPTY
|
||||
));
|
||||
|
||||
protected final LocalTexture skin;
|
||||
protected final LocalTexture elytra;
|
||||
|
||||
|
||||
private final GameProfile profile;
|
||||
|
||||
protected boolean previewThinArms = false;
|
||||
protected boolean previewSleeping = false;
|
||||
protected boolean previewRiding = false;
|
||||
|
||||
public EntityPlayerModel(GameProfile gameprofile) {
|
||||
super(DummyWorld.INSTANCE);
|
||||
|
||||
profile = gameprofile;
|
||||
|
||||
skin = new LocalTexture(profile, Type.SKIN, this);
|
||||
elytra = new LocalTexture(profile, Type.ELYTRA, this);
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> reloadRemoteSkin(SkinUploader uploader, SkinManager.SkinAvailableCallback listener) {
|
||||
return uploader.loadTextures(profile).thenAcceptAsync(ptm -> {
|
||||
skin.setRemote(ptm, listener);
|
||||
elytra.setRemote(ptm, listener);
|
||||
}, Minecraft.getMinecraft()::addScheduledTask); // run on main thread
|
||||
}
|
||||
|
||||
public void setLocalTexture(File skinTextureFile, Type type) {
|
||||
if (type == Type.SKIN) {
|
||||
skin.setLocal(skinTextureFile);
|
||||
} else if (type == Type.ELYTRA) {
|
||||
elytra.setLocal(skinTextureFile);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getBlankSkin(Type type) {
|
||||
return type == Type.SKIN ? NO_SKIN : NO_ELYTRA;
|
||||
}
|
||||
|
||||
public boolean isUsingLocalTexture() {
|
||||
return skin.usingLocal() || elytra.usingLocal();
|
||||
}
|
||||
|
||||
public boolean isTextureSetupComplete() {
|
||||
return skin.uploadComplete() && elytra.uploadComplete();
|
||||
}
|
||||
|
||||
public boolean isUsingRemoteTexture() {
|
||||
return skin.hasRemoteTexture() || elytra.hasRemoteTexture();
|
||||
}
|
||||
|
||||
public void releaseTextures() {
|
||||
skin.clearLocal();
|
||||
elytra.clearLocal();
|
||||
}
|
||||
|
||||
public LocalTexture getLocal(Type type) {
|
||||
return type == Type.SKIN ? skin : elytra;
|
||||
}
|
||||
|
||||
public void setPreviewThinArms(boolean thinArms) {
|
||||
previewThinArms = thinArms;
|
||||
}
|
||||
|
||||
public boolean usesThinSkin() {
|
||||
if (skin.uploadComplete() && skin.getRemote().hasModel()) {
|
||||
return skin.getRemote().usesThinArms();
|
||||
}
|
||||
|
||||
return previewThinArms;
|
||||
}
|
||||
|
||||
public void setSleeping(boolean sleep) {
|
||||
previewSleeping = sleep;
|
||||
}
|
||||
|
||||
public void setRiding(boolean ride) {
|
||||
previewRiding = ride;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRiding() {
|
||||
return previewRiding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayerSleeping() {
|
||||
return !previewRiding && previewSleeping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSneaking() {
|
||||
return !previewRiding && !previewSleeping && super.isSneaking();
|
||||
}
|
||||
|
||||
public void updateModel() {
|
||||
prevSwingProgress = swingProgress;
|
||||
if (isSwingInProgress) {
|
||||
++swingProgressInt;
|
||||
if (swingProgressInt >= 8) {
|
||||
swingProgressInt = 0;
|
||||
isSwingInProgress = false;
|
||||
}
|
||||
} else {
|
||||
swingProgressInt = 0;
|
||||
}
|
||||
|
||||
swingProgress = swingProgressInt / 8F;
|
||||
|
||||
motionY *= 0.98;
|
||||
if (Math.abs(motionY) < 0.003) {
|
||||
motionY = 0;
|
||||
}
|
||||
|
||||
if (posY == 0 && isJumping && !previewSleeping && !previewRiding) {
|
||||
jump();
|
||||
}
|
||||
|
||||
|
||||
motionY -= 0.08D;
|
||||
motionY *= 0.9800000190734863D;
|
||||
|
||||
posY += motionY;
|
||||
|
||||
if (posY < 0) {
|
||||
posY = 0;
|
||||
}
|
||||
onGround = posY == 0;
|
||||
|
||||
ticksExisted++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumHandSide getPrimaryHand() {
|
||||
return Minecraft.getMinecraft().gameSettings.mainHand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<ItemStack> getArmorInventoryList() {
|
||||
return armour.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStackFromSlot(EntityEquipmentSlot slotIn) {
|
||||
return armour.get(slotIn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemStackToSlot(EntityEquipmentSlot slotIn, ItemStack stack) {
|
||||
armour.put(slotIn, stack);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.gui;
|
||||
|
||||
/**
|
||||
* Represents the possible features that a skin server can implement.
|
||||
*/
|
||||
public enum Feature {
|
||||
/**
|
||||
* Whether a server has write access.
|
||||
* i.e. If the server allows for users to upload a new skin.
|
||||
*/
|
||||
UPLOAD_USER_SKIN,
|
||||
/**
|
||||
* Whether a server allows for downloading and saving a user's skin.
|
||||
* Most servers should support this.
|
||||
*/
|
||||
DOWNLOAD_USER_SKIN,
|
||||
/**
|
||||
* Whether a server has delete access.
|
||||
* i.e. If the server allows a user to deleted a previously uploaded skin.
|
||||
*/
|
||||
DELETE_USER_SKIN,
|
||||
/**
|
||||
* Whether a server can send a full list of skins for a given profile.
|
||||
* Typically used for servers that keep a record of past uploads
|
||||
* and/or allow for switching between past skins.
|
||||
*/
|
||||
FETCH_SKIN_LIST,
|
||||
/**
|
||||
* Whether a server supports thin (Alex) skins or just default (Steve) skins.
|
||||
* Servers without this will typically fall back to using the player's uuid on the client side.
|
||||
*
|
||||
* (unused)
|
||||
*/
|
||||
MODEL_VARIANTS,
|
||||
/**
|
||||
* Whether a server allows for uploading alternative skin types. i.e. Cape, Elytra, Hats and wears.
|
||||
*/
|
||||
MODEL_TYPES,
|
||||
/**
|
||||
* Whether a server will accept arbitrary extra metadata values with skin uploads.
|
||||
*
|
||||
* (unused)
|
||||
*/
|
||||
MODEL_METADATA,
|
||||
/**
|
||||
* Whether a server can provide a link to view a user's profile online,
|
||||
* typically through a web-portal.
|
||||
*/
|
||||
LINK_PROFILE
|
||||
}
|
|
@ -1,593 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.gui;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.minelittlepony.gui.Button;
|
||||
import com.minelittlepony.gui.GameGui;
|
||||
import com.minelittlepony.gui.IGuiAction;
|
||||
import com.minelittlepony.gui.IconicButton;
|
||||
import com.minelittlepony.gui.IconicToggle;
|
||||
import com.minelittlepony.gui.Label;
|
||||
import com.minelittlepony.gui.Style;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
import com.voxelmodpack.hdskins.SkinChooser;
|
||||
import com.voxelmodpack.hdskins.SkinUploader;
|
||||
import com.voxelmodpack.hdskins.SkinUploader.ISkinUploadHandler;
|
||||
import com.voxelmodpack.hdskins.VanillaModels;
|
||||
import com.voxelmodpack.hdskins.server.SkinServer;
|
||||
import com.voxelmodpack.hdskins.upload.GLWindow;
|
||||
import com.voxelmodpack.hdskins.util.CallableFutures;
|
||||
import com.voxelmodpack.hdskins.util.Edge;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import static net.minecraft.client.renderer.GlStateManager.*;
|
||||
|
||||
public class GuiSkins extends GameGui implements ISkinUploadHandler {
|
||||
|
||||
private int updateCounter = 0;
|
||||
|
||||
private Button btnBrowse;
|
||||
private FeatureButton btnUpload;
|
||||
private FeatureButton btnDownload;
|
||||
private FeatureButton btnClear;
|
||||
|
||||
private FeatureSwitch btnModeSteve;
|
||||
private FeatureSwitch btnModeAlex;
|
||||
|
||||
private FeatureSwitch btnModeSkin;
|
||||
private FeatureSwitch btnModeElytra;
|
||||
|
||||
protected EntityPlayerModel localPlayer;
|
||||
protected EntityPlayerModel remotePlayer;
|
||||
|
||||
private DoubleBuffer doubleBuffer;
|
||||
|
||||
private float msgFadeOpacity = 0;
|
||||
|
||||
private int lastMouseX = 0;
|
||||
|
||||
private boolean jumpState = false;
|
||||
private boolean sneakState = false;
|
||||
|
||||
protected final SkinUploader uploader;
|
||||
protected final SkinChooser chooser;
|
||||
|
||||
protected final CubeMap panorama;
|
||||
|
||||
private final Edge ctrlKey = new Edge(this::ctrlToggled) {
|
||||
@Override
|
||||
protected boolean nextState() {
|
||||
return GuiScreen.isCtrlKeyDown();
|
||||
}
|
||||
};
|
||||
private final Edge jumpKey = new Edge(this::jumpToggled) {
|
||||
@Override
|
||||
protected boolean nextState() {
|
||||
return Keyboard.isKeyDown(Keyboard.KEY_SPACE);
|
||||
}
|
||||
};
|
||||
private final Edge sneakKey = new Edge(this::sneakToggled) {
|
||||
@Override
|
||||
protected boolean nextState() {
|
||||
return GuiScreen.isShiftKeyDown();
|
||||
}
|
||||
};
|
||||
|
||||
public GuiSkins(List<SkinServer> servers) {
|
||||
mc = Minecraft.getMinecraft();
|
||||
GameProfile profile = mc.getSession().getProfile();
|
||||
|
||||
localPlayer = getModel(profile);
|
||||
remotePlayer = getModel(profile);
|
||||
|
||||
RenderManager rm = mc.getRenderManager();
|
||||
rm.renderEngine = mc.getTextureManager();
|
||||
rm.options = mc.gameSettings;
|
||||
rm.renderViewEntity = localPlayer;
|
||||
|
||||
uploader = new SkinUploader(servers, localPlayer, remotePlayer, this);
|
||||
chooser = new SkinChooser(uploader);
|
||||
panorama = new CubeMap(this);
|
||||
initPanorama();
|
||||
}
|
||||
|
||||
protected void initPanorama() {
|
||||
panorama.setSource("hdskins:textures/cubemaps/cubemap0_%d.png");
|
||||
}
|
||||
|
||||
protected EntityPlayerModel getModel(GameProfile profile) {
|
||||
return new EntityPlayerModel(profile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
|
||||
if (!(Keyboard.isKeyDown(Keyboard.KEY_LEFT) || Keyboard.isKeyDown(Keyboard.KEY_RIGHT))) {
|
||||
updateCounter++;
|
||||
}
|
||||
|
||||
panorama.update();
|
||||
uploader.update();
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
GLWindow.current().setDropTargetListener(files -> {
|
||||
files.stream().findFirst().ifPresent(file -> {
|
||||
chooser.selectFile(file);
|
||||
updateButtons();
|
||||
});
|
||||
});
|
||||
|
||||
panorama.init();
|
||||
|
||||
addButton(new Label(width / 2, 10, "hdskins.manager", 0xffffff, true));
|
||||
addButton(new Label(34, 34, "hdskins.local", 0xffffff));
|
||||
addButton(new Label(width / 2 + 34, 34, "hdskins.server", 0xffffff));
|
||||
|
||||
addButton(btnBrowse = new Button(width / 2 - 150, height - 27, 90, 20, "hdskins.options.browse", sender ->
|
||||
chooser.openBrowsePNG(mc, format("hdskins.open.title"))))
|
||||
.setEnabled(!mc.isFullScreen());
|
||||
|
||||
addButton(btnUpload = new FeatureButton(width / 2 - 24, height / 2 - 20, 48, 20, "hdskins.options.chevy", sender -> {
|
||||
if (uploader.canUpload()) {
|
||||
punchServer("hdskins.upload");
|
||||
}
|
||||
})).setEnabled(uploader.canUpload())
|
||||
.setTooltip("hdskins.options.chevy.title");
|
||||
|
||||
addButton(btnDownload = new FeatureButton(width / 2 - 24, height / 2 + 20, 48, 20, "hdskins.options.download", sender -> {
|
||||
if (uploader.canClear()) {
|
||||
chooser.openSavePNG(mc, format("hdskins.save.title"));
|
||||
}
|
||||
})).setEnabled(uploader.canClear())
|
||||
.setTooltip("hdskins.options.download.title");
|
||||
|
||||
addButton(btnClear = new FeatureButton(width / 2 + 60, height - 27, 90, 20, "hdskins.options.clear", sender -> {
|
||||
if (uploader.canClear()) {
|
||||
punchServer("hdskins.request");
|
||||
}
|
||||
})).setEnabled(uploader.canClear());
|
||||
|
||||
addButton(new Button(width / 2 - 50, height - 25, 100, 20, "hdskins.options.close", sender ->
|
||||
mc.displayGuiScreen(new GuiMainMenu())));
|
||||
|
||||
addButton(btnModeSteve = new FeatureSwitch(width - 25, 32, sender -> switchSkinMode(VanillaModels.DEFAULT)))
|
||||
.setIcon(new ItemStack(Items.LEATHER_LEGGINGS), 0x3c5dcb)
|
||||
.setEnabled(VanillaModels.isSlim(uploader.getMetadataField("model")))
|
||||
.setTooltip("hdskins.mode.steve")
|
||||
.setTooltipOffset(0, 10);
|
||||
|
||||
addButton(btnModeAlex = new FeatureSwitch(width - 25, 51, sender -> switchSkinMode(VanillaModels.SLIM)))
|
||||
.setIcon(new ItemStack(Items.LEATHER_LEGGINGS), 0xfff500)
|
||||
.setEnabled(VanillaModels.isFat(uploader.getMetadataField("model")))
|
||||
.setTooltip("hdskins.mode.alex")
|
||||
.setTooltipOffset(0, 10);
|
||||
|
||||
addButton(btnModeSkin = new FeatureSwitch(width - 25, 75, sender -> uploader.setSkinType(Type.SKIN)))
|
||||
.setIcon(new ItemStack(Items.LEATHER_CHESTPLATE))
|
||||
.setEnabled(uploader.getSkinType() == Type.ELYTRA)
|
||||
.setTooltip(format("hdskins.mode." + Type.SKIN.name().toLowerCase()))
|
||||
.setTooltipOffset(0, 10);
|
||||
|
||||
addButton(btnModeElytra = new FeatureSwitch(width - 25, 94, sender -> uploader.setSkinType(Type.ELYTRA)))
|
||||
.setIcon(new ItemStack(Items.ELYTRA))
|
||||
.setEnabled(uploader.getSkinType() == Type.SKIN)
|
||||
.setTooltip(format("hdskins.mode." + Type.ELYTRA.name().toLowerCase()))
|
||||
.setTooltipOffset(0, 10);
|
||||
|
||||
addButton(new IconicToggle(width - 25, 118, 3, sender -> {
|
||||
playSound(SoundEvents.BLOCK_BREWING_STAND_BREW);
|
||||
|
||||
boolean sleep = sender.getValue() == 1;
|
||||
boolean ride = sender.getValue() == 2;
|
||||
localPlayer.setSleeping(sleep);
|
||||
remotePlayer.setSleeping(sleep);
|
||||
|
||||
localPlayer.setRiding(ride);
|
||||
remotePlayer.setRiding(ride);
|
||||
}))
|
||||
.setValue(localPlayer.isPlayerSleeping() ? 1 : 0)
|
||||
.setStyle(new Style().setIcon(new ItemStack(Items.IRON_BOOTS, 1)).setTooltip("hdskins.mode.stand"), 0)
|
||||
.setStyle(new Style().setIcon(new ItemStack(Items.CLOCK, 1)).setTooltip("hdskins.mode.sleep"), 1)
|
||||
.setStyle(new Style().setIcon(new ItemStack(Items.BOAT, 1)).setTooltip("hdskins.mode.ride"), 2)
|
||||
.setTooltipOffset(0, 10);
|
||||
|
||||
addButton(new Button(width - 25, height - 65, 20, 20, "?", sender -> {
|
||||
uploader.cycleGateway();
|
||||
playSound(SoundEvents.ENTITY_VILLAGER_YES);
|
||||
sender.setTooltip(uploader.getGateway());
|
||||
}))
|
||||
.setTooltip(uploader.getGateway())
|
||||
.setTooltipOffset(0, 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
super.onGuiClosed();
|
||||
try {
|
||||
uploader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
HDSkinManager.INSTANCE.clearSkinCache();
|
||||
|
||||
GLWindow.current().clearDropTargetListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSkinTypeChanged(Type newType) {
|
||||
playSound(SoundEvents.BLOCK_BREWING_STAND_BREW);
|
||||
|
||||
btnModeSkin.enabled = newType == Type.ELYTRA;
|
||||
btnModeElytra.enabled = newType == Type.SKIN;
|
||||
}
|
||||
|
||||
protected void switchSkinMode(String model) {
|
||||
playSound(SoundEvents.BLOCK_BREWING_STAND_BREW);
|
||||
|
||||
boolean thinArmType = VanillaModels.isSlim(model);
|
||||
|
||||
btnModeSteve.enabled = thinArmType;
|
||||
btnModeAlex.enabled = !thinArmType;
|
||||
|
||||
uploader.setMetadataField("model", model);
|
||||
localPlayer.setPreviewThinArms(thinArmType);
|
||||
remotePlayer.setPreviewThinArms(thinArmType);
|
||||
}
|
||||
|
||||
protected boolean canTakeEvents() {
|
||||
return !chooser.pickingInProgress() && uploader.tryClearStatus() && msgFadeOpacity == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(GuiButton guiButton) throws IOException {
|
||||
if (canTakeEvents()) {
|
||||
super.actionPerformed(guiButton);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int button) throws IOException {
|
||||
if (canTakeEvents()) {
|
||||
super.mouseClicked(mouseX, mouseY, button);
|
||||
|
||||
int bottom = height - 40;
|
||||
int mid = width / 2;
|
||||
|
||||
if ((mouseX > 30 && mouseX < mid - 30 || mouseX > mid + 30 && mouseX < width - 30) && mouseY > 30 && mouseY < bottom) {
|
||||
localPlayer.swingArm(EnumHand.MAIN_HAND);
|
||||
remotePlayer.swingArm(EnumHand.MAIN_HAND);
|
||||
}
|
||||
}
|
||||
|
||||
lastMouseX = mouseX;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
|
||||
if (canTakeEvents()) {
|
||||
updateCounter -= (lastMouseX - mouseX);
|
||||
}
|
||||
lastMouseX = mouseX;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char keyChar, int keyCode) throws IOException {
|
||||
if (canTakeEvents()) {
|
||||
if (keyCode == Keyboard.KEY_LEFT) {
|
||||
updateCounter -= 5;
|
||||
} else if (keyCode == Keyboard.KEY_RIGHT) {
|
||||
updateCounter += 5;
|
||||
}
|
||||
|
||||
if (!chooser.pickingInProgress() && !uploader.uploadInProgress()) {
|
||||
super.keyTyped(keyChar, keyCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void jumpToggled(boolean jumping) {
|
||||
if (jumping && ctrlKey.getState()) {
|
||||
jumpState = !jumpState;
|
||||
}
|
||||
|
||||
jumping |= jumpState;
|
||||
|
||||
localPlayer.setJumping(jumping);
|
||||
remotePlayer.setJumping(jumping);
|
||||
}
|
||||
|
||||
private void sneakToggled(boolean sneaking) {
|
||||
if (sneaking && ctrlKey.getState()) {
|
||||
sneakState = !sneakState;
|
||||
}
|
||||
|
||||
sneaking |= sneakState;
|
||||
|
||||
localPlayer.setSneaking(sneaking);
|
||||
remotePlayer.setSneaking(sneaking);
|
||||
}
|
||||
|
||||
private void ctrlToggled(boolean ctrl) {
|
||||
if (ctrl) {
|
||||
if (sneakKey.getState()) {
|
||||
sneakState = !sneakState;
|
||||
}
|
||||
|
||||
if (jumpKey.getState()) {
|
||||
jumpState = !jumpState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawContents(int mouseX, int mouseY, float partialTick) {
|
||||
ctrlKey.update();
|
||||
jumpKey.update();
|
||||
sneakKey.update();
|
||||
|
||||
float deltaTime = panorama.getDelta(partialTick);
|
||||
panorama.render(partialTick, zLevel);
|
||||
|
||||
int bottom = height - 40;
|
||||
int mid = width / 2;
|
||||
int horizon = height / 2 + height / 5;
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
|
||||
drawRect(30, 30, mid - 30, bottom, Integer.MIN_VALUE);
|
||||
drawRect(mid + 30, 30, width - 30, bottom, Integer.MIN_VALUE);
|
||||
|
||||
drawGradientRect(30, horizon, mid - 30, bottom, 0x80FFFFFF, 0xffffff);
|
||||
drawGradientRect(mid + 30, horizon, width - 30, bottom, 0x80FFFFFF, 0xffffff);
|
||||
|
||||
super.drawContents(mouseX, mouseY, partialTick);
|
||||
|
||||
enableClipping(bottom);
|
||||
|
||||
float yPos = height * 0.75F;
|
||||
float xPos1 = width / 4;
|
||||
float xPos2 = width * 0.75F;
|
||||
float scale = height / 4;
|
||||
|
||||
renderPlayerModel(localPlayer, xPos1, yPos, scale, horizon - mouseY, mouseX, partialTick);
|
||||
renderPlayerModel(remotePlayer, xPos2, yPos, scale, horizon - mouseY, mouseX, partialTick);
|
||||
|
||||
disableClipping();
|
||||
|
||||
if (chooser.getStatus() != null && !uploader.canUpload()) {
|
||||
drawRect(40, height / 2 - 12, width / 2 - 40, height / 2 + 12, 0xB0000000);
|
||||
drawCenteredString(fontRenderer, format(chooser.getStatus()), (int) xPos1, height / 2 - 4, 0xffffff);
|
||||
}
|
||||
|
||||
if (uploader.downloadInProgress() || uploader.isThrottled() || uploader.isOffline()) {
|
||||
|
||||
int lineHeight = uploader.isThrottled() ? 18 : 12;
|
||||
|
||||
drawRect((int) (xPos2 - width / 4 + 40), height / 2 - lineHeight, width - 40, height / 2 + lineHeight, 0xB0000000);
|
||||
|
||||
if (uploader.isThrottled()) {
|
||||
drawCenteredString(fontRenderer, format(SkinUploader.ERR_MOJANG), (int) xPos2, height / 2 - 10, 0xff5555);
|
||||
drawCenteredString(fontRenderer, format(SkinUploader.ERR_WAIT, uploader.getRetries()), (int) xPos2, height / 2 + 2, 0xff5555);
|
||||
} else if (uploader.isOffline()) {
|
||||
drawCenteredString(fontRenderer, format(SkinUploader.ERR_OFFLINE), (int) xPos2, height / 2 - 4, 0xff5555);
|
||||
} else {
|
||||
drawCenteredString(fontRenderer, format(SkinUploader.STATUS_FETCH), (int) xPos2, height / 2 - 4, 0xffffff);
|
||||
}
|
||||
}
|
||||
|
||||
boolean uploadInProgress = uploader.uploadInProgress();
|
||||
boolean showError = uploader.hasStatus();
|
||||
|
||||
if (uploadInProgress || showError || msgFadeOpacity > 0) {
|
||||
if (!uploadInProgress && !showError) {
|
||||
msgFadeOpacity -= deltaTime / 10;
|
||||
} else if (msgFadeOpacity < 1) {
|
||||
msgFadeOpacity += deltaTime / 10;
|
||||
}
|
||||
|
||||
msgFadeOpacity = MathHelper.clamp(msgFadeOpacity, 0, 1);
|
||||
}
|
||||
|
||||
if (msgFadeOpacity > 0) {
|
||||
int opacity = (Math.min(180, (int) (msgFadeOpacity * 180)) & 255) << 24;
|
||||
|
||||
drawRect(0, 0, width, height, opacity);
|
||||
|
||||
String errorMsg = format(uploader.getStatusMessage());
|
||||
|
||||
if (uploadInProgress) {
|
||||
drawCenteredString(fontRenderer, errorMsg, width / 2, height / 2, 0xffffff);
|
||||
} else if (showError) {
|
||||
int blockHeight = (height - fontRenderer.getWordWrappedHeight(errorMsg, width - 10)) / 2;
|
||||
|
||||
drawCenteredString(fontRenderer, format("hdskins.failed"), width / 2, blockHeight - fontRenderer.FONT_HEIGHT * 2, 0xffff55);
|
||||
fontRenderer.drawSplitString(errorMsg, 5, blockHeight, width - 10, 0xff5555);
|
||||
}
|
||||
}
|
||||
|
||||
depthMask(true);
|
||||
enableDepth();
|
||||
}
|
||||
|
||||
private void renderPlayerModel(EntityPlayerModel thePlayer, float xPosition, float yPosition, float scale, float mouseY, float mouseX, float partialTick) {
|
||||
mc.getTextureManager().bindTexture(thePlayer.getLocal(Type.SKIN).getTexture());
|
||||
|
||||
enableColorMaterial();
|
||||
pushMatrix();
|
||||
translate(xPosition, yPosition, 300);
|
||||
|
||||
scale(scale, scale, scale);
|
||||
rotate(-15, 1, 0, 0);
|
||||
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
|
||||
float rot = ((updateCounter + partialTick) * 2.5F) % 360;
|
||||
|
||||
rotate(rot, 0, 1, 0);
|
||||
|
||||
float lookFactor = (float)Math.sin((rot * (Math.PI / 180)) + 45);
|
||||
float lookX = (float) Math.atan((xPosition - mouseX) / 20) * 30;
|
||||
|
||||
thePlayer.rotationYawHead = lookX * lookFactor;
|
||||
thePlayer.rotationPitch = (float) Math.atan(mouseY / 40) * -20;
|
||||
|
||||
mc.getRenderManager().renderEntity(thePlayer, 0, 0, 0, 0, 1, false);
|
||||
|
||||
popMatrix();
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
disableColorMaterial();
|
||||
}
|
||||
|
||||
/*
|
||||
* / |
|
||||
* 1/ |o Q = t + q
|
||||
* /q | x = xPosition - mouseX
|
||||
* *-----* sin(q) = o cos(q) = x tan(q) = o/x
|
||||
* --|--x------------------------------------
|
||||
* |
|
||||
* mouseX
|
||||
*/
|
||||
|
||||
private void enableClipping(int yBottom) {
|
||||
GL11.glPopAttrib();
|
||||
|
||||
if (doubleBuffer == null) {
|
||||
doubleBuffer = BufferUtils.createByteBuffer(32).asDoubleBuffer();
|
||||
}
|
||||
|
||||
doubleBuffer.clear();
|
||||
doubleBuffer.put(0).put(1).put(0).put(-30).flip();
|
||||
|
||||
GL11.glClipPlane(GL11.GL_CLIP_PLANE0, doubleBuffer);
|
||||
doubleBuffer.clear();
|
||||
doubleBuffer.put(0).put(-1).put(0).put(yBottom).flip();
|
||||
|
||||
GL11.glClipPlane(GL11.GL_CLIP_PLANE1, doubleBuffer);
|
||||
GL11.glEnable(GL11.GL_CLIP_PLANE0);
|
||||
GL11.glEnable(GL11.GL_CLIP_PLANE1);
|
||||
}
|
||||
|
||||
private void disableClipping() {
|
||||
GL11.glDisable(GL11.GL_CLIP_PLANE1);
|
||||
GL11.glDisable(GL11.GL_CLIP_PLANE0);
|
||||
|
||||
disableDepth();
|
||||
enableBlend();
|
||||
depthMask(false);
|
||||
}
|
||||
|
||||
private void punchServer(String uploadMsg) {
|
||||
uploader.uploadSkin(uploadMsg).handle(CallableFutures.callback(this::updateButtons));
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
private void updateButtons() {
|
||||
btnClear.enabled = uploader.canClear();
|
||||
btnUpload.enabled = uploader.canUpload() && uploader.supportsFeature(Feature.UPLOAD_USER_SKIN);
|
||||
btnDownload.enabled = uploader.canClear() && !chooser.pickingInProgress();
|
||||
btnBrowse.enabled = !chooser.pickingInProgress();
|
||||
|
||||
boolean types = !uploader.supportsFeature(Feature.MODEL_TYPES);
|
||||
boolean variants = !uploader.supportsFeature(Feature.MODEL_VARIANTS);
|
||||
|
||||
btnModeSkin.setLocked(types);
|
||||
btnModeElytra.setLocked(types);
|
||||
|
||||
btnModeSteve.setLocked(variants);
|
||||
btnModeAlex.setLocked(variants);
|
||||
|
||||
btnClear.setLocked(!uploader.supportsFeature(Feature.DELETE_USER_SKIN));
|
||||
btnUpload.setLocked(!uploader.supportsFeature(Feature.UPLOAD_USER_SKIN));
|
||||
btnDownload.setLocked(!uploader.supportsFeature(Feature.DOWNLOAD_USER_SKIN));
|
||||
}
|
||||
|
||||
protected class FeatureButton extends Button {
|
||||
private List<String> disabledTooltip = Splitter.onPattern("\r?\n|\\\\n").splitToList(format("hdskins.warning.disabled.description"));
|
||||
|
||||
protected boolean locked;
|
||||
|
||||
public FeatureButton(int x, int y, int width, int height, String label, IGuiAction<? extends Button> callback) {
|
||||
super(x, y, width, height, label, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTooltip() {
|
||||
if (locked) {
|
||||
return disabledTooltip;
|
||||
}
|
||||
return super.getTooltip();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Button setTooltip(String tooltip) {
|
||||
disabledTooltip = Splitter.onPattern("\r?\n|\\\\n").splitToList(
|
||||
format("hdskins.warning.disabled.title",
|
||||
format(tooltip),
|
||||
format("hdskins.warning.disabled.description")));
|
||||
return super.setTooltip(tooltip);
|
||||
}
|
||||
|
||||
public void setLocked(boolean lock) {
|
||||
locked = lock;
|
||||
enabled &= !lock;
|
||||
}
|
||||
}
|
||||
|
||||
protected class FeatureSwitch extends IconicButton {
|
||||
private List<String> disabledTooltip = null;
|
||||
|
||||
protected boolean locked;
|
||||
|
||||
public FeatureSwitch(int x, int y, IGuiAction<? extends IconicButton> callback) {
|
||||
super(x, y, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTooltip() {
|
||||
if (locked) {
|
||||
return disabledTooltip;
|
||||
}
|
||||
return super.getTooltip();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Button setTooltip(String tooltip) {
|
||||
disabledTooltip = Splitter.onPattern("\r?\n|\\\\n").splitToList(
|
||||
format("hdskins.warning.disabled.title",
|
||||
format(tooltip),
|
||||
format("hdskins.warning.disabled.description")));
|
||||
return super.setTooltip(tooltip);
|
||||
}
|
||||
|
||||
public void setLocked(boolean lock) {
|
||||
locked = lock;
|
||||
enabled &= !lock;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.gui;
|
||||
|
||||
import com.minelittlepony.gui.Checkbox;
|
||||
import com.minelittlepony.gui.SettingsPanel;
|
||||
import com.voxelmodpack.hdskins.LiteModHDSkins;
|
||||
import com.voxelmodpack.hdskins.upload.GLWindow;
|
||||
|
||||
public class HDSkinsConfigPanel extends SettingsPanel {
|
||||
@Override
|
||||
public void initGui() {
|
||||
final LiteModHDSkins mod = LiteModHDSkins.instance();
|
||||
|
||||
addButton(new Checkbox(40, 40, "hdskins.options.skindrops", mod.experimentalSkinDrop, checked -> {
|
||||
mod.experimentalSkinDrop = checked;
|
||||
|
||||
mod.writeConfig();
|
||||
|
||||
if (checked) {
|
||||
GLWindow.create();
|
||||
} else {
|
||||
GLWindow.dispose();
|
||||
}
|
||||
|
||||
return checked;
|
||||
})).setTooltip(formatMultiLine("hdskins.warning.experimental", 250));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTitle() {
|
||||
return "HD Skins Settings";
|
||||
}
|
||||
}
|
|
@ -1,219 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.gui;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.model.ModelBiped.ArmPose;
|
||||
import net.minecraft.client.model.ModelElytra;
|
||||
import net.minecraft.client.model.ModelPlayer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderLivingBase;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.client.renderer.entity.layers.LayerRenderer;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.item.EntityBoat;
|
||||
import net.minecraft.entity.player.EnumPlayerModelParts;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntityBed;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static net.minecraft.client.renderer.GlStateManager.*;
|
||||
|
||||
public class RenderPlayerModel<M extends EntityPlayerModel> extends RenderLivingBase<M> {
|
||||
|
||||
/**
|
||||
* The basic Elytra texture.
|
||||
*/
|
||||
protected final ResourceLocation TEXTURE_ELYTRA = new ResourceLocation("textures/entity/elytra.png");
|
||||
|
||||
private static final ModelPlayer FAT = new ModelPlayer(0, false);
|
||||
private static final ModelPlayer THIN = new ModelPlayer(0, true);
|
||||
|
||||
public RenderPlayerModel(RenderManager renderer) {
|
||||
super(renderer, FAT, 0);
|
||||
this.addLayer(this.getElytraLayer());
|
||||
}
|
||||
|
||||
protected LayerRenderer<EntityLivingBase> getElytraLayer() {
|
||||
final ModelElytra modelElytra = new ModelElytra();
|
||||
return new LayerRenderer<EntityLivingBase>() {
|
||||
@Override
|
||||
public void doRenderLayer(EntityLivingBase entityBase, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale) {
|
||||
EntityPlayerModel entity = (EntityPlayerModel) entityBase;
|
||||
ItemStack itemstack = entity.getItemStackFromSlot(EntityEquipmentSlot.CHEST);
|
||||
|
||||
if (itemstack.getItem() == Items.ELYTRA) {
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||
|
||||
bindTexture(entity.getLocal(Type.ELYTRA).getTexture());
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate(0, 0, 0.125F);
|
||||
|
||||
modelElytra.setRotationAngles(limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale, entity);
|
||||
modelElytra.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale);
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCombineTextures() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceLocation getEntityTexture(M entity) {
|
||||
return entity.getLocal(Type.SKIN).getTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canRenderName(M entity) {
|
||||
return Minecraft.getMinecraft().player != null && super.canRenderName(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean setBrightness(M entity, float partialTicks, boolean combineTextures) {
|
||||
return Minecraft.getMinecraft().world != null && super.setBrightness(entity, partialTicks, combineTextures);
|
||||
}
|
||||
|
||||
public ModelPlayer getEntityModel(M entity) {
|
||||
return entity.usesThinSkin() ? THIN : FAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRender(M entity, double x, double y, double z, float entityYaw, float partialTicks) {
|
||||
|
||||
if (entity.isPlayerSleeping()) {
|
||||
BedHead.instance.render(entity);
|
||||
}
|
||||
if (entity.isRiding()) {
|
||||
MrBoaty.instance.render();
|
||||
}
|
||||
|
||||
ModelPlayer player = getEntityModel(entity);
|
||||
mainModel = player;
|
||||
|
||||
Set<EnumPlayerModelParts> parts = Minecraft.getMinecraft().gameSettings.getModelParts();
|
||||
player.bipedHeadwear.isHidden = !parts.contains(EnumPlayerModelParts.HAT);
|
||||
player.bipedBodyWear.isHidden = !parts.contains(EnumPlayerModelParts.JACKET);
|
||||
player.bipedLeftLegwear.isHidden = !parts.contains(EnumPlayerModelParts.LEFT_PANTS_LEG);
|
||||
player.bipedRightLegwear.isHidden = !parts.contains(EnumPlayerModelParts.RIGHT_PANTS_LEG);
|
||||
player.bipedLeftArmwear.isHidden = !parts.contains(EnumPlayerModelParts.LEFT_SLEEVE);
|
||||
player.bipedRightArmwear.isHidden = !parts.contains(EnumPlayerModelParts.RIGHT_SLEEVE);
|
||||
player.isSneak = entity.isSneaking();
|
||||
|
||||
player.leftArmPose = ArmPose.EMPTY;
|
||||
player.rightArmPose = ArmPose.EMPTY;
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
|
||||
double offset = entity.getYOffset() + entity.posY;
|
||||
|
||||
|
||||
|
||||
if (entity.isPlayerSleeping()) {
|
||||
y--;
|
||||
z += 0.5F;
|
||||
} else if (player.isSneak) {
|
||||
y -= 0.125D;
|
||||
}
|
||||
|
||||
pushMatrix();
|
||||
enableBlend();
|
||||
color(1, 1, 1, 0.3F);
|
||||
translate(0, offset, 0);
|
||||
|
||||
if (entity.isPlayerSleeping()) {
|
||||
GlStateManager.rotate(-90, 1, 0, 0);
|
||||
}
|
||||
|
||||
super.doRender(entity, x, y, z, entityYaw, partialTicks);
|
||||
|
||||
color(1, 1, 1, 1);
|
||||
disableBlend();
|
||||
popMatrix();
|
||||
GL11.glPopAttrib();
|
||||
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
pushMatrix();
|
||||
scale(1, -1, 1);
|
||||
translate(0.001, offset, 0.001);
|
||||
|
||||
if (entity.isPlayerSleeping()) {
|
||||
GlStateManager.rotate(-90, 1, 0, 0);
|
||||
}
|
||||
|
||||
super.doRender(entity, x, y, z, entityYaw, partialTicks);
|
||||
popMatrix();
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
|
||||
static class BedHead extends TileEntityBed {
|
||||
public static BedHead instance = new BedHead(Blocks.BED.getDefaultState());
|
||||
|
||||
public int metadata;
|
||||
|
||||
public BedHead(IBlockState state) {
|
||||
state.getBlock().getMetaFromState(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public void render(Entity entity) {
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
pushMatrix();
|
||||
|
||||
scale(-1, -1, -1);
|
||||
|
||||
TileEntityRendererDispatcher dispatcher = TileEntityRendererDispatcher.instance;
|
||||
|
||||
dispatcher.prepare(entity.getEntityWorld(), Minecraft.getMinecraft().getTextureManager(), Minecraft.getMinecraft().getRenderManager().getFontRenderer(), entity, null, 0);
|
||||
dispatcher.getRenderer(this).render(BedHead.instance, -0.5F, 0, 0, 0, -1, 1);
|
||||
|
||||
popMatrix();
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
}
|
||||
|
||||
static class MrBoaty extends EntityBoat {
|
||||
public static MrBoaty instance = new MrBoaty();
|
||||
|
||||
public MrBoaty() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public void render() {
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
pushMatrix();
|
||||
|
||||
scale(-1, -1, -1);
|
||||
|
||||
Render<EntityBoat> render = Minecraft.getMinecraft().getRenderManager().getEntityRenderObject(this);
|
||||
|
||||
render.doRender(this, 0, 0, 0, 0, 0);
|
||||
|
||||
popMatrix();
|
||||
GL11.glPopAttrib();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package com.voxelmodpack.hdskins.gui;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -1,24 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.mixin;
|
||||
|
||||
import com.minelittlepony.gui.IconicButton;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(GuiMainMenu.class)
|
||||
public class MixinGuiMainMenu extends GuiScreen {
|
||||
|
||||
@Inject(method = "initGui()V", at = @At("RETURN"))
|
||||
private void onInit(CallbackInfo ci) {
|
||||
addButton(new IconicButton(width - 50, height - 50, sender -> {
|
||||
mc.displayGuiScreen(HDSkinManager.INSTANCE.createSkinsGui());
|
||||
}).setIcon(new ItemStack(Items.LEATHER_LEGGINGS), 0x3c5dcb));
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.mixin;
|
||||
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
import net.minecraft.client.renderer.IImageBuffer;
|
||||
import net.minecraft.client.renderer.ImageBufferDownload;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
@Mixin(ImageBufferDownload.class)
|
||||
public abstract class MixinImageBufferDownload implements IImageBuffer {
|
||||
|
||||
@Inject(
|
||||
method = "parseUserSkin(Ljava/awt/image/BufferedImage;)Ljava/awt/image/BufferedImage;",
|
||||
at = @At("RETURN"),
|
||||
cancellable = true)
|
||||
private void update(BufferedImage image, CallbackInfoReturnable<BufferedImage> ci) {
|
||||
// convert skins from mojang server
|
||||
BufferedImage image2 = ci.getReturnValue();
|
||||
boolean isLegacy = image.getHeight() == 32;
|
||||
if (isLegacy) {
|
||||
Graphics graphics = image2.getGraphics();
|
||||
HDSkinManager.INSTANCE.convertSkin(image2, graphics);
|
||||
graphics.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.voxelmodpack.hdskins.upload.GLWindow;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
|
||||
/**
|
||||
* Mixin required to close the window after the game detects a crash.
|
||||
*
|
||||
* DO NOT REMOVE
|
||||
*
|
||||
* That means you, Killjoy.
|
||||
*
|
||||
*/
|
||||
@Mixin(value = Minecraft.class, priority = 9000)
|
||||
public abstract class MixinMinecraft {
|
||||
//
|
||||
// Due to how JFrame works the only way to know for sure when the game has crashed
|
||||
// is to have it call us directly.
|
||||
//
|
||||
// ShutdownListener.onShutDown is unlikely to be called as it depends on the
|
||||
// Minecraft.running flag to be unset, which is unlikely to happen if the game crashes.
|
||||
//
|
||||
// Runtime.current().addShutdownHook won't be called as it waits for all
|
||||
// non-daemon threads to end, one of which is depending on the JFrame being
|
||||
// disposed to tell it when to end.
|
||||
//
|
||||
// If you're thinking 'hey, what about Minecraft.isCrashed?'
|
||||
// No, that's only set if the internal MinecraftServer crashes.
|
||||
// Otherwise the value is always false and threads spinning to check any such value
|
||||
// will only serve to hang up the VM.
|
||||
//
|
||||
// But senpai, what about a warden thread joined on the main? I'm sure as soon as
|
||||
// the main thread closes that would-
|
||||
//
|
||||
// Nope. It never runs.
|
||||
//
|
||||
// @forge
|
||||
// Because the minecraft forge team are stupid, they call displayCrashReport on startup
|
||||
// regardless of whether the game has crashed or not. Thus the window may flicker an additional
|
||||
// time as the native window is forced back to the front.
|
||||
// This is a minor issue as the window will simply reassert itself when it's next referenced
|
||||
// (i.e. The skins GUI uses it for file drops) so I have no intention of fixing this.
|
||||
//
|
||||
// This is their problem.
|
||||
//
|
||||
// Update 09/06/2018:
|
||||
// After inspecting the forge source this was found to be nothing but pure lies.
|
||||
// The only place they call it is from FMLClientHandler#haltGame.
|
||||
// There is still the possible case where another mod tries to call it,
|
||||
// but that would be the very definition of 'misbehaving'.
|
||||
//
|
||||
// Also note that the method unconditionally calls System.exit, so anyone
|
||||
// who does will be having a hard time.
|
||||
//
|
||||
// @killjoy
|
||||
// Don't be afraid to use a mixin when the situation calls for it.
|
||||
// There is no other way to do this.
|
||||
//
|
||||
// Do not remove.
|
||||
//
|
||||
// [!!!DO NOT REMOVE!!!]
|
||||
//
|
||||
// I'm serious, do not remove.
|
||||
// I don't care how much of a vendeta you have against mixins.
|
||||
//
|
||||
//public void displayCrashReport(CrashReport crashReportIn)
|
||||
@Inject(method = "displayCrashReport(Lnet/minecraft/crash/CrashReport;)V", at = @At("HEAD"))
|
||||
private void onGameCrash(CrashReport report, CallbackInfo info) {
|
||||
GLWindow.dispose();
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.mixin;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
import com.voxelmodpack.hdskins.ducks.INetworkPlayerInfo;
|
||||
import net.minecraft.client.network.NetworkPlayerInfo;
|
||||
import net.minecraft.client.resources.SkinManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Mixin(NetworkPlayerInfo.class)
|
||||
public abstract class MixinNetworkPlayerInfo implements INetworkPlayerInfo {
|
||||
|
||||
private Map<Type, ResourceLocation> customTextures = new HashMap<>();
|
||||
private Map<Type, MinecraftProfileTexture> customProfiles = new HashMap<>();
|
||||
|
||||
private Map<Type, MinecraftProfileTexture> vanillaProfiles = new HashMap<>();
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private GameProfile gameProfile;
|
||||
|
||||
@Shadow
|
||||
Map<Type, ResourceLocation> playerTextures;
|
||||
|
||||
@SuppressWarnings("InvalidMemberReference") // mc-dev bug?
|
||||
@Redirect(method = {"getLocationSkin", "getLocationCape", "getLocationElytra"},
|
||||
at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;", remap = false))
|
||||
// synthetic
|
||||
private Object getSkin(Map<Type, ResourceLocation> playerTextures, Object key) {
|
||||
return getSkin(playerTextures, (Type) key);
|
||||
}
|
||||
|
||||
// with generics
|
||||
private ResourceLocation getSkin(Map<Type, ResourceLocation> playerTextures, Type type) {
|
||||
if (this.customTextures.containsKey(type)) {
|
||||
return this.customTextures.get(type);
|
||||
}
|
||||
|
||||
return playerTextures.get(type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Redirect(method = "getSkinType",
|
||||
at = @At(value = "FIELD", target = "Lnet/minecraft/client/network/NetworkPlayerInfo;skinType:Ljava/lang/String;"))
|
||||
private String getTextureModel(NetworkPlayerInfo self) {
|
||||
String model = getModelFrom(customProfiles);
|
||||
if (model != null) {
|
||||
return model;
|
||||
}
|
||||
return getModelFrom(vanillaProfiles);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getModelFrom(Map<Type, MinecraftProfileTexture> texture) {
|
||||
if (texture.containsKey(Type.SKIN)) {
|
||||
String model = texture.get(Type.SKIN).getMetadata("model");
|
||||
|
||||
return model != null ? model : "default";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Inject(method = "loadPlayerTextures",
|
||||
at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/resources/SkinManager;loadProfileTextures("
|
||||
+ "Lcom/mojang/authlib/GameProfile;"
|
||||
+ "Lnet/minecraft/client/resources/SkinManager$SkinAvailableCallback;"
|
||||
+ "Z)V",
|
||||
shift = At.Shift.BEFORE))
|
||||
private void onLoadTexture(CallbackInfo ci) {
|
||||
HDSkinManager.INSTANCE.fetchAndLoadSkins(gameProfile, (type, location, profileTexture) -> {
|
||||
customTextures.put(type, location);
|
||||
customProfiles.put(type, profileTexture);
|
||||
});
|
||||
}
|
||||
|
||||
@Redirect(method = "loadPlayerTextures",
|
||||
at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/resources/SkinManager;loadProfileTextures("
|
||||
+ "Lcom/mojang/authlib/GameProfile;"
|
||||
+ "Lnet/minecraft/client/resources/SkinManager$SkinAvailableCallback;"
|
||||
+ "Z)V"))
|
||||
private void redirectLoadPlayerTextures(SkinManager skinManager, GameProfile profile, SkinManager.SkinAvailableCallback callback, boolean requireSecure) {
|
||||
skinManager.loadProfileTextures(profile, (typeIn, location, profileTexture) -> {
|
||||
HDSkinManager.INSTANCE.parseSkin(profile, typeIn, location, profileTexture).thenAccept(v -> {
|
||||
playerTextures.put(typeIn, location);
|
||||
vanillaProfiles.put(typeIn, profileTexture);
|
||||
});
|
||||
}, requireSecure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadTextures() {
|
||||
synchronized (this) {
|
||||
for (Map.Entry<Type, MinecraftProfileTexture> entry : customProfiles.entrySet()) {
|
||||
HDSkinManager.INSTANCE.parseSkin(gameProfile, entry.getKey(), customTextures.get(entry.getKey()), entry.getValue());
|
||||
}
|
||||
for (Map.Entry<Type, MinecraftProfileTexture> entry : vanillaProfiles.entrySet()) {
|
||||
HDSkinManager.INSTANCE.parseSkin(gameProfile, entry.getKey(), playerTextures.get(entry.getKey()), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.mixin;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySkullRenderer;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraft.tileentity.TileEntitySkull;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Mixin(TileEntitySkullRenderer.class)
|
||||
public abstract class MixinSkullRenderer extends TileEntitySpecialRenderer<TileEntitySkull> {
|
||||
|
||||
@Redirect(method = "renderSkull",
|
||||
at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/renderer/tileentity/TileEntitySkullRenderer;bindTexture(Lnet/minecraft/util/ResourceLocation;)V",
|
||||
ordinal = 4))
|
||||
private void onBindTexture(TileEntitySkullRenderer tesr, ResourceLocation rl, float x, float y, float z, EnumFacing facing, float rotation, int meta, @Nullable GameProfile profile, int p_180543_8_, float ticks) {
|
||||
if (profile != null) {
|
||||
ResourceLocation skin = HDSkinManager.INSTANCE.getTextures(profile).get(Type.SKIN);
|
||||
|
||||
if (skin != null) {
|
||||
rl = skin;
|
||||
}
|
||||
}
|
||||
|
||||
bindTexture(rl);
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package com.voxelmodpack.hdskins.mixin;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -1,7 +0,0 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package com.voxelmodpack.hdskins;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -1,42 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources;
|
||||
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListenableFutureTask;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class AsyncCacheLoader<K, V> extends CacheLoader<K, V> {
|
||||
|
||||
public static <K, V> AsyncCacheLoader<K, V> create(CacheLoader<K, V> loader, V placeholder, Executor executor) {
|
||||
return new AsyncCacheLoader<>(loader, placeholder, executor);
|
||||
}
|
||||
|
||||
private final CacheLoader<K, V> loader;
|
||||
private final V placeholder;
|
||||
private final Executor executor;
|
||||
|
||||
private AsyncCacheLoader(CacheLoader<K, V> loader, V placeholder, Executor executor) {
|
||||
this.executor = executor;
|
||||
this.placeholder = placeholder;
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V load(K key) {
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<V> reload(final K key, final V oldValue) {
|
||||
ListenableFutureTask<V> task = ListenableFutureTask.create(() -> loader.reload(key, oldValue).get());
|
||||
executor.execute(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
|
||||
return loader.loadAll(keys);
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources;
|
||||
|
||||
import com.voxelmodpack.hdskins.resources.texture.DynamicTextureImage;
|
||||
import com.voxelmodpack.hdskins.resources.texture.ImageBufferDownloadHD;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ImageLoader implements Supplier<ResourceLocation> {
|
||||
|
||||
private static Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
private final ResourceLocation original;
|
||||
|
||||
public ImageLoader(ResourceLocation loc) {
|
||||
this.original = loc;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ResourceLocation get() {
|
||||
BufferedImage image = getImage(original);
|
||||
final BufferedImage updated = new ImageBufferDownloadHD().parseUserSkin(image);
|
||||
if (updated == null) {
|
||||
return null;
|
||||
}
|
||||
if (updated == image) {
|
||||
// don't load a new image
|
||||
return this.original;
|
||||
}
|
||||
return addTaskAndGet(() -> loadSkin(updated));
|
||||
}
|
||||
|
||||
private static <V> V addTaskAndGet(Callable<V> callable) {
|
||||
try {
|
||||
return mc.addScheduledTask(callable).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static BufferedImage getImage(ResourceLocation res) {
|
||||
|
||||
try (InputStream in = mc.getResourceManager().getResource(res).getInputStream()) {
|
||||
return TextureUtil.readBufferedImage(in);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ResourceLocation loadSkin(BufferedImage image) {
|
||||
|
||||
ResourceLocation conv = new ResourceLocation(original.getNamespace() + "-converted", original.getPath());
|
||||
boolean success = mc.getTextureManager().loadTexture(conv, new DynamicTextureImage(image));
|
||||
return success ? conv : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.voxelmodpack.hdskins.resources.texture.DynamicTextureImage;
|
||||
import com.voxelmodpack.hdskins.resources.texture.ImageBufferDownloadHD;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.resources.SkinManager.SkinAvailableCallback;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public class LocalTexture {
|
||||
|
||||
private final TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
|
||||
|
||||
private DynamicTexture local;
|
||||
private PreviewTexture remote;
|
||||
|
||||
private ResourceLocation remoteResource;
|
||||
private ResourceLocation localResource;
|
||||
|
||||
private final IBlankSkinSupplier blank;
|
||||
|
||||
private final Type type;
|
||||
|
||||
private boolean remoteLoaded = false;
|
||||
|
||||
public LocalTexture(GameProfile profile, Type type, IBlankSkinSupplier blank) {
|
||||
this.blank = blank;
|
||||
this.type = type;
|
||||
|
||||
String file = String.format("%s/preview_%s.png", type.name().toLowerCase(), profile.getName());
|
||||
|
||||
remoteResource = new ResourceLocation(file);
|
||||
textureManager.deleteTexture(remoteResource);
|
||||
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
public ResourceLocation getTexture() {
|
||||
if (hasRemote()) {
|
||||
return remoteResource;
|
||||
}
|
||||
|
||||
return localResource;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
localResource = blank.getBlankSkin(type);
|
||||
}
|
||||
|
||||
public boolean hasRemote() {
|
||||
return remote != null;
|
||||
}
|
||||
|
||||
public boolean hasLocal() {
|
||||
return local != null;
|
||||
}
|
||||
|
||||
public boolean hasRemoteTexture() {
|
||||
return uploadComplete() && remoteLoaded;
|
||||
}
|
||||
|
||||
public boolean usingLocal() {
|
||||
return !hasRemote() && hasLocal();
|
||||
}
|
||||
|
||||
public boolean uploadComplete() {
|
||||
return hasRemote() && remote.isTextureUploaded();
|
||||
}
|
||||
|
||||
public PreviewTexture getRemote() {
|
||||
return remote;
|
||||
}
|
||||
|
||||
public void setRemote(PreviewTextureManager ptm, SkinAvailableCallback callback) {
|
||||
clearRemote();
|
||||
|
||||
remote = ptm.getPreviewTexture(remoteResource, type, blank.getBlankSkin(type), (type, location, profileTexture) -> {
|
||||
if (callback != null) {
|
||||
callback.skinAvailable(type, location, profileTexture);
|
||||
}
|
||||
remoteLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
public void setLocal(File file) {
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearLocal();
|
||||
|
||||
try {
|
||||
BufferedImage image = ImageIO.read(file);
|
||||
BufferedImage bufferedImage = new ImageBufferDownloadHD().parseUserSkin(image);
|
||||
|
||||
local = new DynamicTextureImage(bufferedImage);
|
||||
localResource = textureManager.getDynamicTextureLocation("localSkinPreview", local);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearRemote() {
|
||||
remoteLoaded = false;
|
||||
if (hasRemote()) {
|
||||
remote = null;
|
||||
textureManager.deleteTexture(remoteResource);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearLocal() {
|
||||
if (hasLocal()) {
|
||||
local = null;
|
||||
textureManager.deleteTexture(localResource);
|
||||
localResource = blank.getBlankSkin(type);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IBlankSkinSupplier {
|
||||
|
||||
ResourceLocation getBlankSkin(Type type);
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources;
|
||||
|
||||
import net.minecraft.client.renderer.IImageBuffer;
|
||||
import net.minecraft.client.renderer.ThreadDownloadImageData;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import com.voxelmodpack.hdskins.VanillaModels;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PreviewTexture extends ThreadDownloadImageData {
|
||||
|
||||
private boolean uploaded;
|
||||
|
||||
private String model;
|
||||
|
||||
private String fileUrl;
|
||||
|
||||
public PreviewTexture(@Nullable String model, String url, ResourceLocation fallbackTexture, @Nullable IImageBuffer imageBuffer) {
|
||||
super(null, url, fallbackTexture, imageBuffer);
|
||||
|
||||
this.model = VanillaModels.nonNull(model);
|
||||
this.fileUrl = url;
|
||||
}
|
||||
|
||||
public boolean isTextureUploaded() {
|
||||
return uploaded && this.getGlTextureId() > -1;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return fileUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteGlTexture() {
|
||||
super.deleteGlTexture();
|
||||
this.uploaded = true;
|
||||
}
|
||||
|
||||
public boolean hasModel() {
|
||||
return model != null;
|
||||
}
|
||||
|
||||
public boolean usesThinArms() {
|
||||
return VanillaModels.isSlim(model);
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||
import com.voxelmodpack.hdskins.resources.texture.ISkinAvailableCallback;
|
||||
import com.voxelmodpack.hdskins.resources.texture.ImageBufferDownloadHD;
|
||||
|
||||
import net.minecraft.client.resources.SkinManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Manager for fetching preview textures. This ensures that multiple calls
|
||||
* to the skin server aren't done when fetching preview textures.
|
||||
*/
|
||||
public class PreviewTextureManager {
|
||||
|
||||
private final Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> textures;
|
||||
|
||||
public PreviewTextureManager(MinecraftTexturesPayload payload) {
|
||||
this.textures = payload.getTextures();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PreviewTexture getPreviewTexture(ResourceLocation location, MinecraftProfileTexture.Type type, ResourceLocation def, @Nullable SkinManager.SkinAvailableCallback callback) {
|
||||
if (!textures.containsKey(type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MinecraftProfileTexture texture = textures.get(type);
|
||||
ISkinAvailableCallback buff = new ImageBufferDownloadHD(type, () -> {
|
||||
if (callback != null) {
|
||||
callback.skinAvailable(type, location, new MinecraftProfileTexture(texture.getUrl(), Maps.newHashMap()));
|
||||
}
|
||||
});
|
||||
|
||||
PreviewTexture skinTexture = new PreviewTexture(texture.getMetadata("model"), texture.getUrl(), def, buff);
|
||||
|
||||
TextureLoader.loadTexture(location, skinTexture);
|
||||
|
||||
return skinTexture;
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
class SkinData {
|
||||
|
||||
List<Skin> skins;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
class Skin {
|
||||
|
||||
String name;
|
||||
UUID uuid;
|
||||
String skin;
|
||||
|
||||
public ResourceLocation getTexture() {
|
||||
return new ResourceLocation("hdskins", String.format("textures/skins/%s.png", skin));
|
||||
}
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class SkinResourceManager implements IResourceManagerReloadListener {
|
||||
|
||||
private ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
private Map<UUID, Skin> uuidSkins = Maps.newHashMap();
|
||||
private Map<String, Skin> namedSkins = Maps.newHashMap();
|
||||
private Map<ResourceLocation, Future<ResourceLocation>> inProgress = Maps.newHashMap();
|
||||
private Map<ResourceLocation, ResourceLocation> converted = Maps.newHashMap();
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager) {
|
||||
uuidSkins.clear();
|
||||
namedSkins.clear();
|
||||
executor.shutdownNow();
|
||||
executor = Executors.newSingleThreadExecutor();
|
||||
inProgress.clear();
|
||||
converted.clear();
|
||||
for (String domain : resourceManager.getResourceDomains()) {
|
||||
try {
|
||||
for (IResource res : resourceManager.getAllResources(new ResourceLocation(domain, "textures/skins/skins.json"))) {
|
||||
try {
|
||||
SkinData data = getSkinData(res.getInputStream());
|
||||
for (Skin s : data.skins) {
|
||||
if (s.uuid != null) {
|
||||
uuidSkins.put(s.uuid, s);
|
||||
}
|
||||
if (s.name != null) {
|
||||
namedSkins.put(s.name, s);
|
||||
}
|
||||
}
|
||||
} catch (JsonParseException je) {
|
||||
LiteLoaderLogger.warning(je, "Invalid skins.json in %s", res.getResourcePackName());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private SkinData getSkinData(InputStream stream) {
|
||||
try {
|
||||
return new Gson().fromJson(new InputStreamReader(stream), SkinData.class);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation getPlayerTexture(GameProfile profile, Type type) {
|
||||
if (type != Type.SKIN)
|
||||
// not supported
|
||||
return null;
|
||||
|
||||
Skin skin = getSkin(profile);
|
||||
if (skin != null) {
|
||||
final ResourceLocation res = skin.getTexture();
|
||||
return getConvertedResource(res);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert older resources to a newer format.
|
||||
*
|
||||
* @param res The skin resource to convert
|
||||
* @return The converted resource
|
||||
*/
|
||||
@Nullable
|
||||
public ResourceLocation getConvertedResource(@Nullable ResourceLocation res) {
|
||||
loadSkinResource(res);
|
||||
return converted.get(res);
|
||||
}
|
||||
|
||||
private void loadSkinResource(@Nullable final ResourceLocation res) {
|
||||
if (res != null) {
|
||||
// read and convert in a new thread
|
||||
this.inProgress.computeIfAbsent(res, r -> CompletableFuture.supplyAsync(new ImageLoader(r), executor)
|
||||
.whenComplete((loc, t) -> {
|
||||
if (loc != null)
|
||||
converted.put(res, loc);
|
||||
else {
|
||||
LogManager.getLogger().warn("Errored while processing {}. Using original.", res, t);
|
||||
converted.put(res, res);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Skin getSkin(GameProfile profile) {
|
||||
Skin skin = this.uuidSkins.get(profile.getId());
|
||||
if (skin == null) {
|
||||
skin = this.namedSkins.get(profile.getName());
|
||||
}
|
||||
return skin;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.ITextureObject;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class TextureLoader {
|
||||
|
||||
private static Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
public static void loadTexture(final ResourceLocation textureLocation, final ITextureObject textureObj) {
|
||||
mc.addScheduledTask((Runnable) () -> mc.getTextureManager().loadTexture(textureLocation, textureObj));
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package com.voxelmodpack.hdskins.resources;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -1,27 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources.texture;
|
||||
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class DynamicTextureImage extends DynamicTexture implements IBufferedTexture {
|
||||
|
||||
private BufferedImage image;
|
||||
|
||||
public DynamicTextureImage(BufferedImage bufferedImage) {
|
||||
super(bufferedImage);
|
||||
this.image = bufferedImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getBufferedImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteGlTexture() {
|
||||
super.deleteGlTexture();
|
||||
this.image = null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources.texture;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface IBufferedTexture {
|
||||
|
||||
@Nullable
|
||||
BufferedImage getBufferedImage();
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources.texture;
|
||||
|
||||
import net.minecraft.client.renderer.IImageBuffer;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ISkinAvailableCallback extends IImageBuffer {
|
||||
@Override
|
||||
default BufferedImage parseUserSkin(BufferedImage image) {
|
||||
return image;
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources.texture;
|
||||
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class ImageBufferDownloadHD implements ISkinAvailableCallback {
|
||||
|
||||
private int scale;
|
||||
private Graphics graphics;
|
||||
private BufferedImage image;
|
||||
|
||||
private ISkinAvailableCallback callback = null;
|
||||
|
||||
private Type skinType = Type.SKIN;
|
||||
|
||||
public ImageBufferDownloadHD() {
|
||||
|
||||
}
|
||||
|
||||
public ImageBufferDownloadHD(Type type, ISkinAvailableCallback callback) {
|
||||
this.callback = callback;
|
||||
this.skinType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@SuppressWarnings({"SuspiciousNameCombination", "NullableProblems"})
|
||||
public BufferedImage parseUserSkin(@Nullable BufferedImage downloadedImage) {
|
||||
// TODO: Do we want to convert other skin types?
|
||||
if (downloadedImage == null || skinType != Type.SKIN) {
|
||||
return downloadedImage;
|
||||
}
|
||||
|
||||
int imageWidth = downloadedImage.getWidth();
|
||||
int imageHeight = downloadedImage.getHeight();
|
||||
if (imageHeight == imageWidth) {
|
||||
return downloadedImage;
|
||||
}
|
||||
scale = imageWidth / 64;
|
||||
image = new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_ARGB);
|
||||
graphics = image.getGraphics();
|
||||
graphics.drawImage(downloadedImage, 0, 0, null);
|
||||
|
||||
// copy layers
|
||||
// leg
|
||||
drawImage(24, 48, 20, 52, 4, 16, 8, 20); // top
|
||||
drawImage(28, 48, 24, 52, 8, 16, 12, 20); // bottom
|
||||
drawImage(20, 52, 16, 64, 8, 20, 12, 32); // inside
|
||||
drawImage(24, 52, 20, 64, 4, 20, 8, 32); // front
|
||||
drawImage(28, 52, 24, 64, 0, 20, 4, 32); // outside
|
||||
drawImage(32, 52, 28, 64, 12, 20, 16, 32); // back
|
||||
// arm
|
||||
drawImage(40, 48, 36, 52, 44, 16, 48, 20); // top
|
||||
drawImage(44, 48, 40, 52, 48, 16, 52, 20); // bottom
|
||||
drawImage(36, 52, 32, 64, 48, 20, 52, 32);
|
||||
drawImage(40, 52, 36, 64, 44, 20, 48, 32);
|
||||
drawImage(44, 52, 40, 64, 40, 20, 44, 32);
|
||||
drawImage(48, 52, 44, 64, 52, 20, 56, 32);
|
||||
|
||||
// mod things
|
||||
HDSkinManager.INSTANCE.convertSkin(image, graphics);
|
||||
|
||||
graphics.dispose();
|
||||
|
||||
if (callback != null) {
|
||||
return callback.parseUserSkin(image);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
private void drawImage(int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2) {
|
||||
graphics.drawImage(image,
|
||||
dx1 * scale, dy1 * scale, dx2 * scale, dy2 * scale,
|
||||
sx1 * scale, sy1 * scale, sx2 * scale, sy2 * scale,
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skinAvailable() {
|
||||
if (callback != null) {
|
||||
callback.skinAvailable();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,222 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.resources.texture;
|
||||
|
||||
import com.voxelmodpack.hdskins.util.MoreHttpResponses;
|
||||
import net.minecraft.client.renderer.IImageBuffer;
|
||||
import net.minecraft.client.renderer.texture.SimpleTexture;
|
||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpHead;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Do not use. This will be removed in a later update.
|
||||
* Now that legacy includes the etag in the hash, it is no longer required to save it to disk.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ThreadDownloadImageETag extends SimpleTexture implements IBufferedTexture {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final AtomicInteger THREAD_ID = new AtomicInteger(0);
|
||||
private static CloseableHttpClient client = HttpClients.createSystem();
|
||||
|
||||
@Nonnull
|
||||
private final Path cacheFile;
|
||||
private final Path eTagFile;
|
||||
private final String imageUrl;
|
||||
@Nullable
|
||||
private final IImageBuffer imageBuffer;
|
||||
|
||||
@Nullable
|
||||
private BufferedImage bufferedImage;
|
||||
@Nullable
|
||||
private Thread imageThread;
|
||||
private boolean textureUploaded;
|
||||
|
||||
public ThreadDownloadImageETag(@Nonnull File cacheFileIn, String imageUrlIn, ResourceLocation defLocation, @Nullable IImageBuffer imageBufferIn) {
|
||||
super(defLocation);
|
||||
this.cacheFile = cacheFileIn.toPath();
|
||||
this.eTagFile = cacheFile.resolveSibling(cacheFile.getFileName() + ".etag");
|
||||
this.imageUrl = imageUrlIn;
|
||||
this.imageBuffer = imageBufferIn;
|
||||
}
|
||||
|
||||
private void checkTextureUploaded() {
|
||||
if (!this.textureUploaded) {
|
||||
if (this.bufferedImage != null) {
|
||||
if (this.textureLocation != null) {
|
||||
this.deleteGlTexture();
|
||||
}
|
||||
|
||||
TextureUtil.uploadTextureImage(super.getGlTextureId(), this.bufferedImage);
|
||||
this.textureUploaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGlTextureId() {
|
||||
this.checkTextureUploaded();
|
||||
return super.getGlTextureId();
|
||||
}
|
||||
|
||||
private void setBufferedImage(@Nonnull BufferedImage bufferedImageIn) {
|
||||
this.bufferedImage = bufferedImageIn;
|
||||
|
||||
if (this.imageBuffer != null) {
|
||||
this.imageBuffer.skinAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BufferedImage getBufferedImage() {
|
||||
return bufferedImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadTexture(IResourceManager resourceManager) throws IOException {
|
||||
if (this.bufferedImage == null && this.textureLocation != null) {
|
||||
super.loadTexture(resourceManager);
|
||||
}
|
||||
|
||||
if (this.imageThread == null) {
|
||||
this.imageThread = new Thread(this::loadTexture, "Texture Downloader #" + THREAD_ID.incrementAndGet());
|
||||
this.imageThread.setDaemon(true);
|
||||
this.imageThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadTexture() {
|
||||
switch (checkLocalCache()) {
|
||||
case GONE:
|
||||
clearCache();
|
||||
break;
|
||||
case OK:
|
||||
case NOPE:
|
||||
LOGGER.debug("Loading http texture from local cache ({})", cacheFile);
|
||||
try {
|
||||
// e-tag check passed. Load the local file
|
||||
setLocalCache();
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
// Nope. Local cache is corrupt. Re-download it.
|
||||
// fallthrough to load from network
|
||||
LOGGER.error("Couldn't load skin {}", cacheFile, e);
|
||||
}
|
||||
case OUTDATED:
|
||||
loadTextureFromServer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setLocalCache() throws IOException {
|
||||
if (Files.isRegularFile(cacheFile)) {
|
||||
try (InputStream in = Files.newInputStream(cacheFile)) {
|
||||
BufferedImage image = ImageIO.read(in);
|
||||
if (imageBuffer != null) {
|
||||
image = imageBuffer.parseUserSkin(image);
|
||||
}
|
||||
setBufferedImage(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCache() {
|
||||
try {
|
||||
Files.deleteIfExists(this.cacheFile);
|
||||
Files.deleteIfExists(this.eTagFile);
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private enum State {
|
||||
OUTDATED,
|
||||
GONE,
|
||||
NOPE,
|
||||
OK
|
||||
}
|
||||
|
||||
private State checkLocalCache() {
|
||||
try (CloseableHttpResponse response = client.execute(new HttpHead(imageUrl))) {
|
||||
int code = response.getStatusLine().getStatusCode();
|
||||
if (code == HttpStatus.SC_NOT_FOUND) {
|
||||
return State.GONE;
|
||||
}
|
||||
if (code != HttpStatus.SC_OK) {
|
||||
return State.NOPE;
|
||||
}
|
||||
return checkETag(response) ? State.OK : State.OUTDATED;
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Couldn't load skin {} ", imageUrl, e);
|
||||
return State.NOPE;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkETag(HttpResponse response) {
|
||||
try {
|
||||
if (Files.isRegularFile(cacheFile)) {
|
||||
String localETag = Files.lines(eTagFile).limit(1).findFirst().orElse("");
|
||||
Header remoteETag = response.getFirstHeader(HttpHeaders.ETAG);
|
||||
// true if no remote etag or does match
|
||||
return remoteETag == null || localETag.equals(remoteETag.getValue());
|
||||
}
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
// it failed, so re-fetch.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadTextureFromServer() {
|
||||
LOGGER.debug("Downloading http texture from {} to {}", imageUrl, cacheFile);
|
||||
try (MoreHttpResponses resp = MoreHttpResponses.execute(client, new HttpGet(imageUrl))) {
|
||||
if (resp.ok()) {
|
||||
// write the image to disk
|
||||
Files.createDirectories(cacheFile.getParent());
|
||||
Files.copy(resp.getInputStream(), cacheFile);
|
||||
|
||||
try (InputStream in = Files.newInputStream(cacheFile)) {
|
||||
BufferedImage bufferedimage = ImageIO.read(in);
|
||||
|
||||
// maybe write the etag to disk
|
||||
Header eTag = resp.getResponse().getFirstHeader(HttpHeaders.ETAG);
|
||||
if (eTag != null) {
|
||||
Files.write(eTagFile, Collections.singleton(eTag.getValue()));
|
||||
}
|
||||
|
||||
if (imageBuffer != null) {
|
||||
bufferedimage = imageBuffer.parseUserSkin(bufferedimage);
|
||||
}
|
||||
setBufferedImage(bufferedimage);
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
LOGGER.error("Couldn\'t download http texture", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.server;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||
import com.mojang.util.UUIDTypeAdapter;
|
||||
import com.voxelmodpack.hdskins.gui.Feature;
|
||||
import com.voxelmodpack.hdskins.util.IndentedToStringStyle;
|
||||
import com.voxelmodpack.hdskins.util.MoreHttpResponses;
|
||||
import com.voxelmodpack.hdskins.util.NetClient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
@ServerType("bethlehem")
|
||||
public class BethlehemSkinServer implements SkinServer {
|
||||
|
||||
private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";
|
||||
|
||||
@Expose
|
||||
private final String address;
|
||||
|
||||
private BethlehemSkinServer(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException {
|
||||
try (MoreHttpResponses response = new NetClient("GET", getPath(profile)).send()) {
|
||||
if (!response.ok()) {
|
||||
throw new HttpException(response.getResponse());
|
||||
}
|
||||
|
||||
return response.json(MinecraftTexturesPayload.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkinUploadResponse performSkinUpload(SkinUpload upload) throws IOException, AuthenticationException {
|
||||
SkinServer.verifyServerConnection(upload.getSession(), SERVER_ID);
|
||||
|
||||
NetClient client = new NetClient("POST", address);
|
||||
|
||||
client.putHeaders(createHeaders(upload));
|
||||
|
||||
if (upload.getImage() != null) {
|
||||
client.putFile(upload.getType().toString().toLowerCase(Locale.US), "image/png", upload.getImage());
|
||||
}
|
||||
|
||||
try (MoreHttpResponses response = client.send()) {
|
||||
if (!response.ok()) {
|
||||
throw new HttpException(response.getResponse());
|
||||
}
|
||||
|
||||
return new SkinUploadResponse(response.text());
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, ?> createHeaders(SkinUpload upload) {
|
||||
Builder<String, Object> builder = ImmutableMap.<String, Object>builder()
|
||||
.put("accessToken", upload.getSession().getToken())
|
||||
.put("user", upload.getSession().getUsername())
|
||||
.put("uuid", UUIDTypeAdapter.fromUUID(upload.getSession().getProfile().getId()))
|
||||
.put("type", upload.getType().toString().toLowerCase(Locale.US));
|
||||
|
||||
if (upload.getImage() == null) {
|
||||
builder.put("clear", "1");
|
||||
} else {
|
||||
builder.put("model", upload.getMetadata().getOrDefault("model", "default"));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private String getPath(GameProfile profile) {
|
||||
return String.format("%s/profile/%s", address, UUIDTypeAdapter.fromUUID(profile.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new IndentedToStringStyle.Builder(this)
|
||||
.append("address", address)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFeature(Feature feature) {
|
||||
switch (feature) {
|
||||
case DOWNLOAD_USER_SKIN:
|
||||
case UPLOAD_USER_SKIN:
|
||||
case MODEL_VARIANTS:
|
||||
case MODEL_TYPES:
|
||||
case LINK_PROFILE:
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.server;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.StatusLine;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class HttpException extends IOException {
|
||||
private static final long serialVersionUID = -6168434367054139332L;
|
||||
|
||||
private final String reason;
|
||||
|
||||
private final int statusCode;
|
||||
|
||||
public HttpException(HttpResponse response) {
|
||||
this(response.getStatusLine());
|
||||
}
|
||||
|
||||
public HttpException(StatusLine status) {
|
||||
this(status.getReasonPhrase(), status.getStatusCode(), null);
|
||||
}
|
||||
|
||||
public HttpException(String reason, int statusCode, Throwable cause) {
|
||||
super("(" + statusCode + ") " + reason, cause);
|
||||
|
||||
this.reason = reason;
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public String getReasonPhrase() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.server;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||
import com.mojang.util.UUIDTypeAdapter;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
import com.voxelmodpack.hdskins.gui.Feature;
|
||||
import com.voxelmodpack.hdskins.util.CallableFutures;
|
||||
import com.voxelmodpack.hdskins.util.IndentedToStringStyle;
|
||||
import com.voxelmodpack.hdskins.util.MoreHttpResponses;
|
||||
import com.voxelmodpack.hdskins.util.NetClient;
|
||||
import com.voxelmodpack.hdskins.util.TexturesPayloadBuilder;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.client.methods.HttpHead;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ServerType("legacy")
|
||||
public class LegacySkinServer implements SkinServer {
|
||||
|
||||
private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";
|
||||
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
@Expose
|
||||
private final String address;
|
||||
|
||||
@Expose
|
||||
private final String gateway;
|
||||
|
||||
public LegacySkinServer(String address, @Nullable String gateway) {
|
||||
this.address = address;
|
||||
this.gateway = gateway;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<MinecraftTexturesPayload> getPreviewTextures(GameProfile profile) {
|
||||
return CallableFutures.asyncFailableFuture(() -> {
|
||||
SkinServer.verifyServerConnection(Minecraft.getMinecraft().getSession(), SERVER_ID);
|
||||
|
||||
if (Strings.isNullOrEmpty(gateway)) {
|
||||
throw gatewayUnsupported();
|
||||
}
|
||||
|
||||
Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map = new EnumMap<>(MinecraftProfileTexture.Type.class);
|
||||
for (MinecraftProfileTexture.Type type : MinecraftProfileTexture.Type.values()) {
|
||||
map.put(type, new MinecraftProfileTexture(getPath(gateway, type, profile), null));
|
||||
}
|
||||
|
||||
return TexturesPayloadBuilder.createTexturesPayload(profile, map);
|
||||
}, HDSkinManager.skinDownloadExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException {
|
||||
ImmutableMap.Builder<MinecraftProfileTexture.Type, MinecraftProfileTexture> builder = ImmutableMap.builder();
|
||||
for (MinecraftProfileTexture.Type type : MinecraftProfileTexture.Type.values()) {
|
||||
|
||||
String url = getPath(address, type, profile);
|
||||
try {
|
||||
builder.put(type, loadProfileTexture(profile, url));
|
||||
} catch (IOException e) {
|
||||
logger.trace("Couldn't find texture for {} at {}. Does it exist?", profile.getName(), url, e);
|
||||
}
|
||||
}
|
||||
|
||||
Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map = builder.build();
|
||||
if (map.isEmpty()) {
|
||||
throw new HttpException(String.format("No textures found for %s at %s", profile, this.address), 404, null);
|
||||
}
|
||||
return TexturesPayloadBuilder.createTexturesPayload(profile, map);
|
||||
}
|
||||
|
||||
private MinecraftProfileTexture loadProfileTexture(GameProfile profile, String url) throws IOException {
|
||||
try (MoreHttpResponses resp = MoreHttpResponses.execute(HDSkinManager.httpClient, new HttpHead(url))) {
|
||||
if (!resp.ok()) {
|
||||
throw new HttpException(resp.getResponse());
|
||||
}
|
||||
logger.debug("Found skin for {} at {}", profile.getName(), url);
|
||||
|
||||
Header eTagHeader = resp.getResponse().getFirstHeader(HttpHeaders.ETAG);
|
||||
final String eTag = eTagHeader == null ? "" : StringUtils.strip(eTagHeader.getValue(), "\"");
|
||||
|
||||
// Add the ETag onto the end of the texture hash. Should properly cache the textures.
|
||||
return new MinecraftProfileTexture(url, null) {
|
||||
@Override
|
||||
public String getHash() {
|
||||
return super.getHash() + eTag;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkinUploadResponse performSkinUpload(SkinUpload upload) throws IOException, AuthenticationException {
|
||||
if (Strings.isNullOrEmpty(gateway)) {
|
||||
throw gatewayUnsupported();
|
||||
}
|
||||
|
||||
SkinServer.verifyServerConnection(upload.getSession(), SERVER_ID);
|
||||
|
||||
NetClient client = new NetClient("POST", gateway);
|
||||
|
||||
client.putFormData(createHeaders(upload), "image/png");
|
||||
|
||||
if (upload.getImage() != null) {
|
||||
client.putFile(upload.getType().toString().toLowerCase(Locale.US), "image/png", upload.getImage());
|
||||
}
|
||||
|
||||
MoreHttpResponses resp = client.send();
|
||||
String response = resp.text();
|
||||
|
||||
if (response.startsWith("ERROR: ")) {
|
||||
response = response.substring(7);
|
||||
}
|
||||
|
||||
if (!response.equalsIgnoreCase("OK") && !response.endsWith("OK")) {
|
||||
throw new HttpException(response, resp.getResponseCode(), null);
|
||||
}
|
||||
|
||||
return new SkinUploadResponse(response);
|
||||
}
|
||||
|
||||
private UnsupportedOperationException gatewayUnsupported() {
|
||||
return new UnsupportedOperationException("Server does not have a gateway.");
|
||||
}
|
||||
|
||||
private Map<String, ?> createHeaders(SkinUpload upload) {
|
||||
Builder<String, Object> builder = ImmutableMap.<String, Object>builder()
|
||||
.put("user", upload.getSession().getUsername())
|
||||
.put("uuid", UUIDTypeAdapter.fromUUID(upload.getSession().getProfile().getId()))
|
||||
.put("type", upload.getType().toString().toLowerCase(Locale.US));
|
||||
|
||||
if (upload.getImage() == null) {
|
||||
builder.put("clear", "1");
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static String getPath(String address, MinecraftProfileTexture.Type type, GameProfile profile) {
|
||||
String uuid = UUIDTypeAdapter.fromUUID(profile.getId());
|
||||
String path = type.toString().toLowerCase() + "s";
|
||||
return String.format("%s/%s/%s.png?%s", address, path, uuid, Long.toString(new Date().getTime() / 1000));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyGateway() {
|
||||
return !Strings.isNullOrEmpty(gateway);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFeature(Feature feature) {
|
||||
switch (feature) {
|
||||
case DOWNLOAD_USER_SKIN:
|
||||
case UPLOAD_USER_SKIN:
|
||||
case DELETE_USER_SKIN:
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new IndentedToStringStyle.Builder(this)
|
||||
.append("address", address)
|
||||
.append("gateway", gateway)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.server;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The remote server API level that this skin server implements.
|
||||
*
|
||||
* Current values are:
|
||||
* - legacy
|
||||
* - valhalla
|
||||
* - bethlehem
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ServerType {
|
||||
|
||||
String value();
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.server;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||
import com.mojang.util.UUIDTypeAdapter;
|
||||
import com.mumfrey.liteloader.modconfig.Exposable;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
import com.voxelmodpack.hdskins.gui.Feature;
|
||||
import com.voxelmodpack.hdskins.util.CallableFutures;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.Session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface SkinServer extends Exposable {
|
||||
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter())
|
||||
.create();
|
||||
|
||||
List<SkinServer> defaultServers = Lists.newArrayList(new LegacySkinServer(
|
||||
"http://skins.voxelmodpack.com",
|
||||
"http://skinmanager.voxelmodpack.com")
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns true for any features that this skin server supports.
|
||||
*/
|
||||
boolean supportsFeature(Feature feature);
|
||||
|
||||
/**
|
||||
* Synchronously loads texture information for the provided profile.
|
||||
*
|
||||
* @return The parsed server response as a textures payload.
|
||||
*
|
||||
* @throws IOException If any authentication or network error occurs.
|
||||
*/
|
||||
MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException;
|
||||
|
||||
/**
|
||||
* Synchronously uploads a skin to this server.
|
||||
*
|
||||
* @param upload The payload to send.
|
||||
*
|
||||
* @return A server response object.
|
||||
*
|
||||
* @throws IOException If any authentication or network error occurs.
|
||||
* @throws AuthenticationException
|
||||
*/
|
||||
SkinUploadResponse performSkinUpload(SkinUpload upload) throws IOException, AuthenticationException;
|
||||
|
||||
/**
|
||||
* Asynchronously uploads a skin to the server.
|
||||
*
|
||||
* Returns an incomplete future for chaining other actions to be performed after this method completes.
|
||||
* Actions are dispatched to the default skinUploadExecutor
|
||||
*
|
||||
* @param upload The payload to send.
|
||||
*/
|
||||
default CompletableFuture<SkinUploadResponse> uploadSkin(SkinUpload upload) {
|
||||
return CallableFutures.asyncFailableFuture(() -> performSkinUpload(upload), HDSkinManager.skinUploadExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously loads texture information for the provided profile.
|
||||
*
|
||||
* Returns an incomplete future for chaining other actions to be performed after this method completes.
|
||||
* Actions are dispatched to the default skinDownloadExecutor
|
||||
*/
|
||||
default CompletableFuture<MinecraftTexturesPayload> getPreviewTextures(GameProfile profile) {
|
||||
return CallableFutures.asyncFailableFuture(() -> loadProfileData(profile), HDSkinManager.skinDownloadExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to validate this skin server's state.
|
||||
* Any servers with an invalid gateway format will not be loaded and generate an exception.
|
||||
*/
|
||||
default boolean verifyGateway() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins with the Mojang API to verify the current user's session.
|
||||
|
||||
* @throws AuthenticationException if authentication failed or the session is invalid.
|
||||
*/
|
||||
static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
|
||||
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
|
||||
service.joinServer(session.getProfile(), session.getToken(), serverId);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.server;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class SkinServerSerializer implements JsonSerializer<SkinServer>, JsonDeserializer<SkinServer> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(SkinServer src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
ServerType serverType = src.getClass().getAnnotation(ServerType.class);
|
||||
|
||||
if (serverType == null) {
|
||||
throw new JsonIOException("Skin server class did not have a type: " + typeOfSrc);
|
||||
}
|
||||
|
||||
JsonObject obj = context.serialize(src).getAsJsonObject();
|
||||
obj.addProperty("type", serverType.value());
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkinServer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
String type = json.getAsJsonObject().get("type").getAsString();
|
||||
|
||||
return context.deserialize(json, HDSkinManager.INSTANCE.getSkinServerClass(type));
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.server;
|
||||
|
||||
import net.minecraft.util.Session;
|
||||
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
public class SkinUpload {
|
||||
|
||||
private final Session session;
|
||||
private final URI image;
|
||||
private final Map<String, String> metadata;
|
||||
private final Type type;
|
||||
|
||||
public SkinUpload(Session session, Type type, @Nullable URI image, Map<String, String> metadata) {
|
||||
this.session = session;
|
||||
this.image = image;
|
||||
this.metadata = metadata;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Session getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public URI getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public MinecraftProfileTexture.Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getSchemaAction() {
|
||||
return image == null ? "none" : image.getScheme();
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.server;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
public class SkinUploadResponse {
|
||||
|
||||
private final String message;
|
||||
|
||||
public SkinUploadResponse(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("message", message)
|
||||
.toString();
|
||||
}
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.server;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||
import com.mojang.util.UUIDTypeAdapter;
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
import com.voxelmodpack.hdskins.gui.Feature;
|
||||
import com.voxelmodpack.hdskins.util.IndentedToStringStyle;
|
||||
import com.voxelmodpack.hdskins.util.MoreHttpResponses;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.Session;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.methods.RequestBuilder;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
@ServerType("valhalla")
|
||||
public class ValhallaSkinServer implements SkinServer {
|
||||
|
||||
@Expose
|
||||
private final String address;
|
||||
|
||||
private transient String accessToken;
|
||||
|
||||
public ValhallaSkinServer(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException {
|
||||
try (MoreHttpResponses response = MoreHttpResponses.execute(HDSkinManager.httpClient, new HttpGet(getTexturesURI(profile)))) {
|
||||
|
||||
if (response.ok()) {
|
||||
return response.unwrapAsJson(MinecraftTexturesPayload.class);
|
||||
}
|
||||
|
||||
throw new HttpException(response.getResponse());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkinUploadResponse performSkinUpload(SkinUpload upload) throws IOException, AuthenticationException {
|
||||
try {
|
||||
return uploadPlayerSkin(upload);
|
||||
} catch (IOException e) {
|
||||
if (e.getMessage().equals("Authorization failed")) {
|
||||
accessToken = null;
|
||||
return uploadPlayerSkin(upload);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private SkinUploadResponse uploadPlayerSkin(SkinUpload upload) throws IOException, AuthenticationException {
|
||||
authorize(upload.getSession());
|
||||
|
||||
switch (upload.getSchemaAction()) {
|
||||
case "none":
|
||||
return resetSkin(upload);
|
||||
case "file":
|
||||
return uploadFile(upload);
|
||||
case "http":
|
||||
case "https":
|
||||
return uploadUrl(upload);
|
||||
default:
|
||||
throw new IOException("Unsupported URI scheme: " + upload.getSchemaAction());
|
||||
}
|
||||
}
|
||||
|
||||
private SkinUploadResponse resetSkin(SkinUpload upload) throws IOException {
|
||||
return upload(RequestBuilder.delete()
|
||||
.setUri(buildUserTextureUri(upload.getSession().getProfile(), upload.getType()))
|
||||
.addHeader(HttpHeaders.AUTHORIZATION, this.accessToken)
|
||||
.build());
|
||||
}
|
||||
|
||||
private SkinUploadResponse uploadFile(SkinUpload upload) throws IOException {
|
||||
final File file = new File(upload.getImage());
|
||||
|
||||
MultipartEntityBuilder b = MultipartEntityBuilder.create()
|
||||
.addBinaryBody("file", file, ContentType.create("image/png"), file.getName());
|
||||
|
||||
upload.getMetadata().forEach(b::addTextBody);
|
||||
|
||||
return upload(RequestBuilder.put()
|
||||
.setUri(buildUserTextureUri(upload.getSession().getProfile(), upload.getType()))
|
||||
.addHeader(HttpHeaders.AUTHORIZATION, this.accessToken)
|
||||
.setEntity(b.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
private SkinUploadResponse uploadUrl(SkinUpload upload) throws IOException {
|
||||
return upload(RequestBuilder.post()
|
||||
.setUri(buildUserTextureUri(upload.getSession().getProfile(), upload.getType()))
|
||||
.addHeader(HttpHeaders.AUTHORIZATION, this.accessToken)
|
||||
.addParameter("file", upload.getImage().toString())
|
||||
.addParameters(MoreHttpResponses.mapAsParameters(upload.getMetadata()))
|
||||
.build());
|
||||
}
|
||||
|
||||
private SkinUploadResponse upload(HttpUriRequest request) throws IOException {
|
||||
try (MoreHttpResponses response = MoreHttpResponses.execute(HDSkinManager.httpClient, request)) {
|
||||
return response.unwrapAsJson(SkinUploadResponse.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void authorize(Session session) throws IOException, AuthenticationException {
|
||||
if (this.accessToken != null) {
|
||||
return;
|
||||
}
|
||||
GameProfile profile = session.getProfile();
|
||||
String token = session.getToken();
|
||||
AuthHandshake handshake = authHandshake(profile.getName());
|
||||
|
||||
if (handshake.offline) {
|
||||
return;
|
||||
}
|
||||
|
||||
// join the session server
|
||||
Minecraft.getMinecraft().getSessionService().joinServer(profile, token, handshake.serverId);
|
||||
|
||||
AuthResponse response = authResponse(profile.getName(), handshake.verifyToken);
|
||||
if (!response.userId.equals(profile.getId())) {
|
||||
throw new IOException("UUID mismatch!"); // probably won't ever throw
|
||||
}
|
||||
this.accessToken = response.accessToken;
|
||||
}
|
||||
|
||||
private AuthHandshake authHandshake(String name) throws IOException {
|
||||
try (MoreHttpResponses resp = MoreHttpResponses.execute(HDSkinManager.httpClient, RequestBuilder.post()
|
||||
.setUri(getHandshakeURI())
|
||||
.addParameter("name", name)
|
||||
.build())) {
|
||||
return resp.unwrapAsJson(AuthHandshake.class);
|
||||
}
|
||||
}
|
||||
|
||||
private AuthResponse authResponse(String name, long verifyToken) throws IOException {
|
||||
try (MoreHttpResponses resp = MoreHttpResponses.execute(HDSkinManager.httpClient, RequestBuilder.post()
|
||||
.setUri(getResponseURI())
|
||||
.addParameter("name", name)
|
||||
.addParameter("verifyToken", String.valueOf(verifyToken))
|
||||
.build())) {
|
||||
return resp.unwrapAsJson(AuthResponse.class);
|
||||
}
|
||||
}
|
||||
|
||||
private URI buildUserTextureUri(GameProfile profile, MinecraftProfileTexture.Type textureType) {
|
||||
String user = UUIDTypeAdapter.fromUUID(profile.getId());
|
||||
String skinType = textureType.name().toLowerCase(Locale.US);
|
||||
return URI.create(String.format("%s/user/%s/%s", this.address, user, skinType));
|
||||
}
|
||||
|
||||
private URI getTexturesURI(GameProfile profile) {
|
||||
Preconditions.checkNotNull(profile.getId(), "profile id required for skins");
|
||||
return URI.create(String.format("%s/user/%s", this.address, UUIDTypeAdapter.fromUUID(profile.getId())));
|
||||
}
|
||||
|
||||
private URI getHandshakeURI() {
|
||||
return URI.create(String.format("%s/auth/handshake", this.address));
|
||||
}
|
||||
|
||||
private URI getResponseURI() {
|
||||
return URI.create(String.format("%s/auth/response", this.address));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFeature(Feature feature) {
|
||||
switch (feature) {
|
||||
case DOWNLOAD_USER_SKIN:
|
||||
case UPLOAD_USER_SKIN:
|
||||
case DELETE_USER_SKIN:
|
||||
case MODEL_VARIANTS:
|
||||
case MODEL_TYPES:
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new IndentedToStringStyle.Builder(this)
|
||||
.append("address", address)
|
||||
.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
private static class AuthHandshake {
|
||||
|
||||
private boolean offline;
|
||||
private String serverId;
|
||||
private long verifyToken;
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
private static class AuthResponse {
|
||||
|
||||
private String accessToken;
|
||||
private UUID userId;
|
||||
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package com.voxelmodpack.hdskins.server;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -1,48 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.awt.dnd.DnDConstants;
|
||||
import java.awt.dnd.DropTargetDragEvent;
|
||||
import java.awt.dnd.DropTargetDropEvent;
|
||||
import java.awt.dnd.DropTargetEvent;
|
||||
import java.awt.dnd.DropTargetListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FileDropListener extends DropTargetListener {
|
||||
|
||||
@Override
|
||||
default void dragEnter(DropTargetDragEvent dtde) {
|
||||
}
|
||||
|
||||
@Override
|
||||
default void dragOver(DropTargetDragEvent dtde) {
|
||||
}
|
||||
|
||||
@Override
|
||||
default void dropActionChanged(DropTargetDragEvent dtde) {
|
||||
}
|
||||
|
||||
@Override
|
||||
default void dragExit(DropTargetEvent dte) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
default void drop(DropTargetDropEvent dtde) {
|
||||
dtde.acceptDrop(DnDConstants.ACTION_LINK);
|
||||
try {
|
||||
onDrop((List<File>) dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor));
|
||||
dtde.getDropTargetContext().dropComplete(true);
|
||||
} catch (UnsupportedFlavorException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void onDrop(List<File> files);
|
||||
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
import org.lwjgl.opengl.Display;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.dnd.DropTarget;
|
||||
import java.awt.dnd.DropTargetListener;
|
||||
import java.util.TooManyListenersException;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
public class FileDropper extends JFrame {
|
||||
private static final long serialVersionUID = -2945117328826695659L;
|
||||
|
||||
private static FileDropper instance = null;
|
||||
|
||||
public static FileDropper getAWTContext() {
|
||||
if (instance == null) {
|
||||
instance = new FileDropper();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final DropTarget dt;
|
||||
|
||||
public FileDropper() {
|
||||
super("Skin Drop");
|
||||
|
||||
setType(Type.UTILITY);
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
setResizable(false);
|
||||
setTitle("Skin Drop");
|
||||
setSize(256, 256);
|
||||
setAlwaysOnTop(true);
|
||||
getRootPane().setWindowDecorationStyle(JRootPane.NONE);
|
||||
getContentPane().setLayout(null);
|
||||
|
||||
JPanel panel = new JPanel();
|
||||
panel.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.GRAY));
|
||||
panel.setBounds(10, 11, 230, 205);
|
||||
getContentPane().add(panel);
|
||||
|
||||
JLabel txtInst = new JLabel("Drop skin files here");
|
||||
txtInst.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
txtInst.setVerticalAlignment(SwingConstants.CENTER);
|
||||
panel.add(txtInst);
|
||||
|
||||
dt = new DropTarget();
|
||||
|
||||
setDropTarget(dt);
|
||||
|
||||
if (InternalDialog.hiddenFrame == null) {
|
||||
InternalDialog.hiddenFrame = this;
|
||||
}
|
||||
}
|
||||
|
||||
public void show(DropTargetListener dtl) throws TooManyListenersException {
|
||||
dt.addDropTargetListener(dtl);
|
||||
setVisible(true);
|
||||
requestFocusInWindow();
|
||||
setLocation(Display.getX(), Display.getY());
|
||||
}
|
||||
|
||||
public void hide(DropTargetListener dtl) {
|
||||
dt.removeDropTargetListener(dtl);
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
|
@ -1,293 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.DefaultResourcePack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.DisplayMode;
|
||||
|
||||
import java.awt.Canvas;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Image;
|
||||
import java.awt.Window;
|
||||
import java.awt.dnd.DropTarget;
|
||||
import java.awt.dnd.DropTargetListener;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.TooManyListenersException;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* Experimental window to control file drop. It kind of sucks.
|
||||
*
|
||||
*/
|
||||
public class GLWindow extends DropTarget {
|
||||
|
||||
// Serial version because someone decided to extend DropTarget
|
||||
private static final long serialVersionUID = -8891327070920541481L;
|
||||
|
||||
@Nullable
|
||||
private static GLWindow instance = null;
|
||||
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
/**
|
||||
* Gets or creates the current GLWindow context.
|
||||
*/
|
||||
public static synchronized GLWindow current() {
|
||||
if (instance == null) {
|
||||
instance = new GLWindow();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void create() {
|
||||
try {
|
||||
current().open();
|
||||
} catch (LWJGLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the current GLWindow context and restores default behaviour.
|
||||
*/
|
||||
public static synchronized void dispose() {
|
||||
if (instance != null) {
|
||||
instance.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static int getScaledPixelUnit(int i) {
|
||||
return Math.max((int)Math.round(i * Display.getPixelScaleFactor()), 0);
|
||||
}
|
||||
|
||||
private final Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
private JFrame frame;
|
||||
private Canvas canvas;
|
||||
|
||||
private volatile DropTargetListener dropListener = null;
|
||||
|
||||
private int windowState = 0;
|
||||
|
||||
private boolean isFullscreen;
|
||||
|
||||
private boolean ready = false;
|
||||
private boolean closeRequested = false;
|
||||
|
||||
private GLWindow() {
|
||||
|
||||
}
|
||||
|
||||
public JFrame getFrame() {
|
||||
return frame;
|
||||
}
|
||||
|
||||
private int frameFactorX;
|
||||
private int frameFactorY;
|
||||
|
||||
private synchronized void open() throws LWJGLException {
|
||||
// Dimensions from LWJGL may have a non 1:1 scale on high DPI monitors.
|
||||
int x = getScaledPixelUnit(Display.getX());
|
||||
int y = getScaledPixelUnit(Display.getY());
|
||||
|
||||
int w = getScaledPixelUnit(Display.getWidth());
|
||||
int h = getScaledPixelUnit(Display.getHeight());
|
||||
|
||||
isFullscreen = mc.isFullScreen();
|
||||
|
||||
canvas = new Canvas();
|
||||
|
||||
frame = new JFrame(Display.getTitle());
|
||||
frame.add(canvas);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(WindowEvent windowEvent) {
|
||||
if (!closeRequested) {
|
||||
for (Window w : Frame.getWindows()) {
|
||||
w.dispose();
|
||||
}
|
||||
|
||||
mc.shutdown();
|
||||
}
|
||||
closeRequested = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowStateChanged(WindowEvent event) {
|
||||
windowState = event.getNewState();
|
||||
onResize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowOpened(WindowEvent e) {
|
||||
// Once the window has opened compare the content and window dimensions to get
|
||||
// the OS's frame size then reassign adjusted dimensions to match LWJGL's window.
|
||||
frameFactorX = frame.getWidth() - frame.getContentPane().getWidth();
|
||||
frameFactorY = frame.getHeight() - frame.getContentPane().getHeight();
|
||||
|
||||
frame.setSize(w + frameFactorX, h + frameFactorY);
|
||||
}
|
||||
});
|
||||
frame.addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent componentEvent) {
|
||||
onResize();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: (Unconfirmed) reports say the icon appears small on some OSs.
|
||||
// I've yet to reproduce this.
|
||||
setIcons();
|
||||
|
||||
// Order here is important. Size is set _before_ displaying but
|
||||
// after events to ensure the window and canvas both get correct dimensions.
|
||||
frame.setResizable(Display.isResizable());
|
||||
frame.setLocation(x, y);
|
||||
frame.setSize(w, h);
|
||||
frame.setVisible(true);
|
||||
|
||||
Display.setParent(canvas);
|
||||
Display.setFullscreen(isFullscreen);
|
||||
|
||||
ready = true;
|
||||
}
|
||||
|
||||
private synchronized void close() {
|
||||
if (frame == null) {
|
||||
String msg = "GLClose was called in an illegal state! You cannot close the GLWindow before it has been opened.";
|
||||
logger.fatal(new IllegalStateException(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
closeRequested = true;
|
||||
|
||||
try {
|
||||
Display.setParent(null);
|
||||
} catch (LWJGLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
if (isFullscreen) {
|
||||
Display.setFullscreen(true);
|
||||
} else {
|
||||
if ((windowState & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH) {
|
||||
Display.setLocation(0, 0);
|
||||
Display.setDisplayMode(Display.getDesktopDisplayMode());
|
||||
} else {
|
||||
Display.setDisplayMode(new DisplayMode(frame.getContentPane().getWidth(), frame.getContentPane().getHeight()));
|
||||
Display.setLocation(Math.max(0, frame.getX() + frameFactorX/3), Math.max(0, frame.getY() + frameFactorY/7));
|
||||
}
|
||||
|
||||
// https://bugs.mojang.com/browse/MC-68754
|
||||
Display.setResizable(false);
|
||||
Display.setResizable(true);
|
||||
}
|
||||
} catch (LWJGLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
frame.setVisible(false);
|
||||
frame.dispose();
|
||||
|
||||
for (Window w : Frame.getWindows()) {
|
||||
w.dispose();
|
||||
}
|
||||
|
||||
instance = null;
|
||||
}
|
||||
|
||||
private void setIcons() {
|
||||
// VanillaTweakInjector.loadIconsOnFrames();
|
||||
try {
|
||||
//
|
||||
// The icons are stored in Display#cached_icons. However they're not the _original_ values.
|
||||
// LWJGL copies the initial byte streams and then reverses them. The result is a stream that's not
|
||||
// only already consumed, but somehow invalid when you try to parse it through ImageIO.read.
|
||||
//
|
||||
DefaultResourcePack pack = (DefaultResourcePack) mc.getResourcePackRepository().rprDefaultResourcePack;
|
||||
|
||||
List<Image> images = Lists.newArrayList(
|
||||
ImageIO.read(pack.getInputStreamAssets(new ResourceLocation("icons/icon_16x16.png"))),
|
||||
ImageIO.read(pack.getInputStreamAssets(new ResourceLocation("icons/icon_32x32.png")))
|
||||
);
|
||||
|
||||
Frame[] frames = Frame.getFrames();
|
||||
|
||||
if (frames != null) {
|
||||
for (Frame frame : frames) {
|
||||
try {
|
||||
frame.setIconImages(images);
|
||||
} catch (Throwable t) {}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void onResize() {
|
||||
canvas.setBounds(0, 0, frame.getContentPane().getWidth(), frame.getContentPane().getHeight());
|
||||
}
|
||||
|
||||
public void refresh(boolean fullscreen) {
|
||||
if (ready && fullscreen != isFullscreen) {
|
||||
// Repaint the canvas, not the window.
|
||||
// The former strips the window of its state. The latter fixes a viewport scaling bug.
|
||||
canvas.setBounds(0, 0, 0, 0);
|
||||
onResize();
|
||||
isFullscreen = fullscreen;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void clearDropTargetListener() {
|
||||
SwingUtilities.invokeLater(this::syncClearDropTargetListener);
|
||||
}
|
||||
|
||||
private void syncClearDropTargetListener() {
|
||||
if (dropListener != null) {
|
||||
if (!ready) {
|
||||
FileDropper.getAWTContext().hide(dropListener);
|
||||
} else {
|
||||
frame.setDropTarget(null);
|
||||
removeDropTargetListener(dropListener);
|
||||
}
|
||||
|
||||
dropListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setDropTargetListener(FileDropListener dtl) {
|
||||
SwingUtilities.invokeLater(() -> syncSetDropTargetListener(dtl));
|
||||
}
|
||||
|
||||
private void syncSetDropTargetListener(FileDropListener dtl) {
|
||||
try {
|
||||
syncClearDropTargetListener();
|
||||
|
||||
dropListener = dtl;
|
||||
|
||||
if (!ready) {
|
||||
FileDropper.getAWTContext().show(dtl);
|
||||
return;
|
||||
}
|
||||
|
||||
frame.setDropTarget(this);
|
||||
addDropTargetListener(dtl);
|
||||
} catch (TooManyListenersException ignored) { }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface IFileCallback {
|
||||
void onDialogClosed(File file, int dialogResults);
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
public interface IFileDialog extends Runnable {
|
||||
void start();
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
final class InternalDialog {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
static JFrame hiddenFrame;
|
||||
|
||||
public static JFrame getAWTContext() {
|
||||
JFrame context = GLWindow.current().getFrame();
|
||||
|
||||
if (context != null) {
|
||||
return context;
|
||||
}
|
||||
|
||||
if (hiddenFrame == null) {
|
||||
hiddenFrame = new JFrame("InternalDialogue");
|
||||
hiddenFrame.setVisible(false);
|
||||
hiddenFrame.requestFocusInWindow();
|
||||
hiddenFrame.requestFocus();
|
||||
|
||||
try {
|
||||
if (hiddenFrame.isAlwaysOnTopSupported()) {
|
||||
hiddenFrame.setAlwaysOnTop(true);
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
LOGGER.fatal("Could not set window on top state. This is probably Forge's fault.", e);
|
||||
}
|
||||
}
|
||||
|
||||
return hiddenFrame;
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.voxelmodpack.hdskins.LiteModHDSkins;
|
||||
|
||||
/**
|
||||
* Base class for "open file" dialog threads
|
||||
*
|
||||
* @author Adam Mummery-Smith
|
||||
*/
|
||||
public abstract class ThreadOpenFile extends Thread implements IFileDialog {
|
||||
|
||||
protected String dialogTitle;
|
||||
|
||||
/**
|
||||
* Delegate to call back when the dialog box is closed
|
||||
*/
|
||||
protected final IFileCallback parentScreen;
|
||||
|
||||
protected ThreadOpenFile(Minecraft minecraft, String dialogTitle, IFileCallback callback) throws IllegalStateException {
|
||||
if (minecraft.isFullScreen()) {
|
||||
throw new IllegalStateException("Cannot open an awt window whilst minecraft is in full screen mode!");
|
||||
}
|
||||
|
||||
this.parentScreen = callback;
|
||||
this.dialogTitle = dialogTitle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
JFileChooser fileDialog = new JFileChooser();
|
||||
fileDialog.setDialogTitle(dialogTitle);
|
||||
|
||||
String last = LiteModHDSkins.instance().lastChosenFile;
|
||||
if (!StringUtils.isBlank(last)) {
|
||||
fileDialog.setSelectedFile(new File(last));
|
||||
}
|
||||
fileDialog.setFileFilter(getFileFilter());
|
||||
|
||||
int dialogResult = showDialog(fileDialog);
|
||||
|
||||
File f = fileDialog.getSelectedFile();
|
||||
|
||||
if (f != null) {
|
||||
LiteModHDSkins.instance().lastChosenFile = f.getAbsolutePath();
|
||||
LiteModHDSkins.instance().writeConfig();
|
||||
|
||||
if (!f.exists() && f.getName().indexOf('.') == -1) {
|
||||
f = appendMissingExtension(f);
|
||||
}
|
||||
}
|
||||
|
||||
parentScreen.onDialogClosed(f, dialogResult);
|
||||
}
|
||||
|
||||
protected int showDialog(JFileChooser chooser) {
|
||||
return chooser.showOpenDialog(InternalDialog.getAWTContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should override this to return a file filter
|
||||
*/
|
||||
protected abstract FileFilter getFileFilter();
|
||||
|
||||
protected File appendMissingExtension(File file) {
|
||||
return file;
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Opens an awt "Open File" dialog with a PNG file filter
|
||||
*
|
||||
* @author Adam Mummery-Smith
|
||||
*/
|
||||
public class ThreadOpenFilePNG extends ThreadOpenFile {
|
||||
|
||||
public ThreadOpenFilePNG(Minecraft minecraft, String dialogTitle, IFileCallback callback) throws IllegalStateException {
|
||||
super(minecraft, dialogTitle, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileFilter getFileFilter() {
|
||||
return new FileFilter() {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "PNG Files (*.png)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return f.isDirectory() || f.getName().toLowerCase().endsWith(".png");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Opens an awt "Save File" dialog
|
||||
*/
|
||||
public abstract class ThreadSaveFile extends ThreadOpenFile {
|
||||
|
||||
protected String filename;
|
||||
|
||||
protected ThreadSaveFile(Minecraft minecraft, String dialogTitle, String initialFilename, IFileCallback callback) throws IllegalStateException {
|
||||
super(minecraft, dialogTitle, callback);
|
||||
this.filename = initialFilename;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int showDialog(JFileChooser chooser) {
|
||||
|
||||
|
||||
do {
|
||||
chooser.setSelectedFile(new File(filename));
|
||||
|
||||
int result = chooser.showSaveDialog(InternalDialog.getAWTContext());
|
||||
|
||||
File f = chooser.getSelectedFile();
|
||||
if (result == 0 && f != null && f.exists()) {
|
||||
|
||||
if (JOptionPane.showConfirmDialog(chooser,
|
||||
"A file named \"" + f.getName() + "\" already exists. Do you want to replace it?", "Confirm",
|
||||
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION) {
|
||||
continue;
|
||||
}
|
||||
|
||||
f.delete();
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
} while (true);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ThreadSaveFilePNG extends ThreadSaveFile {
|
||||
|
||||
public ThreadSaveFilePNG(Minecraft minecraft, String dialogTitle, String filename, IFileCallback callback) {
|
||||
super(minecraft, dialogTitle, filename, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileFilter getFileFilter() {
|
||||
return new FileFilter() {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "PNG Files (*.png)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(File f) {
|
||||
return f.isDirectory() || f.getName().toLowerCase().endsWith(".png");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File appendMissingExtension(File file) {
|
||||
return new File(file.getParentFile(), file.getName() + ".png");
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package com.voxelmodpack.hdskins.upload;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -1,56 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.util;
|
||||
|
||||
import com.google.common.util.concurrent.Runnables;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class CallableFutures {
|
||||
|
||||
private static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
public static <T> CompletableFuture<T> asyncFailableFuture(Callable<T> call, Executor exec) {
|
||||
CompletableFuture<T> ret = new CompletableFuture<>();
|
||||
exec.execute(() -> {
|
||||
try {
|
||||
ret.complete(call.call());
|
||||
} catch (Throwable e) {
|
||||
ret.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static <T> CompletableFuture<T> failedFuture(Exception e) {
|
||||
CompletableFuture<T> ret = new CompletableFuture<>();
|
||||
ret.completeExceptionally(e);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static <T> BiFunction<? super T, Throwable, Void> callback(Runnable c) {
|
||||
return (o, t) -> {
|
||||
if (t != null) {
|
||||
t.printStackTrace();
|
||||
} else {
|
||||
c.run();
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
public static CompletableFuture<Void> scheduleTask(Runnable task) {
|
||||
// schedule a task for next tick.
|
||||
return CompletableFuture.runAsync(Runnables.doNothing(), delayed(50, TimeUnit.MILLISECONDS))
|
||||
.handleAsync(callback(task), Minecraft.getMinecraft()::addScheduledTask);
|
||||
}
|
||||
|
||||
private static Executor delayed(long time, TimeUnit unit) {
|
||||
return (task) -> executor.schedule(task, time, unit);
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.util;
|
||||
|
||||
public abstract class Edge {
|
||||
|
||||
private boolean previousState;
|
||||
|
||||
private Callback callback;
|
||||
|
||||
public Edge(Callback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
boolean state = nextState();
|
||||
|
||||
if (state != previousState) {
|
||||
previousState = state;
|
||||
callback.call(state);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getState() {
|
||||
return previousState;
|
||||
}
|
||||
|
||||
protected abstract boolean nextState();
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Callback {
|
||||
void call(boolean state);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.util;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import static net.minecraft.util.text.TextFormatting.*;
|
||||
|
||||
public class IndentedToStringStyle extends ToStringStyle {
|
||||
|
||||
private static final long serialVersionUID = 2031593562293731492L;
|
||||
|
||||
private static final ToStringStyle INSTANCE = new IndentedToStringStyle();
|
||||
|
||||
private IndentedToStringStyle() {
|
||||
this.setFieldNameValueSeparator(": " + RESET + ITALIC);
|
||||
this.setContentStart(null);
|
||||
this.setFieldSeparator(SystemUtils.LINE_SEPARATOR + " " + RESET + YELLOW);
|
||||
this.setFieldSeparatorAtStart(true);
|
||||
this.setContentEnd(null);
|
||||
this.setUseIdentityHashCode(false);
|
||||
this.setUseShortClassName(true);
|
||||
}
|
||||
|
||||
public static class Builder extends ToStringBuilder {
|
||||
public Builder(Object o) {
|
||||
super(o, IndentedToStringStyle.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
return YELLOW + super.build();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.util;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.voxelmodpack.hdskins.server.SkinServer;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Utility class for getting different response types from a http response.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MoreHttpResponses extends AutoCloseable {
|
||||
|
||||
CloseableHttpResponse getResponse();
|
||||
|
||||
default boolean ok() {
|
||||
return getResponseCode() == HttpStatus.SC_OK;
|
||||
}
|
||||
|
||||
default int getResponseCode() {
|
||||
return getResponse().getStatusLine().getStatusCode();
|
||||
}
|
||||
|
||||
default String getContentType() {
|
||||
return getResponse().getEntity().getContentType().getValue();
|
||||
}
|
||||
|
||||
default InputStream getInputStream() throws IOException {
|
||||
return getResponse().getEntity().getContent();
|
||||
}
|
||||
|
||||
default BufferedReader getReader() throws IOException {
|
||||
return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
default byte[] bytes() throws IOException {
|
||||
try (InputStream input = getInputStream()) {
|
||||
return ByteStreams.toByteArray(input);
|
||||
}
|
||||
}
|
||||
|
||||
default String text() throws IOException {
|
||||
try (BufferedReader reader = getReader()) {
|
||||
return CharStreams.toString(reader);
|
||||
}
|
||||
}
|
||||
|
||||
default Stream<String> lines() throws IOException {
|
||||
try (BufferedReader reader = getReader()) {
|
||||
return reader.lines();
|
||||
}
|
||||
}
|
||||
|
||||
default <T> T json(Class<T> type) throws IOException {
|
||||
try (BufferedReader reader = getReader()) {
|
||||
return SkinServer.gson.fromJson(reader, type);
|
||||
}
|
||||
}
|
||||
|
||||
default <T> T json(Type type) throws IOException {
|
||||
try (BufferedReader reader = getReader()) {
|
||||
return SkinServer.gson.fromJson(reader, type);
|
||||
}
|
||||
}
|
||||
|
||||
default <T> T unwrapAsJson(Type type) throws IOException {
|
||||
if (!"application/json".equals(getContentType())) {
|
||||
throw new IOException("Server returned a non-json response!");
|
||||
}
|
||||
|
||||
if (ok()) {
|
||||
return json(type);
|
||||
}
|
||||
|
||||
throw new IOException(json(JsonObject.class).get("message").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
default void close() throws IOException {
|
||||
this.getResponse().close();
|
||||
}
|
||||
|
||||
static MoreHttpResponses execute(CloseableHttpClient client, HttpUriRequest request) throws IOException {
|
||||
CloseableHttpResponse response = client.execute(request);
|
||||
return () -> response;
|
||||
}
|
||||
|
||||
static NameValuePair[] mapAsParameters(Map<String, String> parameters) {
|
||||
return parameters.entrySet().stream()
|
||||
.map(entry ->
|
||||
new BasicNameValuePair(entry.getKey(), entry.getValue())
|
||||
)
|
||||
.toArray(NameValuePair[]::new);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class MoreStreams {
|
||||
|
||||
public static <T> Stream<T> ofNullable(@Nullable T t) {
|
||||
return t == null ? Stream.empty() : Stream.of(t);
|
||||
}
|
||||
|
||||
public static <T, V> V[] map(T[] items, Function<T, V> converter, IntFunction<V[]> collector) {
|
||||
return Lists.newArrayList(items)
|
||||
.stream()
|
||||
.map(converter)
|
||||
.toArray(collector);
|
||||
}
|
||||
|
||||
public static <T, V> List<V> map(List<T> items, Function<T, V> converter) {
|
||||
return items.stream()
|
||||
.map(converter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <T> List<T> distinct(List<T> input) {
|
||||
return input.stream()
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.util;
|
||||
|
||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.methods.RequestBuilder;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Ew. Why so many builders? >.<
|
||||
*/
|
||||
public class NetClient {
|
||||
|
||||
private final RequestBuilder rqBuilder;
|
||||
private MultipartEntityBuilder entityBuilder;
|
||||
|
||||
private Map<String, ?> headers;
|
||||
|
||||
public NetClient(String method, String uri) {
|
||||
rqBuilder = RequestBuilder.create(method).setUri(uri);
|
||||
}
|
||||
|
||||
public NetClient putFile(String key, String contentType, URI file) {
|
||||
if (entityBuilder == null) {
|
||||
entityBuilder= MultipartEntityBuilder.create();
|
||||
}
|
||||
|
||||
File f = new File(file);
|
||||
HttpEntity entity = entityBuilder.addBinaryBody(key, f, ContentType.create(contentType), f.getName()).build();
|
||||
|
||||
rqBuilder.setEntity(entity);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public NetClient putFormData(Map<String, ?> data, String contentTypes) {
|
||||
if (entityBuilder == null) {
|
||||
entityBuilder= MultipartEntityBuilder.create();
|
||||
}
|
||||
|
||||
for (Map.Entry<String, ?> i : data.entrySet()) {
|
||||
entityBuilder.addTextBody(i.getKey(), i.getValue().toString());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public NetClient putHeaders(Map<String, ?> headers) {
|
||||
this.headers = headers;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MoreHttpResponses send() throws IOException {
|
||||
if (entityBuilder != null) {
|
||||
rqBuilder.setEntity(entityBuilder.build());
|
||||
}
|
||||
|
||||
HttpUriRequest request = rqBuilder.build();
|
||||
|
||||
if (headers != null) {
|
||||
for (Map.Entry<String, ?> parameter : headers.entrySet()) {
|
||||
request.addHeader(parameter.getKey(), parameter.getValue().toString());
|
||||
}
|
||||
}
|
||||
|
||||
return MoreHttpResponses.execute(HDSkinManager.httpClient, request);
|
||||
}
|
||||
|
||||
public CompletableFuture<MoreHttpResponses> async(Executor exec) {
|
||||
return CallableFutures.asyncFailableFuture(this::send, exec);
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.util;
|
||||
|
||||
import net.minecraft.client.entity.AbstractClientPlayer;
|
||||
import net.minecraft.client.network.NetworkPlayerInfo;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class PlayerUtil {
|
||||
|
||||
private static final Field playerInfo = FieldUtils.getAllFields(AbstractClientPlayer.class)[0];
|
||||
|
||||
public static NetworkPlayerInfo getInfo(AbstractClientPlayer player) {
|
||||
try {
|
||||
if (!playerInfo.isAccessible()) {
|
||||
playerInfo.setAccessible(true);
|
||||
}
|
||||
return (NetworkPlayerInfo) FieldUtils.readField(playerInfo, player);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.util;
|
||||
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
public class ProfileTextureUtil {
|
||||
|
||||
private static Field metadata = FieldUtils.getDeclaredField(MinecraftProfileTexture.class, "metadata", true);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, String> getMetadata(MinecraftProfileTexture texture) {
|
||||
try {
|
||||
return (Map<String, String>) FieldUtils.readField(metadata, texture);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Unable to read metadata field", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setMetadata(MinecraftProfileTexture texture, Map<String, String> meta) {
|
||||
try {
|
||||
FieldUtils.writeField(metadata, texture, meta);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Unable to write metadata field", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static BufferedImage getDynamicBufferedImage(int width, int height, DynamicTexture texture) {
|
||||
BufferedImage image = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
final int[] src = texture.getTextureData();
|
||||
|
||||
final int[] dst = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
|
||||
|
||||
System.arraycopy(src, 0, dst, 0, src.length);
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package com.voxelmodpack.hdskins.util;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||
import com.mojang.util.UUIDTypeAdapter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Use this to build a {@link MinecraftTexturesPayload} object. This is
|
||||
* required because it has no useful constructor. This uses reflection
|
||||
* via Gson to create a new instance and populate the fields.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class TexturesPayloadBuilder {
|
||||
|
||||
private static Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
|
||||
|
||||
public static MinecraftTexturesPayload createTexturesPayload(GameProfile profile, Map<Type, MinecraftProfileTexture> textures) {
|
||||
// This worked fine as is before I started using sub-classes.
|
||||
MinecraftTexturesPayload payload = gson.fromJson(gson.toJson(new TexturesPayloadBuilder(profile)), MinecraftTexturesPayload.class);
|
||||
payload.getTextures().putAll(textures);
|
||||
return payload;
|
||||
}
|
||||
|
||||
private long timestamp;
|
||||
|
||||
private UUID profileId;
|
||||
private String profileName;
|
||||
|
||||
private boolean isPublic;
|
||||
|
||||
private Map<Type, MinecraftProfileTexture> textures;
|
||||
|
||||
private TexturesPayloadBuilder(GameProfile profile) {
|
||||
profileId = profile.getId();
|
||||
profileName = profile.getName();
|
||||
timestamp = System.currentTimeMillis();
|
||||
|
||||
isPublic = true;
|
||||
|
||||
this.textures = new HashMap<>();
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
#HD Skins de_DE.lang file
|
||||
|
||||
hdskins.choose=Suche die datei aus
|
||||
hdskins.manager=Skin Verwalter
|
||||
hdskins.error.unreadable=Datei nicht lesbar
|
||||
hdskins.error.ext=Keine PNG Datei
|
||||
hdskins.error.open=Fehler beim öffnen der skin Datei
|
||||
hdskins.error.invalid=Das ist doch kein skin du scherzkeks
|
||||
hdskins.error.select=Bitte erst den skin auswählen
|
||||
hdskins.error.mojang=Mojang API Fehler
|
||||
hdskins.error.mojang.wait=Bitte warte %d minuten
|
||||
hdskins.error.noserver=Es ist kein gültiges Skin Server verfügbar
|
||||
hdskins.error.offline=- Server Offline -
|
||||
|
||||
hdskins.open.title=Suche dir ein skin aus
|
||||
hdskins.save.title=Wo soll dieses gegen gespeichert werden
|
||||
hdskins.fetch=Rufe Skin ab...
|
||||
hdskins.failed=Hochladen des Skins fehlgeschlagen
|
||||
hdskins.request=Sende Anfrage zu Server bitte warten...
|
||||
hdskins.upload=Skin wird hochgeladen bitte warten...
|
||||
|
||||
hdskins.local=Lokaler Skin
|
||||
hdskins.server=Server Skin
|
||||
|
||||
hdskins.mode.steve=Steve Model
|
||||
hdskins.mode.alex=Alex Model
|
||||
|
||||
hdskins.mode.skin=Spieler Texture
|
||||
hdskins.mode.cape=Cape Texture
|
||||
hdskins.mode.elytra=Elytra Texture
|
||||
|
||||
hdskins.mode.stand=Stehen
|
||||
hdskins.mode.sleep=Schlafen
|
||||
hdskins.mode.ride=Reiten
|
||||
|
||||
hdskins.options.chevy=>>
|
||||
hdskins.options.chevy.title=Skin Hochladen
|
||||
hdskins.options.download=<<
|
||||
hdskins.options.download.title=Skin Speichern
|
||||
|
||||
hdskins.options.close=Zurück
|
||||
hdskins.options.clear=Entfernen
|
||||
hdskins.options.browse=Suchen
|
||||
|
||||
hdskins.options.skindrops=Experimental Skin Drop
|
||||
hdskins.options.cache=Bereinige Temporären Skin speicher (cache)
|
||||
|
||||
hdskins.warning.experimental=§6WARNUNG: diese Funktion ist §4experimental§6, Das heißt falls es passt nicht richtig funktioniert, oder kaputt geht bist du selber verantwortlich
|
||||
hdskins.warning.disabled.title=§c%s %s
|
||||
hdskins.warning.disabled.description=§4(DEAKTIVIERT)\n§7diese Funktion wird von deinem aktuellen Skin Server nicht unterstützt.\n§7Bitte suche dir einen anderen Server um Fortzufahren
|
|
@ -1,50 +0,0 @@
|
|||
#HD Skins en_US.lang file
|
||||
|
||||
hdskins.choose=Choose a file
|
||||
hdskins.manager=Skin Manager
|
||||
hdskins.error.unreadable=File not readable
|
||||
hdskins.error.ext=File not PNG
|
||||
hdskins.error.open=Error opening skin file
|
||||
hdskins.error.invalid=Not a valid skin file
|
||||
hdskins.error.select=Please select a skin first
|
||||
hdskins.error.mojang=Mojang API Error
|
||||
hdskins.error.mojang.wait=Please wait %d minutes
|
||||
hdskins.error.noserver=There was no valid skin server available
|
||||
hdskins.error.offline=- Server Offline -
|
||||
|
||||
hdskins.open.title=Choose skin
|
||||
hdskins.save.title=Choose save location
|
||||
hdskins.fetch=Fetching skin...
|
||||
hdskins.failed=Uploading skin failed
|
||||
hdskins.request=Sending request to server please wait...
|
||||
hdskins.upload=Uploading skin please wait...
|
||||
|
||||
hdskins.local=Local Skin
|
||||
hdskins.server=Server Skin
|
||||
|
||||
hdskins.mode.steve=Steve Model
|
||||
hdskins.mode.alex=Alex Model
|
||||
|
||||
hdskins.mode.skin=Player Texture
|
||||
hdskins.mode.cape=Cape Texture
|
||||
hdskins.mode.elytra=Elytra Texture
|
||||
|
||||
hdskins.mode.stand=Standing
|
||||
hdskins.mode.sleep=Sleeping
|
||||
hdskins.mode.ride=Riding
|
||||
|
||||
hdskins.options.chevy=>>
|
||||
hdskins.options.chevy.title=Upload Skin
|
||||
hdskins.options.download=<<
|
||||
hdskins.options.download.title=Save Skin
|
||||
|
||||
hdskins.options.close=Close
|
||||
hdskins.options.clear=Clear
|
||||
hdskins.options.browse=Browse
|
||||
|
||||
hdskins.options.skindrops=Experimental Skin Drop
|
||||
hdskins.options.cache=Clear Skin Cache
|
||||
|
||||
hdskins.warning.experimental=§6WARNING: This feature is §4experimental§6, meaning things may break or derp or even slurp. Enabling this means you accept responsibility for what may happen to your chickens.
|
||||
hdskins.warning.disabled.title=§c%s %s
|
||||
hdskins.warning.disabled.description=§4(DISABLED)\n§7This feature is not supported by your current skin server.\n§7Please choose a different one to proceed.
|
|
@ -1,46 +0,0 @@
|
|||
# HD Skins fr_FR.lang file
|
||||
# Provided by Dalfio (PinkishPie)
|
||||
hdskins.choose=Choisissez un fichier
|
||||
hdskins.manager=Skin Manager HD
|
||||
hdskins.error.unreadable=Fichier non lisible
|
||||
hdskins.error.ext=Fichier non PNG
|
||||
hdskins.error.open=Erreur d'ouverture du fichier
|
||||
hdskins.error.invalid=Pas un fichier valide
|
||||
hdskins.error.select=S.V.P. sélectionner un skin en premier
|
||||
hdskins.error.mojang=Erreur d'API Mojang
|
||||
hdskins.error.mojang.wait=Please wait %d minutes
|
||||
hdskins.open.title=Choisissez un skin
|
||||
hdskins.fetch=Chargement du skin...
|
||||
hdskins.failed=Ajout du skin échoué
|
||||
hdskins.request=Envoi de la requête au serveur S.V.P. patientez ...
|
||||
hdskins.upload=Ajout du skin, S.V.P. patientez ...
|
||||
|
||||
hdskins.local=Local Skin
|
||||
hdskins.server=Server Skin
|
||||
|
||||
hdskins.mode.steve=Steve Model
|
||||
hdskins.mode.alex=Alex Model
|
||||
|
||||
hdskins.mode.skin=Player Texture
|
||||
hdskins.mode.cape=Cape Texture
|
||||
hdskins.mode.elytra=Elytra Texture
|
||||
|
||||
hdskins.mode.stand=Standing
|
||||
hdskins.mode.sleep=Sleeping
|
||||
hdskins.mode.ride=Riding
|
||||
|
||||
hdskins.options.chevy=>>
|
||||
hdskins.options.chevy.title=Upload Skin
|
||||
hdskins.options.download=<<
|
||||
hdskins.options.download.title=Save Skin
|
||||
|
||||
hdskins.options.close=Close
|
||||
hdskins.options.clear=Clear
|
||||
hdskins.options.browse=Browse
|
||||
|
||||
hdskins.options.skindrops=Experimental Skin Drop
|
||||
hdskins.options.cache=Clear Skin Cache
|
||||
|
||||
hdskins.warning.experimental=§6WARNING: This feature is §4experimental§6, meaning things may break or derp or even slurp. Enabling this means you accept responsibility for what may happen to your chickens.
|
||||
hdskins.warning.disabled.title=§c%s %s
|
||||
hdskins.warning.disabled.description=§4(DISABLED)\n§7This feature is not supported by your current skin server.\n§7Please choose a different one to proceed.
|
|
@ -1,50 +0,0 @@
|
|||
#HD Skins ru_ru.lang file
|
||||
|
||||
hdskins.choose=Выберите файл
|
||||
hdskins.manager=Помощник по работе со скинами
|
||||
hdskins.error.unreadable=Не удалось прочитать файл
|
||||
hdskins.error.ext=Файл должен быть в формате .png
|
||||
hdskins.error.open=Ошибка при открытии файла скина
|
||||
hdskins.error.invalid=Неверный файл скина
|
||||
hdskins.error.select=Пожалуйста, сначала выберите скин
|
||||
hdskins.error.mojang=Ошибка Mojang API
|
||||
hdskins.error.mojang.wait=Пожалуйста, подождите %d минут(ы)...
|
||||
hdskins.error.noserver=Не найдено ни одного скин-сервера
|
||||
hdskins.error.offline=- Сервер не в сети -
|
||||
|
||||
hdskins.open.title=Выберите ваш скин
|
||||
hdskins.save.title=Выберите имя файла для сохранения...
|
||||
hdskins.fetch=Скачивание скина...
|
||||
hdskins.failed=Загрузка скина не удалась
|
||||
hdskins.request=Отправка запроса на сервер, пожалуйста, подождите.
|
||||
hdskins.upload=Загрузка скина, пожалуйста, подождите.
|
||||
|
||||
hdskins.local=Локальный скин
|
||||
hdskins.server=Скин на сервере
|
||||
|
||||
hdskins.mode.steve=Стандартная модель
|
||||
hdskins.mode.alex=Тонконогая модель
|
||||
|
||||
hdskins.mode.skin=Скин игрока
|
||||
hdskins.mode.cape=Текстура плаща
|
||||
hdskins.mode.elytra=Текстура надкрылий
|
||||
|
||||
hdskins.mode.stand=Обычная поза
|
||||
hdskins.mode.sleep=Поза сна
|
||||
hdskins.mode.ride=Сидячая поза
|
||||
|
||||
hdskins.options.chevy=>>
|
||||
hdskins.options.chevy.title=Загрузить скин
|
||||
hdskins.options.download=<<
|
||||
hdskins.options.download.title=Скачать скин
|
||||
|
||||
hdskins.options.close=Закрыть
|
||||
hdskins.options.clear=Удалить скин
|
||||
hdskins.options.browse=Выбрать
|
||||
|
||||
hdskins.options.skindrops=Экспериментальное перетаскивание скина
|
||||
hdskins.options.cache=Очистить кеш скинов
|
||||
|
||||
hdskins.warning.experimental=§6ВНИМАНИЕ: Эта функция §4экспериментальная§6, что означает, что вещи могут начать ломаться, извиваться или даже захлёбываться. При её включении авторы сего текста не несут ответственности за возможные последствия.
|
||||
hdskins.warning.disabled.title=§c%s %s
|
||||
hdskins.warning.disabled.description=§4(ОТКЛЮЧЕНО)\n§7Данная опция не поддерживается текущим скин-сервером.\n§7Пожалуйста, выберите другой скин-сервер.
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue