Merge branch 'development' into render

# Conflicts:
#	pom.xml
#	src/main/java/de/bixilon/minosoft/data/world/BlockPosition.java
#	src/main/java/de/bixilon/minosoft/data/world/Chunk.java
#	src/main/java/de/bixilon/minosoft/data/world/ChunkSection.java
#	src/main/java/de/bixilon/minosoft/data/world/InChunkLocation.java
#	src/main/java/de/bixilon/minosoft/data/world/World.java
#	src/main/java/de/bixilon/minosoft/util/ChunkUtil.java
This commit is contained in:
Bixilon 2020-11-03 15:01:05 +01:00
commit f79b438108
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
48 changed files with 392 additions and 637 deletions

View File

@ -2,7 +2,7 @@ variables:
MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository" MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true" MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true"
image: maven:3-openjdk-14 image: maven:3-openjdk-15
cache: cache:
paths: paths:

1
.idea/compiler.xml generated
View File

@ -10,5 +10,6 @@
<module name="Minosoft" /> <module name="Minosoft" />
</profile> </profile>
</annotationProcessing> </annotationProcessing>
<bytecodeTargetLevel target="15" />
</component> </component>
</project> </project>

2
.idea/misc.xml generated
View File

@ -8,7 +8,7 @@
</list> </list>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_14" default="false" project-jdk-name="14" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_14_PREVIEW" default="false" project-jdk-name="15" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View File

@ -24,8 +24,8 @@ Minosoft is an open source minecraft client, written from scratch in java. It ai
- Disk space: Minosoft itself is pretty small (2-3 Mib), the libraries are a bit bigger (up to 100 Mib). - Disk space: Minosoft itself is pretty small (2-3 Mib), the libraries are a bit bigger (up to 100 Mib).
You also need to have the "normal" minecraft assets (~ 300 Mib). So a total of 500 Mib is recommended. You also need to have the "normal" minecraft assets (~ 300 Mib). So a total of 500 Mib is recommended.
- GPU: Currently only needed for rendering, no clue yet. - GPU: Currently only needed for rendering, no clue yet.
- Java 14 (This is really important, we use specific features that are only available in the latest version. Java 8 is **not** supported). - Java 15 (This is really important, we use specific features that are only available in the latest version. Java 8 is **not** supported).
OpenJDK 14 is (of course) also supported. OpenJDK 15 is (of course) also supported.
## Rendering ## Rendering
@ -69,4 +69,13 @@ Many thanks to [Credits](Credits.md).
## Releases and beta ## Releases and beta
We are almost ready to release a beta once !8 is merged. We are almost ready to release a beta once !8 is merged.
## Compiling and running
1. Install Maven and java 15 (On Ubuntu based distributions: `sudo apt install maven openjdk-15-jdk`)
2. Clone this repo (`git clone https://gitlab.bixilon.de/bixilon/minosoft.git`)
3. Change directory (`cd minosoft`)
4. Checkout the branch (`git checkout <branch>`). Probably `render`
5. Run Minosoft with `mvn javafx:run`. If any errors occur, feel free to open an issue. In this early stage it might be helpful
to delete the app data folder (only of minosoft).
This readme is work in progress, things may change over time. This readme is work in progress, things may change over time.

View File

