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_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:
paths:
@ -14,4 +14,4 @@ stages:
verify:
stage: verify
script:
- 'mvn $MAVEN_CLI_OPTS verify'
- 'mvn $MAVEN_CLI_OPTS verify'

1
.idea/compiler.xml generated
View File

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

2
.idea/misc.xml generated
View File

@ -8,7 +8,7 @@
</list>
</option>
</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" />
</component>
</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).
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.
- Java 14 (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.
- Java 15 (This is really important, we use specific features that are only available in the latest version. Java 8 is **not** supported).
OpenJDK 15 is (of course) also supported.
## Rendering
@ -69,4 +69,13 @@ Many thanks to [Credits](Credits.md).
## Releases and beta
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.

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"
],
"name": "Example Mod",
"moddingAPIVersion": 1,
"identifier": "example",
"mainClass": "de.example.mod.Main",
"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**
- `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**
- `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**
- `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**
@ -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**
- `uuid` the uuid of the mod to load. **Required**
- `version` Specifies the version you need to load. **Optional**
- `minimum` Minimum versionId required. **Maximum, minimum or both**
- `maximum` Maximum versionId required. **Maximum, minimum or both**
- `minimum` Minimum versionId required. **Maximum, minimum, both or none**
- `maximum` Maximum versionId required. **Maximum, minimum, both or none**
## Mod loading (aka Main class)
Your main class must extend the following class: `de.bixilon.minosoft.MinosoftMod`.

View File

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

13
pom.xml
View File

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

View File

@ -33,19 +33,19 @@ public class Configuration {
private final Object lock = new Object();
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()) {
// no configuration file
InputStream input = getClass().getResourceAsStream("/config/" + StaticConfiguration.CONFIG_FILENAME);
if (input == null) {
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()) {
throw new IOException("[Config] Could not create config folder!");
}
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());
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
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();
FileWriter writer;
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 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 {
// Sets Config.homeDir to the correct folder per OS
String homeDir;
homeDir = System.getProperty("user.home");
if (!homeDir.endsWith(File.separator)) {
homeDir += "/";
@ -42,5 +43,6 @@ public class StaticConfiguration {
// failed creating folder
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;
public class EntityRotation {
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 record EntityRotation(float yaw, float pitch, float roll) {
public float getYaw() {
return yaw;
}
@ -40,4 +25,9 @@ public class EntityRotation {
public float getRoll() {
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<>();
final MojangAccount account;
final ScoreboardManager scoreboardManager = new ScoreboardManager();
final World world = new World("world");
final World world = new World();
final HashMap<Integer, Inventory> inventories = new HashMap<>();
float health;
int food;

View File

@ -13,26 +13,7 @@
package de.bixilon.minosoft.data;
public class Vector {
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 record Vector(int x, int y, int z) {
public int getX() {
return x;
}
@ -47,6 +28,6 @@ public class Vector {
@Override
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) {
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;
import java.util.Objects;
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 record Location(double x, double y, double z) {
public double getX() {
return x;
@ -54,6 +29,6 @@ public class Location {
@Override
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;
import java.util.Objects;
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 record RelativeLocation(double x, double y, double z) {
public double getX() {
return x;
}
@ -54,6 +28,6 @@ public class RelativeLocation {
@Override
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;
public class StatusEffect {
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 record StatusEffect(MobEffect effect, int amplifier, int duration) {
public int getAmplifier() {
return amplifier;
}

View File

@ -13,26 +13,7 @@
package de.bixilon.minosoft.data.entities;
public class Velocity {
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 record Velocity(short x, short y, short z) {
public short getX() {
return x;
}
@ -47,6 +28,6 @@ public class Velocity {
@Override
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.VersionValueMap;
public class VillagerData {
final VillagerTypes type;
final VillagerProfessions profession;
final VillagerLevels level;
public record VillagerData(VillagerTypes type, VillagerProfessions profession, VillagerLevels level) {
public VillagerData(int type, int profession, int level, int versionId) {
this.type = VillagerTypes.byId(type);
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();
this(VillagerTypes.byId(type), VillagerProfessions.byId(profession, versionId), VillagerLevels.byId(level));
}
public VillagerTypes getType() {

View File

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

View File

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

View File

@ -13,15 +13,7 @@
package de.bixilon.minosoft.data.mappings;
public class BlockId {
final String mod;
final String identifier;
public BlockId(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
}
public record BlockId(String mod, String identifier) {
public String getMod() {
return mod;
}
@ -34,21 +26,4 @@ public class BlockId {
public String toString() {
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;
public class Enchantment {
final String mod;
final String identifier;
public Enchantment(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
public record Enchantment(String mod, String identifier) {
public String getMod() {
return mod;
}
public String getIdentifier() {
return identifier;
}
public String getMod() {
return mod;
}
@Override
public String toString() {
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;
}
Enchantment their = (Enchantment) obj;
return getIdentifier().equals(their.getIdentifier()) && getMod().equals(their.getMod());
return String.format("%s:%s", mod, identifier);
}
}

View File

@ -13,15 +13,7 @@
package de.bixilon.minosoft.data.mappings;
public class MobEffect {
final String mod;
final String identifier;
public MobEffect(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
}
public record MobEffect(String mod, String identifier) {
public String getMod() {
return mod;
}
@ -34,21 +26,4 @@ public class MobEffect {
public String toString() {
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;
public class Motive {
final String mod;
final String identifier;
public Motive(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
}
public record Motive(String mod, String identifier) {
public String getMod() {
return mod;
}
@ -34,21 +26,4 @@ public class Motive {
public String toString() {
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;
public class Particle {
final String mod;
final String identifier;
public Particle(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
}
public record Particle(String mod, String identifier) {
public String getMod() {
return mod;
}
@ -32,23 +24,6 @@ public class Particle {
@Override
public String toString() {
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;
}
Particle their = (Particle) obj;
return getIdentifier().equals(their.getIdentifier()) && getMod().equals(their.getMod());
return String.format("%s:%s", mod, identifier);
}
}

View File

@ -15,14 +15,9 @@ package de.bixilon.minosoft.data.mappings.recipes;
import de.bixilon.minosoft.data.inventory.Slot;
public class Ingredient {
final Slot[] slot;
public Ingredient(Slot[] slot) {
this.slot = slot;
}
public record Ingredient(Slot[] slot) {
public static boolean slotEquals(Slot[] one, Slot[] two) {
// ToDo
if (one.length != two.length) {
return false;
}
@ -43,18 +38,6 @@ public class Ingredient {
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() {
return slot;
}

View File

@ -13,15 +13,7 @@
package de.bixilon.minosoft.data.mappings.statistics;
public class Statistic {
final String mod;
final String identifier;
public Statistic(String mod, String identifier) {
this.mod = mod;
this.identifier = identifier;
}
public record Statistic(String mod, String identifier) {
public String getMod() {
return mod;
}
@ -32,22 +24,6 @@ public class Statistic {
@Override
public String toString() {
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;
}
return toString().equals(obj.toString());
return String.format("%s:%s", mod, identifier);
}
}

View File

@ -128,7 +128,7 @@ public class Versions {
long startTime = System.currentTimeMillis();
// 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.mkdirs()) {
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;
try {
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.utility.Vec3;
import java.util.Objects;
public class BlockPosition {
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 record BlockPosition(int x, int y, int z) {
public BlockPosition(Vec3 vec3) {
this((int) vec3.x, (int) vec3.y, (int) vec3.z);
}
public BlockPosition(Vec3 testPosition) {
x = (int) testPosition.x;
y = (short) testPosition.y;
z = (int) testPosition.z;
public BlockPosition(ChunkLocation chunkLocation, Byte height, InChunkSectionLocation sectionLocation) {
this((chunkLocation.getX() * RenderConstants.SECTION_WIDTH + sectionLocation.getX()), (chunkLocation.getX() * RenderConstants.SECTION_WIDTH + sectionLocation.getX()), (chunkLocation.getZ() * RenderConstants.SECTION_WIDTH + sectionLocation.getZ()));
}
public BlockPosition(ChunkLocation chunkLocation, Byte height, ChunkNibbleLocation nibbleLocation) {
this.x = chunkLocation.getX() * RenderConstants.SECTION_WIDTH + nibbleLocation.getX();
this.y = height * RenderConstants.SECTION_HEIGHT + nibbleLocation.getY();
this.z = chunkLocation.getZ() * RenderConstants.SECTION_WIDTH + nibbleLocation.getZ();
public ChunkLocation getChunkLocation() {
return new ChunkLocation(x / 16, z / 16);
}
public int getX() {
@ -53,48 +41,21 @@ public class BlockPosition {
return z;
}
@Override
public int hashCode() {
return Objects.hash(x, y, z);
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
public InChunkLocation getInChunkLocation() {
int x = this.x % RenderConstants.SECTION_WIDTH;
if (x < 0) {
x += RenderConstants.SECTION_WIDTH;
}
BlockPosition pos = (BlockPosition) obj;
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--;
int z = this.z % RenderConstants.SECTION_WIDTH;
if (z < 0) {
z += RenderConstants.SECTION_WIDTH;
}
if (getZ() < 0) {
z--;
}
return new ChunkLocation(x, z);
return new InChunkLocation(x, this.y, z);
}
@Override
public String toString() {
return String.format("%d %d %d", getX(), getY(), getZ());
}
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);
return String.format("%d %d %d", x, y, z);
}
public BlockPosition add(int[] ints) {

View File

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

View File

@ -13,34 +13,10 @@
package de.bixilon.minosoft.data.world;
import java.util.Objects;
/**
* Chunk X and Z location (block position / 16, rounded down)
*/
public class ChunkLocation {
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 record ChunkLocation(int x, int z) {
public int getX() {
return x;
}
@ -51,6 +27,6 @@ public class ChunkLocation {
@Override
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
*/
public class ChunkNibble {
final ConcurrentHashMap<ChunkNibbleLocation, Block> blocks;
public class ChunkSection {
final ConcurrentHashMap<InChunkSectionLocation, Block> blocks;
public ChunkNibble(ConcurrentHashMap<ChunkNibbleLocation, Block> blocks) {
public ChunkSection(ConcurrentHashMap<InChunkSectionLocation, Block> blocks) {
this.blocks = blocks;
}
public ChunkNibble() {
// empty
public ChunkSection() {
this.blocks = new ConcurrentHashMap<>();
}
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);
}
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)) {
blocks.remove(location);
return;
@ -53,7 +52,7 @@ public class ChunkNibble {
blocks.put(location, block);
}
public ConcurrentHashMap<ChunkNibbleLocation, Block> getBlocks() {
public ConcurrentHashMap<InChunkSectionLocation, Block> getBlocks() {
return blocks;
}
}

View File

@ -15,31 +15,14 @@ package de.bixilon.minosoft.data.world;
import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
import java.util.Objects;
public class InChunkLocation {
final int x;
final int y;
final int 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;
/**
* Chunk X, Y and Z location (max 16x255x16)
*/
public record InChunkLocation(int x, int y, int z) {
public InChunkLocation {
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));
}
InChunkLocation that = (InChunkLocation) obj;
return getX() == that.getX() && getY() == that.getY() && getZ() == that.getZ();
}
public int getX() {
@ -50,16 +33,16 @@ public class InChunkLocation {
return y;
}
public ChunkNibbleLocation getChunkNibbleLocation() {
return new ChunkNibbleLocation(getX(), getY() % RenderConstants.SECTION_HEIGHT, getZ());
public int getZ() {
return z;
}
public InChunkSectionLocation getInChunkSectionLocation() {
return new InChunkSectionLocation(x, y % RenderConstants.SECTION_HEIGHT, z);
}
@Override
public String toString() {
return String.format("%d %d %d", getX(), getY(), getZ());
}
public int getZ() {
return z;
return String.format("%d %d %d", x, y, z);
}
}

View File

@ -13,36 +13,10 @@
package de.bixilon.minosoft.data.world;
import java.util.Objects;
/**
* Chunk X, Y and Z location (max 16x16x16)
*/
public class ChunkNibbleLocation {
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 record InChunkSectionLocation(int x, int y, int z) {
public int getX() {
return x;
}
@ -57,6 +31,6 @@ public class ChunkNibbleLocation {
@Override
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;
/**
* Collection of ChunkColumns
* Collection of chunks
*/
public class World {
final ConcurrentHashMap<ChunkLocation, Chunk> chunks = new ConcurrentHashMap<>();
final ConcurrentHashMap<Integer, Entity> entities = new ConcurrentHashMap<>();
final String name;
final HashMap<BlockPosition, BlockEntityMetaData> blockEntityMeta = new HashMap<>();
boolean hardcore;
boolean raining;
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() {
return chunks;
}
public Block getBlock(BlockPosition pos) {
if (pos.y < 1) {
if (pos.getY() < 1) {
return Blocks.nullBlock;
}
ChunkLocation loc = pos.getChunkLocation();
@ -133,4 +120,8 @@ public class World {
public void setBlockEntityData(HashMap<BlockPosition, BlockEntityMetaData> blockEntities) {
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(moddedBrandLabel, 1, column);
if (lastPing.getServerModInfo() instanceof ForgeModInfo) {
ForgeModInfo modInfo = (ForgeModInfo) lastPing.getServerModInfo();
Label moddedModsLabel = new Label(modInfo.getModList().toString());
if (lastPing.getServerModInfo() instanceof ForgeModInfo forgeModInfo) {
Label moddedModsLabel = new Label(forgeModInfo.getModList().toString());
moddedModsLabel.setWrapText(true);
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())) {
return;
}
if (!annotation.ignoreCancelled() && event instanceof CancelableEvent && ((CancelableEvent) event).isCancelled()) {
if (!annotation.ignoreCancelled() && event instanceof CancelableEvent cancelableEvent && cancelableEvent.isCancelled()) {
return;
}
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 de.bixilon.minosoft.util.Util;
import java.util.HashSet;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
@ -26,11 +27,14 @@ public class ModInfo {
final String versionName;
final String name;
final String[] authors;
final int moddingAPIVersion;
final String identifier;
final String mainClass;
final HashSet<ModDependency> hardDependencies = new HashSet<>();
final HashSet<ModDependency> softDependencies = new HashSet<>();
LoadingInfo loadingInfo;
public ModInfo(JsonObject json) {
public ModInfo(JsonObject json) throws ModLoadingException {
this.uuid = Util.getUUIDFromString(json.get("uuid").getAsString());
this.versionId = json.get("versionId").getAsInt();
this.versionName = json.get("versionName").getAsString();
@ -39,6 +43,10 @@ public class ModInfo {
this.authors = new String[authors.size()];
AtomicInteger i = new AtomicInteger();
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.mainClass = json.get("mainClass").getAsString();
if (json.has("loading")) {
@ -48,6 +56,15 @@ public class ModInfo {
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() {

View File

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

View File

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

View File

@ -55,8 +55,8 @@ public class WorldRenderer {
queuedMapData.add(() -> prepareChunk(location, chunk));
}
public void queueChunkNibble(ChunkLocation location, byte sectionHeight, ChunkNibble nibble) {
queuedMapData.add(() -> prepareChunkNibble(location, sectionHeight, nibble));
public void queueChunkNibble(ChunkLocation location, byte sectionHeight, ChunkSection section) {
queuedMapData.add(() -> prepareChunkNibble(location, sectionHeight, section));
}
public void queueBlock(BlockPosition position, Block block) {
@ -69,20 +69,20 @@ public class WorldRenderer {
private void prepareChunk(ChunkLocation location, Chunk chunk) {
// clear or create current chunk
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);
}
private void prepareChunkNibble(ChunkLocation chunkLocation, byte sectionHeight, ChunkNibble nibble) {
faces.get(chunkLocation).put(sectionHeight, getFacesForChunkNibble(chunkLocation, sectionHeight, nibble));
private void prepareChunkNibble(ChunkLocation chunkLocation, byte sectionHeight, ChunkSection section) {
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();
// clear or create current chunk nibble
ArrayFloatList nibbleMap = new ArrayFloatList();
//faces.get(chunkLocation).put(sectionHeight, nibbleMap);
ConcurrentHashMap<ChunkNibbleLocation, Block> nibbleBlocks = nibble.getBlocks();
ConcurrentHashMap<InChunkSectionLocation, Block> nibbleBlocks = section.getBlocks();
nibbleBlocks.forEach((location, block) -> {
HashSet<FaceOrientation> facesToDraw = new HashSet<>();
@ -97,12 +97,12 @@ public class WorldRenderer {
}
// check if block over us is a full block
byte bottomSection = (byte) (sectionHeight - 1);
if (!world.get(chunkLocation).getNibbles().containsKey(bottomSection)) {
if (!world.get(chunkLocation).getSections().containsKey(bottomSection)) {
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 -> {
if (location.getY() == RenderConstants.SECTIONS_MAX_Y) {
@ -113,48 +113,48 @@ public class WorldRenderer {
}
// check if block over us is a full block
byte upperSection = (byte) (sectionHeight + 1);
if (!world.get(chunkLocation).getNibbles().containsKey(upperSection)) {
if (!world.get(chunkLocation).getSections().containsKey(upperSection)) {
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 -> {
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) {
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 -> {
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) {
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 -> {
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) {
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 -> {
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) {
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))) {
@ -185,9 +185,9 @@ public class WorldRenderer {
glEnd();
}
private ChunkNibble getChunkNibbleOfWorld(ConcurrentHashMap<ChunkLocation, Chunk> world, ChunkLocation location, byte sectionHeight) {
if (world.containsKey(location) && world.get(location).getNibbles().containsKey(sectionHeight)) {
return world.get(location).getNibbles().get(sectionHeight);
private ChunkSection getChunkSectionOfWorld(ConcurrentHashMap<ChunkLocation, Chunk> world, ChunkLocation location, byte sectionHeight) {
if (world.containsKey(location) && world.get(location).getSections().containsKey(sectionHeight)) {
return world.get(location).getSections().get(sectionHeight);
}
return null;
}

View File

@ -48,7 +48,7 @@ public class TextureLoader {
}
combineTextures();
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);
decoder.decode(buf, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
textureID = bindTexture(buf, decoder.getWidth(), decoder.getHeight());
@ -118,7 +118,7 @@ public class TextureLoader {
}
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);
} catch (IOException e) {
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.Blocks;
import de.bixilon.minosoft.data.world.Chunk;
import de.bixilon.minosoft.data.world.ChunkNibble;
import de.bixilon.minosoft.data.world.ChunkNibbleLocation;
import de.bixilon.minosoft.data.world.ChunkSection;
import de.bixilon.minosoft.data.world.InChunkSectionLocation;
import de.bixilon.minosoft.data.world.palette.Palette;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
@ -52,11 +52,11 @@ public final class ChunkUtil {
//parse data
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
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 nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) {
@ -84,15 +84,15 @@ public final class ChunkUtil {
arrayPos++;
continue;
}
blockMap.put(new ChunkNibbleLocation(nibbleX, nibbleY, nibbleZ), block);
blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), block);
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 (sectionBitMask == 0x00 && groundUpContinuous) {
@ -116,12 +116,12 @@ public final class ChunkUtil {
}
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
if (!BitByte.isBitSet(sectionBitMask, c)) {
continue;
}
ConcurrentHashMap<ChunkNibbleLocation, Block> blockMap = new ConcurrentHashMap<>();
ConcurrentHashMap<InChunkSectionLocation, Block> blockMap = new ConcurrentHashMap<>();
for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) {
@ -132,17 +132,17 @@ public final class ChunkUtil {
arrayPos++;
continue;
}
blockMap.put(new ChunkNibbleLocation(nibbleX, nibbleY, nibbleZ), block);
blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), block);
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
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
if (!BitByte.isBitSet(sectionBitMask, c)) {
continue;
@ -156,7 +156,7 @@ public final class ChunkUtil {
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 nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) {
for (int nibbleX = 0; nibbleX < RenderConstants.SECTION_WIDTH; nibbleX++) {
@ -188,7 +188,7 @@ public final class ChunkUtil {
if (block.equals(Blocks.nullBlock)) {
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) {
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) {

View File

@ -26,10 +26,9 @@ import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.concurrent.ThreadFactory;
import java.util.regex.Pattern;
import java.util.zip.*;
@ -246,17 +245,6 @@ public final class Util {
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) {
return new ThreadFactoryBuilder().setNameFormat(threadName + "#%d").build();
}

View File

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