@ -12,6 +12,7 @@ In the root folder of your jar file (the mod) must be a file called `mod.json`.
"Example dev" "Example dev"
], ],
"name": "Example Mod", "name": "Example Mod",
"moddingAPIVersion": 1,
"identifier": "example", "identifier": "example",
"mainClass": "de.example.mod.Main", "mainClass": "de.example.mod.Main",
"loading": { "loading": {
@ -43,7 +44,8 @@ In the root folder of your jar file (the mod) must be a file called `mod.json`.
- `uuid` is a unique id for the mod. Generate 1 and keep it in all versions (used for dependencies, etc). **Required** - `uuid` is a unique id for the mod. Generate 1 and keep it in all versions (used for dependencies, etc). **Required**
- `versionId` like in android there is a numeric version id. It is used to compare between versions (and as identifier). **Required** - `versionId` like in android there is a numeric version id. It is used to compare between versions (and as identifier). **Required**
- `versionName`, `authors`, `name` is the classic implementation of metadata. Can be anything, will be displayed in the mod list. **Required** - `versionName`, `authors`, `name` is the classic implementation of metadata. Can be anything, will be displayed in the mod list. **Required**
- `identifier` is the prefix of items (for Minecraft it is `minecraft`). Aka the thing before the ``. **Required** - `moddingAPIVersion` Modding API version of minosoft. Currently `1` **Required**
- `identifier` is the prefix of items (for Minecraft it is `minecraft`). Aka the thing before the `:`. **Required**
- `mainClass` the Main class of your mod (self explaining). The main class needs to extent the abstract class `MinosoftMod`. **Required** - `mainClass` the Main class of your mod (self explaining). The main class needs to extent the abstract class `MinosoftMod`. **Required**
- `loading` Loading attributes. **Optional** - `loading` Loading attributes. **Optional**
- `priority` should the mod be loaded at the beginning or at the end. Possible values are `LOWEST`, `LOW`, `NORMAL`, `HIGH`, `HIGHEST` **Optional** - `priority` should the mod be loaded at the beginning or at the end. Possible values are `LOWEST`, `LOW`, `NORMAL`, `HIGH`, `HIGHEST` **Optional**
@ -52,8 +54,8 @@ In the root folder of your jar file (the mod) must be a file called `mod.json`.
- `soft` These mods are **optional** to work. Both use the following format: **Optional** - `soft` These mods are **optional** to work. Both use the following format: **Optional**
- `uuid` the uuid of the mod to load. **Required** - `uuid` the uuid of the mod to load. **Required**
- `version` Specifies the version you need to load. **Optional** - `version` Specifies the version you need to load. **Optional**
- `minimum` Minimum versionId required. **Maximum, minimum or both** - `minimum` Minimum versionId required. **Maximum, minimum, both or none**
- `maximum` Maximum versionId required. **Maximum, minimum or both** - `maximum` Maximum versionId required. **Maximum, minimum, both or none**
## Mod loading (aka Main class) ## Mod loading (aka Main class)
Your main class must extend the following class: `de.bixilon.minosoft.MinosoftMod`. Your main class must extend the following class: `de.bixilon.minosoft.MinosoftMod`.

View File

@ -1,4 +1,4 @@
before_install: before_install:
- wget https://github.com/sormuras/bach/raw/master/install-jdk.sh - wget https://github.com/sormuras/bach/raw/master/install-jdk.sh
- source install-jdk.sh --feature 14 - source install-jdk.sh --feature 15
- jshell --version - jshell --version

13
pom.xml
View File

@ -24,8 +24,9 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <version>3.8.1</version>
<configuration> <configuration>
<source>14</source> <source>15</source>
<target>14</target> <target>15</target>
<compilerArgs>--enable-preview</compilerArgs>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
@ -37,9 +38,7 @@
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId> <groupId>org.apache.maven.plugins</groupId>
org.apache.maven.plugins
</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<version>2.3</version> <version>2.3</version>
<configuration> <configuration>
@ -57,8 +56,8 @@
</build> </build>
<properties> <properties>
<maven.compiler.source>14</maven.compiler.source> <maven.compiler.source>15</maven.compiler.source>
<maven.compiler.target>14</maven.compiler.target> <maven.compiler.target>15</maven.compiler.target>
<lwjgl.version>3.2.3</lwjgl.version> <lwjgl.version>3.2.3</lwjgl.version>
</properties> </properties>

View File

@ -33,19 +33,19 @@ public class Configuration {
private final Object lock = new Object(); private final Object lock = new Object();
public Configuration() throws IOException { public Configuration() throws IOException {
File file = new File(StaticConfiguration.homeDir + "config/" + StaticConfiguration.CONFIG_FILENAME); File file = new File(StaticConfiguration.HOME_DIR + "config/" + StaticConfiguration.CONFIG_FILENAME);
if (!file.exists()) { if (!file.exists()) {
// no configuration file // no configuration file
InputStream input = getClass().getResourceAsStream("/config/" + StaticConfiguration.CONFIG_FILENAME); InputStream input = getClass().getResourceAsStream("/config/" + StaticConfiguration.CONFIG_FILENAME);
if (input == null) { if (input == null) {
throw new FileNotFoundException(String.format("[Config] Missing default config: %s!", StaticConfiguration.CONFIG_FILENAME)); throw new FileNotFoundException(String.format("[Config] Missing default config: %s!", StaticConfiguration.CONFIG_FILENAME));
} }
File folder = new File(StaticConfiguration.homeDir + "config/"); File folder = new File(StaticConfiguration.HOME_DIR + "config/");
if (!folder.exists() && !folder.mkdirs()) { if (!folder.exists() && !folder.mkdirs()) {
throw new IOException("[Config] Could not create config folder!"); throw new IOException("[Config] Could not create config folder!");
} }
Files.copy(input, Paths.get(file.getAbsolutePath())); Files.copy(input, Paths.get(file.getAbsolutePath()));
file = new File(StaticConfiguration.homeDir + "config/" + StaticConfiguration.CONFIG_FILENAME); file = new File(StaticConfiguration.HOME_DIR + "config/" + StaticConfiguration.CONFIG_FILENAME);
} }
config = Util.readJsonFromFile(file.getAbsolutePath()); config = Util.readJsonFromFile(file.getAbsolutePath());
int configVersion = getInt(ConfigurationPaths.CONFIG_VERSION); int configVersion = getInt(ConfigurationPaths.CONFIG_VERSION);
@ -67,7 +67,7 @@ public class Configuration {
} }
} }
// write config to temp file, delete original config, rename temp file to original file to avoid conflicts if minosoft gets closed while saving the config // write config to temp file, delete original config, rename temp file to original file to avoid conflicts if minosoft gets closed while saving the config
File tempFile = new File(StaticConfiguration.homeDir + "config/" + StaticConfiguration.CONFIG_FILENAME + ".tmp"); File tempFile = new File(StaticConfiguration.HOME_DIR + "config/" + StaticConfiguration.CONFIG_FILENAME + ".tmp");
Gson gson = new GsonBuilder().setPrettyPrinting().create(); Gson gson = new GsonBuilder().setPrettyPrinting().create();
FileWriter writer; FileWriter writer;
try { try {

View File

@ -23,10 +23,11 @@ public class StaticConfiguration {
public static final boolean COLORED_LOG = true; // the log should be colored with ANSI (does not affect base components) public static final boolean COLORED_LOG = true; // the log should be colored with ANSI (does not affect base components)
public static final boolean LOG_RELATIVE_TIME = false; // prefix all log messages with the relative start time in milliseconds instead of the formatted time public static final boolean LOG_RELATIVE_TIME = false; // prefix all log messages with the relative start time in milliseconds instead of the formatted time
public static String homeDir; public static final String HOME_DIR;
static { static {
// Sets Config.homeDir to the correct folder per OS // Sets Config.homeDir to the correct folder per OS
String homeDir;
homeDir = System.getProperty("user.home"); homeDir = System.getProperty("user.home");
if (!homeDir.endsWith(File.separator)) { if (!homeDir.endsWith(File.separator)) {
homeDir += "/"; homeDir += "/";
@ -42,5 +43,6 @@ public class StaticConfiguration {
// failed creating folder // failed creating folder
throw new RuntimeException(String.format("Could not create home folder (%s)!", homeDir)); throw new RuntimeException(String.format("Could not create home folder (%s)!", homeDir));
} }
HOME_DIR = folder.getAbsolutePath() + "/";
} }
} }

View File

@ -13,22 +13,7 @@
package de.bixilon.minosoft.data; package de.bixilon.minosoft.data;
public class EntityRotation { public record EntityRotation(float yaw, float pitch, float roll) {
final float yaw;
final float pitch;
final float roll;
public EntityRotation(float yaw, float pitch, float roll) {
this.yaw = yaw;
this.pitch = pitch;
this.roll = roll;
}
@Override
public String toString() {
return String.format("%s %s %s", getYaw(), getPitch(), getRoll());
}
public float getYaw() { public float getYaw() {
return yaw; return yaw;
} }
@ -40,4 +25,9 @@ public class EntityRotation {
public float getRoll() { public float getRoll() {
return roll; return roll;
} }
@Override
public String toString() {
return String.format("%s %s %s", yaw, pitch, roll);
}
} }

View File

@ -33,7 +33,7 @@ public class Player {
public final HashMap<UUID, PlayerListItem> playerList = new HashMap<>(); public final HashMap<UUID, PlayerListItem> playerList = new HashMap<>();
final MojangAccount account; final MojangAccount account;
final ScoreboardManager scoreboardManager = new ScoreboardManager(); final ScoreboardManager scoreboardManager = new ScoreboardManager();
final World world = new World("world"); final World world = new World();
final HashMap<Integer, Inventory> inventories = new HashMap<>(); final HashMap<Integer, Inventory> inventories = new HashMap<>();
float health; float health;
int food; int food;

View File

@ -13,26 +13,7 @@
package de.bixilon.minosoft.data; package de.bixilon.minosoft.data;
public class Vector { public record Vector(int x, int y, int z) {
final int x;
final int y;
final int z;
public Vector(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
Vector pos = (Vector) obj;
return pos.getX() == getX() && pos.getY() == getY() && pos.getZ() == getZ();
}
public int getX() { public int getX() {
return x; return x;
} }
@ -47,6 +28,6 @@ public class Vector {
@Override @Override
public String toString() { public String toString() {
return String.format("%s %s %s", getX(), getY(), getZ()); return String.format("%s %s %s", x, y, z);
} }
} }

View File

@ -249,6 +249,6 @@ public class AssetsManager {
} }
private static String getAssetDiskPath(String hash) { private static String getAssetDiskPath(String hash) {
return StaticConfiguration.homeDir + String.format("assets/objects/%s/%s.gz", hash.substring(0, 2), hash); return StaticConfiguration.HOME_DIR + String.format("assets/objects/%s/%s.gz", hash.substring(0, 2), hash);
} }
} }

View File

@ -13,32 +13,7 @@
package de.bixilon.minosoft.data.entities; package de.bixilon.minosoft.data.entities;
import java.util.Objects; public record Location(double x, double y, double z) {
public class Location {
final double x;
final double y;
final double z;
public Location(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
Location that = (Location) obj;
return that.getX() == getX() && that.getY() == getY() && that.getZ() == getZ();
}
@Override
public int hashCode() {
return Objects.hash(x, y, z);
}
public double getX() { public double getX() {
return x; return x;
@ -54,6 +29,6 @@ public class Location {
@Override @Override
public String toString() { public String toString() {
return String.format("%s %s %s", getX(), getY(), getZ()); return String.format("%s %s %s", x, y, z);
} }
} }

View File

@ -13,33 +13,7 @@
package de.bixilon.minosoft.data.entities; package de.bixilon.minosoft.data.entities;
import java.util.Objects; public record RelativeLocation(double x, double y, double z) {
public class RelativeLocation {
final double x;
final double y;
final double z;
public RelativeLocation(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public int hashCode() {
return Objects.hash(x, y, z);
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
RelativeLocation that = (RelativeLocation) obj;
return that.getX() == getX() && that.getY() == getY() && that.getZ() == getZ();
}
public double getX() { public double getX() {
return x; return x;
} }
@ -54,6 +28,6 @@ public class RelativeLocation {
@Override @Override
public String toString() { public String toString() {
return String.format("%s %s %s", getX(), getY(), getZ()); return String.format("%s %s %s", x, y, z);
} }
} }

View File

@ -15,17 +15,7 @@ package de.bixilon.minosoft.data.entities;
import de.bixilon.minosoft.data.mappings.MobEffect; import de.bixilon.minosoft.data.mappings.MobEffect;
public class StatusEffect { public record StatusEffect(MobEffect effect, int amplifier, int duration) {
final MobEffect effect;
final int amplifier;
final int duration;
public StatusEffect(MobEffect effect, int amplifier, int duration) {
this.effect = effect;
this.amplifier = amplifier;
this.duration = duration;
}
public int getAmplifier() { public int getAmplifier() {
return amplifier; return amplifier;
} }

View File

@ -13,26 +13,7 @@
package de.bixilon.minosoft.data.entities; package de.bixilon.minosoft.data.entities;
public class Velocity { public record Velocity(short x, short y, short z) {
final short x;
final short y;
final short z;
public Velocity(short x, short y, short z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
Velocity that = (Velocity) obj;
return that.getX() == getX() && that.getY() == getY() && that.getZ() == getZ();
}
public short getX() { public short getX() {
return x; return x;
} }
@ -47,6 +28,6 @@ public class Velocity {
@Override @Override
public String toString() { public String toString() {
return String.format("%s %s %s", getX(), getY(), getZ()); return String.format("%s %s %s", x, y, z);
} }
} }

View File

@ -16,38 +16,9 @@ package de.bixilon.minosoft.data.entities;
import de.bixilon.minosoft.data.MapSet; import de.bixilon.minosoft.data.MapSet;
import de.bixilon.minosoft.data.VersionValueMap; import de.bixilon.minosoft.data.VersionValueMap;
public class VillagerData { public record VillagerData(VillagerTypes type, VillagerProfessions profession, VillagerLevels level) {
final VillagerTypes type;
final VillagerProfessions profession;
final VillagerLevels level;
public VillagerData(int type, int profession, int level, int versionId) { public VillagerData(int type, int profession, int level, int versionId) {
this.type = VillagerTypes.byId(type); this(VillagerTypes.byId(type), VillagerProfessions.byId(profession, versionId), VillagerLevels.byId(level));
this.profession = VillagerProfessions.byId(profession, versionId);
this.level = VillagerLevels.byId(level);
}
public VillagerData(VillagerTypes type, VillagerProfessions profession, VillagerLevels level) {
this.type = type;
this.profession = profession;
this.level = level;
}
@Override
public int hashCode() {
return type.hashCode() * profession.hashCode() * level.hashCode();
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (hashCode() != obj.hashCode()) {
return false;
}
VillagerData their = (VillagerData) obj;
return getType() == their.getType() && getProfession() == their.getProfession() && getLevel() == their.getLevel();
} }
public VillagerTypes getType() { public VillagerTypes getType() {

View File

@ -26,9 +26,9 @@ public class BedEntityMetaData extends BlockEntityMetaData {
} }
public BedEntityMetaData(NBTTag nbt) { public BedEntityMetaData(NBTTag nbt) {
if (nbt instanceof StringTag) { if (nbt instanceof StringTag stringTag) {
// yes, we support bed rgb colors :D // yes, we support bed rgb colors :D
color = new RGBColor(((StringTag) nbt).getValue()); color = new RGBColor(stringTag.getValue());
return; return;
} }
color = switch (((IntTag) nbt).getValue()) { color = switch (((IntTag) nbt).getValue()) {

View File

@ -309,8 +309,8 @@ public class EntityMetaData {
public boolean getBoolean(int index, boolean defaultValue) { public boolean getBoolean(int index, boolean defaultValue) {
Object ret = get(index, defaultValue); Object ret = get(index, defaultValue);
if (ret instanceof Byte) { if (ret instanceof Byte b) {
return (byte) ret == 0x01; return b == 0x01;
} }
return (boolean) get(index, defaultValue); return (boolean) get(index, defaultValue);
} }

View File

@ -13,15 +13,7 @@
package de.bixilon.minosoft.data.mappings; package de.bixilon.minosoft.data.mappings;
public class BlockId { public record BlockId(String mod, String identifier) {
final String mod;
final String identifier;
public BlockId(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
}
public String getMod() { public String getMod() {
return mod; return mod;
} }
@ -34,21 +26,4 @@ public class BlockId {
public String toString() { public String toString() {
return String.format("%s:%s", getMod(), getIdentifier()); return String.format("%s:%s", getMod(), getIdentifier());
} }
@Override
public int hashCode() {
return mod.hashCode() * identifier.hashCode();
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (hashCode() != obj.hashCode()) {
return false;
}
BlockId their = (BlockId) obj;
return getIdentifier().equals(their.getIdentifier()) && getMod().equals(their.getMod());
}
} }

View File

@ -13,42 +13,17 @@
package de.bixilon.minosoft.data.mappings; package de.bixilon.minosoft.data.mappings;
public class Enchantment { public record Enchantment(String mod, String identifier) {
final String mod; public String getMod() {
final String identifier; return mod;
public Enchantment(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
} }
public String getIdentifier() { public String getIdentifier() {
return identifier; return identifier;
} }
public String getMod() {
return mod;
}
@Override @Override
public String toString() { public String toString() {
return String.format("%s:%s", getMod(), getIdentifier()); return String.format("%s:%s", mod, identifier);
}
@Override
public int hashCode() {
return mod.hashCode() * identifier.hashCode();
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (hashCode() != obj.hashCode()) {
return false;
}
Enchantment their = (Enchantment) obj;
return getIdentifier().equals(their.getIdentifier()) && getMod().equals(their.getMod());
} }
} }

View File

@ -13,15 +13,7 @@
package de.bixilon.minosoft.data.mappings; package de.bixilon.minosoft.data.mappings;
public class MobEffect { public record MobEffect(String mod, String identifier) {
final String mod;
final String identifier;
public MobEffect(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
}
public String getMod() { public String getMod() {
return mod; return mod;
} }
@ -34,21 +26,4 @@ public class MobEffect {
public String toString() { public String toString() {
return String.format("%s:%s", getMod(), getIdentifier()); return String.format("%s:%s", getMod(), getIdentifier());
} }
@Override
public int hashCode() {
return mod.hashCode() * identifier.hashCode();
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (hashCode() != obj.hashCode()) {
return false;
}
MobEffect their = (MobEffect) obj;
return getIdentifier().equals(their.getIdentifier()) && getMod().equals(their.getMod());
}
} }

View File

@ -13,15 +13,7 @@
package de.bixilon.minosoft.data.mappings; package de.bixilon.minosoft.data.mappings;
public class Motive { public record Motive(String mod, String identifier) {
final String mod;
final String identifier;
public Motive(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
}
public String getMod() { public String getMod() {
return mod; return mod;
} }
@ -34,21 +26,4 @@ public class Motive {
public String toString() { public String toString() {
return String.format("%s:%s", getMod(), getIdentifier()); return String.format("%s:%s", getMod(), getIdentifier());
} }
@Override
public int hashCode() {
return mod.hashCode() * identifier.hashCode();
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (hashCode() != obj.hashCode()) {
return false;
}
Motive their = (Motive) obj;
return getIdentifier().equals(their.getIdentifier()) && getMod().equals(their.getMod());
}
} }

View File

@ -13,15 +13,7 @@
package de.bixilon.minosoft.data.mappings.particle; package de.bixilon.minosoft.data.mappings.particle;
public class Particle { public record Particle(String mod, String identifier) {
final String mod;
final String identifier;
public Particle(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
}
public String getMod() { public String getMod() {
return mod; return mod;
} }
@ -32,23 +24,6 @@ public class Particle {
@Override @Override
public String toString() { public String toString() {
return String.format("%s:%s", getMod(), getIdentifier()); return String.format("%s:%s", mod, identifier);
}
@Override
public int hashCode() {
return mod.hashCode() * identifier.hashCode();
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (hashCode() != obj.hashCode()) {
return false;
}
Particle their = (Particle) obj;
return getIdentifier().equals(their.getIdentifier()) && getMod().equals(their.getMod());
} }
} }

View File

@ -15,14 +15,9 @@ package de.bixilon.minosoft.data.mappings.recipes;
import de.bixilon.minosoft.data.inventory.Slot; import de.bixilon.minosoft.data.inventory.Slot;
public class Ingredient { public record Ingredient(Slot[] slot) {
final Slot[] slot;
public Ingredient(Slot[] slot) {
this.slot = slot;
}
public static boolean slotEquals(Slot[] one, Slot[] two) { public static boolean slotEquals(Slot[] one, Slot[] two) {
// ToDo
if (one.length != two.length) { if (one.length != two.length) {
return false; return false;
} }
@ -43,18 +38,6 @@ public class Ingredient {
return false; return false;
} }
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (this.hashCode() != obj.hashCode()) {
return false;
}
Ingredient their = (Ingredient) obj;
return slotEquals(getSlot(), their.getSlot());
}
public Slot[] getSlot() { public Slot[] getSlot() {
return slot; return slot;
} }

View File

@ -13,15 +13,7 @@
package de.bixilon.minosoft.data.mappings.statistics; package de.bixilon.minosoft.data.mappings.statistics;
public class Statistic { public record Statistic(String mod, String identifier) {
final String mod;
final String identifier;
public Statistic(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
}
public String getMod() { public String getMod() {
return mod; return mod;
} }
@ -32,22 +24,6 @@ public class Statistic {
@Override @Override
public String toString() { public String toString() {
return String.format("%s:%s", getMod(), getIdentifier()); return String.format("%s:%s", mod, identifier);
}
@Override
public int hashCode() {
return mod.hashCode() * identifier.hashCode();
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (hashCode() != obj.hashCode()) {
return false;
}
return toString().equals(obj.toString());
} }
} }

View File

@ -128,7 +128,7 @@ public class Versions {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
// check if mapping folder exist // check if mapping folder exist
File mappingFolder = new File(StaticConfiguration.homeDir + "assets/mapping"); File mappingFolder = new File(StaticConfiguration.HOME_DIR + "assets/mapping");
if (!mappingFolder.exists()) { if (!mappingFolder.exists()) {
if (mappingFolder.mkdirs()) { if (mappingFolder.mkdirs()) {
Log.verbose("Created mappings folder."); Log.verbose("Created mappings folder.");
@ -138,7 +138,7 @@ public class Versions {
} }
} }
String fileName = StaticConfiguration.homeDir + String.format("assets/mapping/%s.tar.gz", version.getVersionName()); String fileName = StaticConfiguration.HOME_DIR + String.format("assets/mapping/%s.tar.gz", version.getVersionName());
HashMap<String, JsonObject> files; HashMap<String, JsonObject> files;
try { try {
files = Util.readJsonTarGzFile(fileName); files = Util.readJsonTarGzFile(fileName);

View File

@ -16,29 +16,17 @@ package de.bixilon.minosoft.data.world;
import de.bixilon.minosoft.render.blockModels.Face.RenderConstants; import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
import de.bixilon.minosoft.render.utility.Vec3; import de.bixilon.minosoft.render.utility.Vec3;
import java.util.Objects; public record BlockPosition(int x, int y, int z) {
public BlockPosition(Vec3 vec3) {
public class BlockPosition { this((int) vec3.x, (int) vec3.y, (int) vec3.z);
final int x;
final int y;
final int z;
public BlockPosition(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
} }
public BlockPosition(Vec3 testPosition) { public BlockPosition(ChunkLocation chunkLocation, Byte height, InChunkSectionLocation sectionLocation) {
x = (int) testPosition.x; this((chunkLocation.getX() * RenderConstants.SECTION_WIDTH + sectionLocation.getX()), (chunkLocation.getX() * RenderConstants.SECTION_WIDTH + sectionLocation.getX()), (chunkLocation.getZ() * RenderConstants.SECTION_WIDTH + sectionLocation.getZ()));
y = (short) testPosition.y;
z = (int) testPosition.z;
} }
public BlockPosition(ChunkLocation chunkLocation, Byte height, ChunkNibbleLocation nibbleLocation) { public ChunkLocation getChunkLocation() {
this.x = chunkLocation.getX() * RenderConstants.SECTION_WIDTH + nibbleLocation.getX(); return new ChunkLocation(x / 16, z / 16);
this.y = height * RenderConstants.SECTION_HEIGHT + nibbleLocation.getY();
this.z = chunkLocation.getZ() * RenderConstants.SECTION_WIDTH + nibbleLocation.getZ();
} }
public int getX() { public int getX() {
@ -53,48 +41,21 @@ public class BlockPosition {
return z; return z;
} }
@Override public InChunkLocation getInChunkLocation() {
public int hashCode() { int x = this.x % RenderConstants.SECTION_WIDTH;
return Objects.hash(x, y, z); if (x < 0) {
x += RenderConstants.SECTION_WIDTH;
} }
int z = this.z % RenderConstants.SECTION_WIDTH;
@Override if (z < 0) {
public boolean equals(Object obj) { z += RenderConstants.SECTION_WIDTH;
if (super.equals(obj)) {
return true;
} }
BlockPosition pos = (BlockPosition) obj; return new InChunkLocation(x, this.y, z);
return pos.getX() == getX() && pos.getY() == getY() && pos.getZ() == getZ();
}
public ChunkLocation getChunkLocation() {
int x = getX() / RenderConstants.SECTION_WIDTH;
int z = getZ() / RenderConstants.SECTION_WIDTH;
//ToDo
if (getX() < 0) {
x--;
}
if (getZ() < 0) {
z--;
}
return new ChunkLocation(x, z);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("%d %d %d", getX(), getY(), getZ()); return String.format("%d %d %d", x, y, z);
}
public InChunkLocation getInChunkLocation() {
int x = getX() % RenderConstants.SECTION_WIDTH;
if (x < 0) {
x += RenderConstants.SECTION_WIDTH;
}
int z = getZ() % RenderConstants.SECTION_WIDTH;
if (z < 0) {
z += RenderConstants.SECTION_WIDTH;
}
return new InChunkLocation(x, getY(), z);
} }
public BlockPosition add(int[] ints) { public BlockPosition add(int[] ints) {

View File

@ -21,13 +21,13 @@ import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* Collection of 16 chunks nibbles * Collection of 16 chunks sections
*/ */
public class Chunk { public class Chunk {
final ConcurrentHashMap<Byte, ChunkNibble> nibbles; final ConcurrentHashMap<Byte, ChunkSection> sections;
public Chunk(ConcurrentHashMap<Byte, ChunkNibble> chunks) { public Chunk(ConcurrentHashMap<Byte, ChunkSection> sections) {
this.nibbles = chunks; this.sections = sections;
} }
public Block getBlock(InChunkLocation location) { public Block getBlock(InChunkLocation location) {
@ -36,27 +36,27 @@ public class Chunk {
public Block getBlock(int x, int y, int z) { public Block getBlock(int x, int y, int z) {
byte section = (byte) (y / RenderConstants.SECTION_HEIGHT); byte section = (byte) (y / RenderConstants.SECTION_HEIGHT);
if (!nibbles.containsKey(section)) { if (!sections.containsKey(section)) {
return Blocks.nullBlock; return Blocks.nullBlock;
} }
return nibbles.get(section).getBlock(x, y % RenderConstants.SECTION_HEIGHT, z); return sections.get(section).getBlock(x, y % RenderConstants.SECTION_HEIGHT, z);
} }
public void setBlock(int x, int y, int z, Block block) { public void setBlock(int x, int y, int z, Block block) {
byte section = (byte) (y / RenderConstants.SECTION_HEIGHT); byte section = (byte) (y / RenderConstants.SECTION_HEIGHT);
createSectionIfNotExists(section); createSectionIfNotExists(section);
nibbles.get(section).setBlock(x, y % RenderConstants.SECTION_HEIGHT, z, block); sections.get(section).setBlock(x, y % RenderConstants.SECTION_HEIGHT, z, block);
} }
public void setBlock(InChunkLocation location, Block block) { public void setBlock(InChunkLocation location, Block block) {
byte section = (byte) (location.getY() / RenderConstants.SECTION_HEIGHT); byte section = (byte) (location.getY() / RenderConstants.SECTION_HEIGHT);
createSectionIfNotExists(section); createSectionIfNotExists(section);
nibbles.get(section).setBlock(location.getChunkNibbleLocation(), block); sections.get(section).setBlock(location.getInChunkSectionLocation(), block);
} }
void createSectionIfNotExists(byte section) { void createSectionIfNotExists(byte section) {
if (nibbles.get(section) == null) { if (sections.get(section) == null) {
nibbles.put(section, new ChunkNibble()); sections.put(section, new ChunkSection());
} }
} }
@ -64,7 +64,7 @@ public class Chunk {
blocks.forEach(this::setBlock); blocks.forEach(this::setBlock);
} }
public ConcurrentHashMap<Byte, ChunkNibble> getNibbles() { public ConcurrentHashMap<Byte, ChunkSection> getSections() {
return nibbles; return sections;
} }
} }

View File

@ -13,34 +13,10 @@
package de.bixilon.minosoft.data.world; package de.bixilon.minosoft.data.world;
import java.util.Objects;
/** /**
* Chunk X and Z location (block position / 16, rounded down) * Chunk X and Z location (block position / 16, rounded down)
*/ */
public class ChunkLocation { public record ChunkLocation(int x, int z) {
final int x;
final int z;
public ChunkLocation(int x, int z) {
this.x = x;
this.z = z;
}
@Override
public int hashCode() {
return Objects.hash(x, z);
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
ChunkLocation that = (ChunkLocation) obj;
return getX() == that.getX() && getZ() == that.getZ();
}
public int getX() { public int getX() {
return x; return x;
} }
@ -51,6 +27,6 @@ public class ChunkLocation {
@Override @Override
public String toString() { public String toString() {
return String.format("%d %d", getX(), getZ()); return String.format("%d %d", x, z);
} }
} }

View File

@ -21,31 +21,30 @@ import java.util.concurrent.ConcurrentHashMap;
/** /**
* Collection of 16x16x16 blocks * Collection of 16x16x16 blocks
*/ */
public class ChunkNibble { public class ChunkSection {
final ConcurrentHashMap<ChunkNibbleLocation, Block> blocks; final ConcurrentHashMap<InChunkSectionLocation, Block> blocks;
public ChunkNibble(ConcurrentHashMap<ChunkNibbleLocation, Block> blocks) { public ChunkSection(ConcurrentHashMap<InChunkSectionLocation, Block> blocks) {
this.blocks = blocks; this.blocks = blocks;
} }
public ChunkNibble() { public ChunkSection() {
// empty
this.blocks = new ConcurrentHashMap<>(); this.blocks = new ConcurrentHashMap<>();
} }
public Block getBlock(int x, int y, int z) { public Block getBlock(int x, int y, int z) {
return getBlock(new ChunkNibbleLocation(x, y, z)); return getBlock(new InChunkSectionLocation(x, y, z));
} }
public Block getBlock(ChunkNibbleLocation loc) { public Block getBlock(InChunkSectionLocation loc) {
return blocks.get(loc); return blocks.get(loc);
} }
public void setBlock(int x, int y, int z, Block block) { public void setBlock(int x, int y, int z, Block block) {
setBlock(new ChunkNibbleLocation(x, y, z), block); setBlock(new InChunkSectionLocation(x, y, z), block);
} }
public void setBlock(ChunkNibbleLocation location, Block block) { public void setBlock(InChunkSectionLocation location, Block block) {
if (block == null || block.equals(Blocks.nullBlock)) { if (block == null || block.equals(Blocks.nullBlock)) {
blocks.remove(location); blocks.remove(location);
return; return;
@ -53,7 +52,7 @@ public class ChunkNibble {
blocks.put(location, block); blocks.put(location, block);
} }
public ConcurrentHashMap<ChunkNibbleLocation, Block> getBlocks() { public ConcurrentHashMap<InChunkSectionLocation, Block> getBlocks() {
return blocks; return blocks;
} }
} }

View File

@ -15,31 +15,14 @@ package de.bixilon.minosoft.data.world;
import de.bixilon.minosoft.render.blockModels.Face.RenderConstants; import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
import java.util.Objects; /**
* Chunk X, Y and Z location (max 16x255x16)
public class InChunkLocation { */
final int x; public record InChunkLocation(int x, int y, int z) {
final int y; public InChunkLocation {
final int z; if (x > 15 || y > 255 || z > 15 || x < 0 || y < 0 || z < 0) {
throw new IllegalArgumentException(String.format("Invalid chunk location %s %s %s", x, y, z));
public InChunkLocation(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
} }
@Override
public int hashCode() {
return Objects.hash(x, y, z);
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
InChunkLocation that = (InChunkLocation) obj;
return getX() == that.getX() && getY() == that.getY() && getZ() == that.getZ();
} }
public int getX() { public int getX() {
@ -50,16 +33,16 @@ public class InChunkLocation {
return y; return y;
} }
public ChunkNibbleLocation getChunkNibbleLocation() { public int getZ() {
return new ChunkNibbleLocation(getX(), getY() % RenderConstants.SECTION_HEIGHT, getZ()); return z;
}
public InChunkSectionLocation getInChunkSectionLocation() {
return new InChunkSectionLocation(x, y % RenderConstants.SECTION_HEIGHT, z);
} }
@Override @Override
public String toString() { public String toString() {
return String.format("%d %d %d", getX(), getY(), getZ()); return String.format("%d %d %d", x, y, z);
}
public int getZ() {
return z;
} }
} }

View File

@ -13,36 +13,10 @@
package de.bixilon.minosoft.data.world; package de.bixilon.minosoft.data.world;
import java.util.Objects;
/** /**
* Chunk X, Y and Z location (max 16x16x16) * Chunk X, Y and Z location (max 16x16x16)
*/ */
public class ChunkNibbleLocation { public record InChunkSectionLocation(int x, int y, int z) {
final int x;
final int y;
final int z;
public ChunkNibbleLocation(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public int hashCode() {
return Objects.hash(x, y, z);
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
ChunkNibbleLocation that = (ChunkNibbleLocation) obj;
return getX() == that.getX() && getY() == that.getY() && getZ() == that.getZ();
}
public int getX() { public int getX() {
return x; return x;
} }
@ -57,6 +31,6 @@ public class ChunkNibbleLocation {
@Override @Override
public String toString() { public String toString() {
return String.format("%d %d %d", getX(), getY(), getZ()); return String.format("%d %d %d", x, y, z);
} }
} }

View File

@ -23,35 +23,22 @@ import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* Collection of ChunkColumns * Collection of chunks
*/ */
public class World { public class World {
final ConcurrentHashMap<ChunkLocation, Chunk> chunks = new ConcurrentHashMap<>(); final ConcurrentHashMap<ChunkLocation, Chunk> chunks = new ConcurrentHashMap<>();
final ConcurrentHashMap<Integer, Entity> entities = new ConcurrentHashMap<>(); final ConcurrentHashMap<Integer, Entity> entities = new ConcurrentHashMap<>();
final String name;
final HashMap<BlockPosition, BlockEntityMetaData> blockEntityMeta = new HashMap<>(); final HashMap<BlockPosition, BlockEntityMetaData> blockEntityMeta = new HashMap<>();
boolean hardcore; boolean hardcore;
boolean raining; boolean raining;
Dimension dimension; // used for sky color, etc Dimension dimension; // used for sky color, etc
public World(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Chunk getChunk(ChunkLocation loc) {
return chunks.get(loc);
}
public ConcurrentHashMap<ChunkLocation, Chunk> getAllChunks() { public ConcurrentHashMap<ChunkLocation, Chunk> getAllChunks() {
return chunks; return chunks;
} }
public Block getBlock(BlockPosition pos) { public Block getBlock(BlockPosition pos) {
if (pos.y < 1) { if (pos.getY() < 1) {
return Blocks.nullBlock; return Blocks.nullBlock;
} }
ChunkLocation loc = pos.getChunkLocation(); ChunkLocation loc = pos.getChunkLocation();
@ -133,4 +120,8 @@ public class World {
public void setBlockEntityData(HashMap<BlockPosition, BlockEntityMetaData> blockEntities) { public void setBlockEntityData(HashMap<BlockPosition, BlockEntityMetaData> blockEntities) {
blockEntities.forEach(blockEntityMeta::put); blockEntities.forEach(blockEntityMeta::put);
} }
public Chunk getChunk(ChunkLocation chunkLocation) {
return chunks.get(chunkLocation);
}
} }

View File

@ -421,9 +421,8 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_SERVER_MODDED_BRAND) + ":"), 0, ++column); grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_SERVER_MODDED_BRAND) + ":"), 0, ++column);
grid.add(moddedBrandLabel, 1, column); grid.add(moddedBrandLabel, 1, column);
if (lastPing.getServerModInfo() instanceof ForgeModInfo) { if (lastPing.getServerModInfo() instanceof ForgeModInfo forgeModInfo) {
ForgeModInfo modInfo = (ForgeModInfo) lastPing.getServerModInfo(); Label moddedModsLabel = new Label(forgeModInfo.getModList().toString());
Label moddedModsLabel = new Label(modInfo.getModList().toString());
moddedModsLabel.setWrapText(true); moddedModsLabel.setWrapText(true);
grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_SERVER_MODDED_MOD_LIST) + ":"), 0, ++column); grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_SERVER_MODDED_MOD_LIST) + ":"), 0, ++column);

View File

@ -43,7 +43,7 @@ public class EventMethod {
if (!method.getParameters()[0].getType().isAssignableFrom(event.getClass())) { if (!method.getParameters()[0].getType().isAssignableFrom(event.getClass())) {
return; return;
} }
if (!annotation.ignoreCancelled() && event instanceof CancelableEvent && ((CancelableEvent) event).isCancelled()) { if (!annotation.ignoreCancelled() && event instanceof CancelableEvent cancelableEvent && cancelableEvent.isCancelled()) {
return; return;
} }
try { try {

View File

@ -0,0 +1,110 @@
/*
* Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.modding.loading;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import de.bixilon.minosoft.util.Util;
import java.util.HashSet;
import java.util.UUID;
public class ModDependency {
private final UUID uuid;
private Integer versionMinimum;
private Integer versionMaximum;
public ModDependency(UUID uuid, Integer versionMinimum, Integer versionMaximum) {
this.uuid = uuid;
this.versionMinimum = versionMinimum;
this.versionMaximum = versionMaximum;
}
public ModDependency(UUID uuid) {
this.uuid = uuid;
}
public static ModDependency serialize(JsonObject json) {
UUID uuid = Util.getUUIDFromString(json.get("uuid").getAsString());
Integer versionMinimum = null;
Integer versionMaximum = null;
if (json.has("version")) {
JsonObject version = json.getAsJsonObject("version");
if (version.has("minimum")) {
versionMinimum = version.get("minimum").getAsInt();
}
if (version.has("maximum")) {
versionMaximum = version.get("maximum").getAsInt();
}
}
return new ModDependency(uuid, versionMinimum, versionMaximum);
}
public static HashSet<ModDependency> serializeDependencyArray(JsonArray json) {
HashSet<ModDependency> result = new HashSet<>();
json.forEach((jsonElement -> result.add(serialize(jsonElement.getAsJsonObject()))));
return result;
}
public UUID getUUID() {
return uuid;
}
public Integer getVersionMinimum() {
return versionMinimum;
}
public Integer getVersionMaximum() {
return versionMaximum;
}
@Override
public int hashCode() {
int result = uuid.hashCode();
if (versionMinimum != null && versionMinimum > 0) {
result *= versionMinimum;
}
if (versionMaximum != null && versionMaximum > 0) {
result *= versionMaximum;
}
return result;
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (hashCode() != obj.hashCode()) {
return false;
}
ModDependency their = (ModDependency) obj;
return getUUID().equals(their.getUUID()) && getVersionMaximum().equals(their.getVersionMaximum()) && getVersionMinimum().equals(their.getVersionMinimum());
}
@Override
public String toString() {
String result = uuid.toString();
if (versionMinimum != null) {
result += " >" + versionMinimum;
}
if (versionMaximum != null) {
result += " <" + versionMaximum;
}
return result;
}
}

View File

@ -17,6 +17,7 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import de.bixilon.minosoft.util.Util; import de.bixilon.minosoft.util.Util;
import java.util.HashSet;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -26,11 +27,14 @@ public class ModInfo {
final String versionName; final String versionName;
final String name; final String name;
final String[] authors; final String[] authors;
final int moddingAPIVersion;
final String identifier; final String identifier;
final String mainClass; final String mainClass;
final HashSet<ModDependency> hardDependencies = new HashSet<>();
final HashSet<ModDependency> softDependencies = new HashSet<>();
LoadingInfo loadingInfo; LoadingInfo loadingInfo;
public ModInfo(JsonObject json) { public ModInfo(JsonObject json) throws ModLoadingException {
this.uuid = Util.getUUIDFromString(json.get("uuid").getAsString()); this.uuid = Util.getUUIDFromString(json.get("uuid").getAsString());
this.versionId = json.get("versionId").getAsInt(); this.versionId = json.get("versionId").getAsInt();
this.versionName = json.get("versionName").getAsString(); this.versionName = json.get("versionName").getAsString();
@ -39,6 +43,10 @@ public class ModInfo {
this.authors = new String[authors.size()]; this.authors = new String[authors.size()];
AtomicInteger i = new AtomicInteger(); AtomicInteger i = new AtomicInteger();
authors.forEach((authorElement) -> this.authors[i.getAndIncrement()] = authorElement.getAsString()); authors.forEach((authorElement) -> this.authors[i.getAndIncrement()] = authorElement.getAsString());
moddingAPIVersion = json.get("moddingAPIVersion").getAsInt();
if (moddingAPIVersion > ModLoader.CURRENT_MODDING_API_VERSION) {
throw new ModLoadingException(String.format("Mod was written with for a newer version of minosoft (moddingAPIVersion=%d, expected=%d)", moddingAPIVersion, ModLoader.CURRENT_MODDING_API_VERSION));
}
this.identifier = json.get("identifier").getAsString(); this.identifier = json.get("identifier").getAsString();
this.mainClass = json.get("mainClass").getAsString(); this.mainClass = json.get("mainClass").getAsString();
if (json.has("loading")) { if (json.has("loading")) {
@ -48,6 +56,15 @@ public class ModInfo {
this.loadingInfo.setLoadingPriority(Priorities.valueOf(loading.get("priority").getAsString())); this.loadingInfo.setLoadingPriority(Priorities.valueOf(loading.get("priority").getAsString()));
} }
} }
if (json.has("dependencies")) {
JsonObject dependencies = json.getAsJsonObject("dependencies");
if (dependencies.has("hard")) {
hardDependencies.addAll(ModDependency.serializeDependencyArray(dependencies.getAsJsonArray("hard")));
}
if (dependencies.has("soft")) {
softDependencies.addAll(ModDependency.serializeDependencyArray(dependencies.getAsJsonArray("soft")));
}
}
} }
public String[] getAuthors() { public String[] getAuthors() {

View File

@ -24,63 +24,78 @@ import org.xeustechnologies.jcl.JclObjectFactory;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
public class ModLoader { public class ModLoader {
static final LinkedList<MinosoftMod> mods = new LinkedList<>(); public static final int CURRENT_MODDING_API_VERSION = 1;
public static final LinkedList<MinosoftMod> mods = new LinkedList<>();
public static void loadMods(CountUpAndDownLatch progress) throws Exception { public static void loadMods(CountUpAndDownLatch progress) throws Exception {
Log.verbose("Start loading mods..."); Log.verbose("Start loading mods...");
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), Util.getThreadFactory("ModLoader"));
// load all jars, parse the mod.json // load all jars, parse the mod.json
// sort the list and prioritize // sort the list and prioritize
// load all lists and dependencies async // load all lists and dependencies async
HashSet<Callable<MinosoftMod>> callables = new HashSet<>(); File[] files = new File(StaticConfiguration.HOME_DIR + "mods").listFiles();
File[] files = new File(StaticConfiguration.homeDir + "mods").listFiles();
if (files == null) { if (files == null) {
// no mods to load // no mods to load
return; return;
} }
CountDownLatch latch = new CountDownLatch(files.length);
for (File modFile : files) { for (File modFile : files) {
if (modFile.isDirectory()) { if (modFile.isDirectory()) {
continue; continue;
} }
callables.add(() -> { executor.execute(() -> {
MinosoftMod mod = loadMod(progress, modFile); MinosoftMod mod = loadMod(progress, modFile);
if (mod != null) { if (mod != null) {
mods.add(mod); mods.add(mod);
} }
return mod; latch.countDown();
}); });
} }
latch.await();
Util.executeInThreadPool("ModLoader", callables); if (mods.size() == 0) {
Log.info("No mods to load.");
return;
}
progress.addCount(mods.size() * ModPhases.values().length); // count * mod phases progress.addCount(mods.size() * ModPhases.values().length); // count * mod phases
// sort for priority
mods.sort((a, b) -> { mods.sort((a, b) -> {
if (a == null || b == null) { if (a == null || b == null) {
return 0; return 0;
} }
return -(getLoadingPriorityOrDefault(b.getInfo()).ordinal() - getLoadingPriorityOrDefault(a.getInfo()).ordinal()); return -(getLoadingPriorityOrDefault(b.getInfo()).ordinal() - getLoadingPriorityOrDefault(a.getInfo()).ordinal());
}); });
// ToDo: check dependencies
for (ModPhases phase : ModPhases.values()) { for (ModPhases phase : ModPhases.values()) {
Log.verbose(String.format("Map loading phase changed: %s", phase)); Log.verbose(String.format("Map loading phase changed: %s", phase));
HashSet<Callable<MinosoftMod>> phaseLoaderCallables = new HashSet<>(); CountDownLatch modLatch = new CountDownLatch(mods.size());
mods.forEach((instance) -> phaseLoaderCallables.add(() -> { mods.forEach((instance) -> {
executor.execute(() -> {
if (!instance.isEnabled()) { if (!instance.isEnabled()) {
return instance; modLatch.countDown();
progress.countDown();
return;
} }
if (!instance.start(phase)) { if (!instance.start(phase)) {
Log.warn(String.format("An error occurred while loading %s", instance.getInfo())); Log.warn(String.format("An error occurred while loading %s", instance.getInfo()));
instance.setEnabled(false); instance.setEnabled(false);
} }
modLatch.countDown();
progress.countDown(); progress.countDown();
return instance; });
})); });
Util.executeInThreadPool("ModLoader", phaseLoaderCallables); modLatch.await();
} }
mods.forEach((instance) -> { mods.forEach((instance) -> {
if (instance.isEnabled()) { if (instance.isEnabled()) {
@ -94,6 +109,7 @@ public class ModLoader {
} }
public static MinosoftMod loadMod(CountUpAndDownLatch progress, File file) { public static MinosoftMod loadMod(CountUpAndDownLatch progress, File file) {
MinosoftMod instance;
try { try {
Log.verbose(String.format("[MOD] Loading file %s", file.getAbsolutePath())); Log.verbose(String.format("[MOD] Loading file %s", file.getAbsolutePath()));
progress.countUp(); progress.countUp();
@ -107,18 +123,17 @@ public class ModLoader {
jcl.add(file.getAbsolutePath()); jcl.add(file.getAbsolutePath());
JclObjectFactory factory = JclObjectFactory.getInstance(); JclObjectFactory factory = JclObjectFactory.getInstance();
MinosoftMod instance = (MinosoftMod) factory.create(jcl, modInfo.getMainClass()); instance = (MinosoftMod) factory.create(jcl, modInfo.getMainClass());
instance.setInfo(modInfo); instance.setInfo(modInfo);
Log.verbose(String.format("[MOD] Mod file loaded and added to classpath (%s)", modInfo)); Log.verbose(String.format("[MOD] Mod file loaded and added to classpath (%s)", modInfo));
zipFile.close(); zipFile.close();
progress.countDown(); } catch (IOException | ModLoadingException | NullPointerException e) {
return instance; instance = null;
} catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
Log.warn(String.format("Could not load mod: %s", file.getAbsolutePath())); Log.warn(String.format("Could not load mod: %s", file.getAbsolutePath()));
} }
progress.countDown(); // failed progress.countDown(); // failed
return null; return instance;
} }
private static Priorities getLoadingPriorityOrDefault(ModInfo info) { private static Priorities getLoadingPriorityOrDefault(ModInfo info) {

View File

@ -0,0 +1,35 @@
/*
* Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.modding.loading;
public class ModLoadingException extends Exception {
public ModLoadingException() {
}
public ModLoadingException(String message) {
super(message);
}
public ModLoadingException(String message, Throwable cause) {
super(message, cause);
}
public ModLoadingException(Throwable cause) {
super(cause);
}
public ModLoadingException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -201,8 +201,8 @@ public class Connection {
public boolean fireEvent(ConnectionEvent connectionEvent) { public boolean fireEvent(ConnectionEvent connectionEvent) {
Minosoft.eventManagers.forEach((eventManager -> eventManager.getGlobalEventListeners().forEach((method) -> method.invoke(connectionEvent)))); Minosoft.eventManagers.forEach((eventManager -> eventManager.getGlobalEventListeners().forEach((method) -> method.invoke(connectionEvent))));
eventListeners.forEach((method -> method.invoke(connectionEvent))); eventListeners.forEach((method -> method.invoke(connectionEvent)));
if (connectionEvent instanceof CancelableEvent) { if (connectionEvent instanceof CancelableEvent cancelableEvent) {
return ((CancelableEvent) connectionEvent).isCancelled(); return cancelableEvent.isCancelled();
} }
return false; return false;
} }

View File

@ -125,10 +125,9 @@ public class SocketNetwork implements Network {
outputStream.write(data); outputStream.write(data);
outputStream.flush(); outputStream.flush();
if (packet instanceof PacketEncryptionResponse) { if (packet instanceof PacketEncryptionResponse packetEncryptionResponse) {
// enable encryption // enable encryption
secretKey = ((PacketEncryptionResponse) packet).getSecretKey(); enableEncryption(packetEncryptionResponse.getSecretKey());
enableEncryption(secretKey);
// wake up other thread // wake up other thread
socketRThread.interrupt(); socketRThread.interrupt();
} }
@ -216,8 +215,8 @@ public class SocketNetwork implements Network {
//set special settings to avoid miss timing issues //set special settings to avoid miss timing issues
if (packetInstance instanceof PacketLoginSuccess) { if (packetInstance instanceof PacketLoginSuccess) {
connection.setConnectionState(ConnectionStates.PLAY); connection.setConnectionState(ConnectionStates.PLAY);
} else if (packetInstance instanceof PacketCompressionInterface) { } else if (packetInstance instanceof PacketCompressionInterface compressionPacket) {
compressionThreshold = ((PacketCompressionInterface) packetInstance).getThreshold(); compressionThreshold = compressionPacket.getThreshold();
} else if (packetInstance instanceof PacketEncryptionRequest) { } else if (packetInstance instanceof PacketEncryptionRequest) {
// wait until response is ready // wait until response is ready
connection.handle(packetInstance); connection.handle(packetInstance);

View File

@ -55,8 +55,8 @@ public class WorldRenderer {
queuedMapData.add(() -> prepareChunk(location, chunk)); queuedMapData.add(() -> prepareChunk(location, chunk));
} }
public void queueChunkNibble(ChunkLocation location, byte sectionHeight, ChunkNibble nibble) { public void queueChunkNibble(ChunkLocation location, byte sectionHeight, ChunkSection section) {
queuedMapData.add(() -> prepareChunkNibble(location, sectionHeight, nibble)); queuedMapData.add(() -> prepareChunkNibble(location, sectionHeight, section));
} }
public void queueBlock(BlockPosition position, Block block) { public void queueBlock(BlockPosition position, Block block) {
@ -69,20 +69,20 @@ public class WorldRenderer {
private void prepareChunk(ChunkLocation location, Chunk chunk) { private void prepareChunk(ChunkLocation location, Chunk chunk) {
// clear or create current chunk // clear or create current chunk
ConcurrentHashMap<Byte, ArrayFloatList> chunkFaces = new ConcurrentHashMap<>(); ConcurrentHashMap<Byte, ArrayFloatList> chunkFaces = new ConcurrentHashMap<>();
chunk.getNibbles().forEach(((height, chunkNibble) -> chunkFaces.put(height, getFacesForChunkNibble(location, height, chunkNibble)))); chunk.getSections().forEach(((height, chunkNibble) -> chunkFaces.put(height, getFacesForChunkNibble(location, height, chunkNibble))));
faces.put(location, chunkFaces); faces.put(location, chunkFaces);
} }
private void prepareChunkNibble(ChunkLocation chunkLocation, byte sectionHeight, ChunkNibble nibble) { private void prepareChunkNibble(ChunkLocation chunkLocation, byte sectionHeight, ChunkSection section) {
faces.get(chunkLocation).put(sectionHeight, getFacesForChunkNibble(chunkLocation, sectionHeight, nibble)); faces.get(chunkLocation).put(sectionHeight, getFacesForChunkNibble(chunkLocation, sectionHeight, section));
} }
private ArrayFloatList getFacesForChunkNibble(ChunkLocation chunkLocation, byte sectionHeight, ChunkNibble nibble) { private ArrayFloatList getFacesForChunkNibble(ChunkLocation chunkLocation, byte sectionHeight, ChunkSection section) {
ConcurrentHashMap<ChunkLocation, Chunk> world = connection.getPlayer().getWorld().getAllChunks(); ConcurrentHashMap<ChunkLocation, Chunk> world = connection.getPlayer().getWorld().getAllChunks();
// clear or create current chunk nibble // clear or create current chunk nibble
ArrayFloatList nibbleMap = new ArrayFloatList(); ArrayFloatList nibbleMap = new ArrayFloatList();
//faces.get(chunkLocation).put(sectionHeight, nibbleMap); //faces.get(chunkLocation).put(sectionHeight, nibbleMap);
ConcurrentHashMap<ChunkNibbleLocation, Block> nibbleBlocks = nibble.getBlocks(); ConcurrentHashMap<InChunkSectionLocation, Block> nibbleBlocks = section.getBlocks();
nibbleBlocks.forEach((location, block) -> { nibbleBlocks.forEach((location, block) -> {
HashSet<FaceOrientation> facesToDraw = new HashSet<>(); HashSet<FaceOrientation> facesToDraw = new HashSet<>();
@ -97,12 +97,12 @@ public class WorldRenderer {
} }
// check if block over us is a full block // check if block over us is a full block
byte bottomSection = (byte) (sectionHeight - 1); byte bottomSection = (byte) (sectionHeight - 1);
if (!world.get(chunkLocation).getNibbles().containsKey(bottomSection)) { if (!world.get(chunkLocation).getSections().containsKey(bottomSection)) {
yield null; yield null;
} }
yield world.get(chunkLocation).getNibbles().get(bottomSection).getBlock(location.getX(), RenderConstants.SECTIONS_MAX_Y, location.getZ()); yield world.get(chunkLocation).getSections().get(bottomSection).getBlock(location.getX(), RenderConstants.SECTIONS_MAX_Y, location.getZ());
} }
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY() - 1, location.getZ())); yield nibbleBlocks.get(new InChunkSectionLocation(location.getX(), location.getY() - 1, location.getZ()));
} }
case UP -> { case UP -> {
if (location.getY() == RenderConstants.SECTIONS_MAX_Y) { if (location.getY() == RenderConstants.SECTIONS_MAX_Y) {
@ -113,48 +113,48 @@ public class WorldRenderer {
} }
// check if block over us is a full block // check if block over us is a full block
byte upperSection = (byte) (sectionHeight + 1); byte upperSection = (byte) (sectionHeight + 1);
if (!world.get(chunkLocation).getNibbles().containsKey(upperSection)) { if (!world.get(chunkLocation).getSections().containsKey(upperSection)) {
yield null; yield null;
} }
yield world.get(chunkLocation).getNibbles().get(upperSection).getBlock(location.getX(), RenderConstants.SECTIONS_MIN_Y, location.getZ()); yield world.get(chunkLocation).getSections().get(upperSection).getBlock(location.getX(), RenderConstants.SECTIONS_MIN_Y, location.getZ());
} }
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY() + 1, location.getZ())); yield nibbleBlocks.get(new InChunkSectionLocation(location.getX(), location.getY() + 1, location.getZ()));
} }
case WEST -> { case WEST -> {
if (location.getX() == RenderConstants.SECTIONS_MIN_X) { if (location.getX() == RenderConstants.SECTIONS_MIN_X) {
ChunkNibble otherChunkNibble = getChunkNibbleOfWorld(world, new ChunkLocation(chunkLocation.getX() - 1, chunkLocation.getZ()), sectionHeight); ChunkSection otherChunkNibble = getChunkSectionOfWorld(world, new ChunkLocation(chunkLocation.getX() - 1, chunkLocation.getZ()), sectionHeight);
if (otherChunkNibble != null) { if (otherChunkNibble != null) {
yield otherChunkNibble.getBlock(RenderConstants.SECTIONS_MAX_X, location.getY(), location.getZ()); yield otherChunkNibble.getBlock(RenderConstants.SECTIONS_MAX_X, location.getY(), location.getZ());
} }
} }
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX() - 1, location.getY(), location.getZ())); yield nibbleBlocks.get(new InChunkSectionLocation(location.getX() - 1, location.getY(), location.getZ()));
} }
case EAST -> { case EAST -> {
if (location.getX() == RenderConstants.SECTIONS_MIN_X) { if (location.getX() == RenderConstants.SECTIONS_MIN_X) {
ChunkNibble otherChunkNibble = getChunkNibbleOfWorld(world, new ChunkLocation(chunkLocation.getX() + 1, chunkLocation.getZ()), sectionHeight); ChunkSection otherChunkNibble = getChunkSectionOfWorld(world, new ChunkLocation(chunkLocation.getX() + 1, chunkLocation.getZ()), sectionHeight);
if (otherChunkNibble != null) { if (otherChunkNibble != null) {
yield otherChunkNibble.getBlock(RenderConstants.SECTIONS_MAX_X, location.getY(), location.getZ()); yield otherChunkNibble.getBlock(RenderConstants.SECTIONS_MAX_X, location.getY(), location.getZ());
} }
} }
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX() + 1, location.getY(), location.getZ())); yield nibbleBlocks.get(new InChunkSectionLocation(location.getX() + 1, location.getY(), location.getZ()));
} }
case NORTH -> { case NORTH -> {
if (location.getZ() == RenderConstants.SECTIONS_MIN_Z) { if (location.getZ() == RenderConstants.SECTIONS_MIN_Z) {
ChunkNibble otherChunkNibble = getChunkNibbleOfWorld(world, new ChunkLocation(chunkLocation.getX(), chunkLocation.getZ() - 1), sectionHeight); ChunkSection otherChunkNibble = getChunkSectionOfWorld(world, new ChunkLocation(chunkLocation.getX(), chunkLocation.getZ() - 1), sectionHeight);
if (otherChunkNibble != null) { if (otherChunkNibble != null) {
yield otherChunkNibble.getBlock(location.getX(), location.getY(), RenderConstants.SECTIONS_MAX_Z); yield otherChunkNibble.getBlock(location.getX(), location.getY(), RenderConstants.SECTIONS_MAX_Z);
} }
} }
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY(), location.getZ() - 1)); yield nibbleBlocks.get(new InChunkSectionLocation(location.getX(), location.getY(), location.getZ() - 1));
} }
case SOUTH -> { case SOUTH -> {
if (location.getZ() == RenderConstants.SECTIONS_MAX_Z) { if (location.getZ() == RenderConstants.SECTIONS_MAX_Z) {
ChunkNibble otherChunkNibble = getChunkNibbleOfWorld(world, new ChunkLocation(chunkLocation.getX(), chunkLocation.getZ() + 1), sectionHeight); ChunkSection otherChunkNibble = getChunkSectionOfWorld(world, new ChunkLocation(chunkLocation.getX(), chunkLocation.getZ() + 1), sectionHeight);
if (otherChunkNibble != null) { if (otherChunkNibble != null) {
yield otherChunkNibble.getBlock(location.getX(), location.getY(), RenderConstants.SECTIONS_MIN_Z); yield otherChunkNibble.getBlock(location.getX(), location.getY(), RenderConstants.SECTIONS_MIN_Z);
} }
} }
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY(), location.getZ() + 1)); yield nibbleBlocks.get(new InChunkSectionLocation(location.getX(), location.getY(), location.getZ() + 1));
} }
}; };
if (dependedBlock == null || !BlockModelLoader.getInstance().isFull(dependedBlock, FaceOrientation.inverse(orientation))) { if (dependedBlock == null || !BlockModelLoader.getInstance().isFull(dependedBlock, FaceOrientation.inverse(orientation))) {
@ -185,9 +185,9 @@ public class WorldRenderer {
glEnd(); glEnd();
} }
private ChunkNibble getChunkNibbleOfWorld(ConcurrentHashMap<ChunkLocation, Chunk> world, ChunkLocation location, byte sectionHeight) { private ChunkSection getChunkSectionOfWorld(ConcurrentHashMap<ChunkLocation, Chunk> world, ChunkLocation location, byte sectionHeight) {
if (world.containsKey(location) && world.get(location).getNibbles().containsKey(sectionHeight)) { if (world.containsKey(location) && world.get(location).getSections().containsKey(sectionHeight)) {
return world.get(location).getNibbles().get(sectionHeight); return world.get(location).getSections().get(sectionHeight);
} }
return null; return null;
} }

View File

@ -48,7 +48,7 @@ public class TextureLoader {
} }
combineTextures(); combineTextures();
try { try {
PNGDecoder decoder = new PNGDecoder(new FileInputStream(StaticConfiguration.homeDir + "assets/allTextures.png")); PNGDecoder decoder = new PNGDecoder(new FileInputStream(StaticConfiguration.HOME_DIR + "assets/allTextures.png"));
ByteBuffer buf = ByteBuffer.allocateDirect(decoder.getWidth() * decoder.getHeight() * 4); ByteBuffer buf = ByteBuffer.allocateDirect(decoder.getWidth() * decoder.getHeight() * 4);
decoder.decode(buf, decoder.getWidth() * 4, PNGDecoder.Format.RGBA); decoder.decode(buf, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
textureID = bindTexture(buf, decoder.getWidth(), decoder.getHeight()); textureID = bindTexture(buf, decoder.getWidth(), decoder.getHeight());
@ -118,7 +118,7 @@ public class TextureLoader {
} }
try { try {
File outputFile = new File(StaticConfiguration.homeDir + "assets/allTextures.png"); File outputFile = new File(StaticConfiguration.HOME_DIR + "assets/allTextures.png");
ImageIO.write(totalImage, "png", outputFile); ImageIO.write(totalImage, "png", outputFile);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -16,8 +16,8 @@ package de.bixilon.minosoft.util;
import de.bixilon.minosoft.data.mappings.blocks.Block; import de.bixilon.minosoft.data.mappings.blocks.Block;
import de.bixilon.minosoft.data.mappings.blocks.Blocks; import de.bixilon.minosoft.data.mappings.blocks.Blocks;
import de.bixilon.minosoft.data.world.Chunk; import de.bixilon.minosoft.data.world.Chunk;
import de.bixilon.minosoft.data.world.ChunkNibble; import de.bixilon.minosoft.data.world.ChunkSection;
import de.bixilon.minosoft.data.world.ChunkNibbleLocation; import de.bixilon.minosoft.data.world.InChunkSectionLocation;
import de.bixilon.minosoft.data.world.palette.Palette; import de.bixilon.minosoft.data.world.palette.Palette;
import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
@ -52,11 +52,11 @@ public final class ChunkUtil {
//parse data //parse data
int arrayPos = 0; int arrayPos = 0;
ConcurrentHashMap<Byte, ChunkNibble> nibbleMap = new ConcurrentHashMap<>(); ConcurrentHashMap<Byte, ChunkSection> sectionMap = new ConcurrentHashMap<>();
for (byte c = 0; c < RenderConstants.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column for (byte c = 0; c < RenderConstants.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column
if (BitByte.isBitSet(sectionBitMask, c)) { if (BitByte.isBitSet(sectionBitMask, c)) {
ConcurrentHashMap<ChunkNibbleLocation, Block> blockMap = new ConcurrentHashMap<>(); ConcurrentHashMap<InChunkSectionLocation, Block> blockMap = new ConcurrentHashMap<>();
for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) { for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) { for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) {
@ -84,15 +84,15 @@ public final class ChunkUtil {
arrayPos++; arrayPos++;
continue; continue;
} }
blockMap.put(new ChunkNibbleLocation(nibbleX, nibbleY, nibbleZ), block); blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), block);
arrayPos++; arrayPos++;
} }
} }
} }
nibbleMap.put(c, new ChunkNibble(blockMap)); sectionMap.put(c, new ChunkSection(blockMap));
} }
} }
return new Chunk(nibbleMap); return new Chunk(sectionMap);
} }
if (buffer.getVersionId() < 62) { // ToDo: was this really changed in 62? if (buffer.getVersionId() < 62) { // ToDo: was this really changed in 62?
if (sectionBitMask == 0x00 && groundUpContinuous) { if (sectionBitMask == 0x00 && groundUpContinuous) {
@ -116,12 +116,12 @@ public final class ChunkUtil {
} }
int arrayPos = 0; int arrayPos = 0;
ConcurrentHashMap<Byte, ChunkNibble> nibbleMap = new ConcurrentHashMap<>(); ConcurrentHashMap<Byte, ChunkSection> sectionMap = new ConcurrentHashMap<>();
for (byte c = 0; c < RenderConstants.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column for (byte c = 0; c < RenderConstants.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column
if (!BitByte.isBitSet(sectionBitMask, c)) { if (!BitByte.isBitSet(sectionBitMask, c)) {
continue; continue;
} }
ConcurrentHashMap<ChunkNibbleLocation, Block> blockMap = new ConcurrentHashMap<>(); ConcurrentHashMap<InChunkSectionLocation, Block> blockMap = new ConcurrentHashMap<>();
for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) { for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) { for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) {
@ -132,17 +132,17 @@ public final class ChunkUtil {
arrayPos++; arrayPos++;
continue; continue;
} }
blockMap.put(new ChunkNibbleLocation(nibbleX, nibbleY, nibbleZ), block); blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), block);
arrayPos++; arrayPos++;
} }
} }
} }
nibbleMap.put(c, new ChunkNibble(blockMap)); sectionMap.put(c, new ChunkSection(blockMap));
} }
return new Chunk(nibbleMap); return new Chunk(sectionMap);
} }
// really big thanks to: https://wiki.vg/index.php?title=Chunk_Format&oldid=13712 // really big thanks to: https://wiki.vg/index.php?title=Chunk_Format&oldid=13712
ConcurrentHashMap<Byte, ChunkNibble> nibbleMap = new ConcurrentHashMap<>(); ConcurrentHashMap<Byte, ChunkSection> sectionMap = new ConcurrentHashMap<>();
for (byte c = 0; c < RenderConstants.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column for (byte c = 0; c < RenderConstants.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column
if (!BitByte.isBitSet(sectionBitMask, c)) { if (!BitByte.isBitSet(sectionBitMask, c)) {
continue; continue;
@ -156,7 +156,7 @@ public final class ChunkUtil {
long[] data = buffer.readLongArray(buffer.readVarInt()); long[] data = buffer.readLongArray(buffer.readVarInt());
ConcurrentHashMap<ChunkNibbleLocation, Block> blockMap = new ConcurrentHashMap<>(); ConcurrentHashMap<InChunkSectionLocation, Block> blockMap = new ConcurrentHashMap<>();
for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) { for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) { for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) {
for (int nibbleX = 0; nibbleX < RenderConstants.SECTION_WIDTH; nibbleX++) { for (int nibbleX = 0; nibbleX < RenderConstants.SECTION_WIDTH; nibbleX++) {
@ -188,7 +188,7 @@ public final class ChunkUtil {
if (block.equals(Blocks.nullBlock)) { if (block.equals(Blocks.nullBlock)) {
continue; continue;
} }
blockMap.put(new ChunkNibbleLocation(nibbleX, nibbleY, nibbleZ), block); blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), block);
} }
} }
} }
@ -200,12 +200,12 @@ public final class ChunkUtil {
} }
} }
nibbleMap.put(c, new ChunkNibble(blockMap)); sectionMap.put(c, new ChunkSection(blockMap));
} }
if (buffer.getVersionId() < 552) { if (buffer.getVersionId() < 552) {
byte[] biomes = buffer.readBytes(RenderConstants.SECTION_WIDTH * RenderConstants.SECTION_WIDTH); byte[] biomes = buffer.readBytes(RenderConstants.SECTION_WIDTH * RenderConstants.SECTION_WIDTH);
} }
return new Chunk(nibbleMap); return new Chunk(sectionMap);
} }
public static void readSkyLightPacket(InByteBuffer buffer, int skyLightMask, int blockLightMask, int emptyBlockLightMask, int emptySkyLightMask) { public static void readSkyLightPacket(InByteBuffer buffer, int skyLightMask, int blockLightMask, int emptyBlockLightMask, int emptySkyLightMask) {

View File

@ -26,10 +26,9 @@ import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.*; import java.util.concurrent.ThreadFactory;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.zip.*; import java.util.zip.*;
@ -246,17 +245,6 @@ public final class Util {
return new BufferedInputStream(new URL(url).openStream()); return new BufferedInputStream(new URL(url).openStream());
} }
public static <T> void executeInThreadPool(String name, Collection<Callable<T>> callables) throws InterruptedException {
ExecutorService phaseLoader = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), getThreadFactory(name));
phaseLoader.invokeAll(callables).forEach((tFuture -> {
try {
tFuture.get();
} catch (ExecutionException | InterruptedException ex) {
ex.getCause().printStackTrace();
}
}));
}
public static ThreadFactory getThreadFactory(String threadName) { public static ThreadFactory getThreadFactory(String threadName) {
return new ThreadFactoryBuilder().setNameFormat(threadName + "#%d").build(); return new ThreadFactoryBuilder().setNameFormat(threadName + "#%d").build();
} }

View File

@ -80,9 +80,8 @@ public class CompoundTag extends NBTTag {
buffer.writeStringNoLength(set.getKey()); buffer.writeStringNoLength(set.getKey());
// write data // write data
if (set.getValue() instanceof CompoundTag) { if (set.getValue() instanceof CompoundTag compoundTag) {
// that's a subtag! special rule // that's a subtag! special rule
CompoundTag compoundTag = (CompoundTag) set.getValue();
compoundTag.writeBytesSubTag(buffer); compoundTag.writeBytesSubTag(buffer);
continue; continue;
} }