Merge branch 'world' into proto_1.12.2
This commit is contained in:
@@ -1,12 +0,0 @@
|
|||||||
package mc.core.exception;
|
|
||||||
|
|
||||||
public abstract class McCoreUncheckedException extends RuntimeException {
|
|
||||||
|
|
||||||
public McCoreUncheckedException() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public McCoreUncheckedException(String msg) {
|
|
||||||
super(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package mc.core.exception;
|
package mc.core.exception;
|
||||||
|
|
||||||
public class ResourceUnloadedException extends McCoreUncheckedException {
|
public class ResourceUnloadedException extends RuntimeException {
|
||||||
|
|
||||||
public ResourceUnloadedException(String msg) {
|
public ResourceUnloadedException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ public interface World {
|
|||||||
|
|
||||||
EntityLocation getSpawn();
|
EntityLocation getSpawn();
|
||||||
void setSpawn(EntityLocation location);
|
void setSpawn(EntityLocation location);
|
||||||
|
default void setSpawn(double x, double y, double z, float yaw, float pitch) {
|
||||||
|
setSpawn(new EntityLocation(x, y, z, yaw, pitch));
|
||||||
|
}
|
||||||
|
default void setSpawn(double x, double y, double z) {
|
||||||
|
setSpawn(x, y, z, 0f, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
Chunk getChunk(int x, int z);
|
Chunk getChunk(int x, int z);
|
||||||
void setChunk(int x, int z, Chunk chunkSection);
|
void setChunk(int x, int z, Chunk chunkSection);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package mc.core.world.chunk;
|
package mc.core.world.chunk;
|
||||||
|
|
||||||
import mc.core.world.Biome;
|
import mc.core.world.Biome;
|
||||||
import mc.core.world.World;
|
|
||||||
|
|
||||||
public interface Chunk {
|
public interface Chunk {
|
||||||
int getX();
|
int getX();
|
||||||
@@ -12,7 +11,4 @@ public interface Chunk {
|
|||||||
|
|
||||||
Biome getBiome(int localX, int localZ);
|
Biome getBiome(int localX, int localZ);
|
||||||
void setBiome(int localX, int localZ, Biome biome);
|
void setBiome(int localX, int localZ, Biome biome);
|
||||||
|
|
||||||
World getWorld();
|
|
||||||
void setWorld(World world);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package mc.core.world.chunk;
|
||||||
|
|
||||||
|
public interface ChunkProvider {
|
||||||
|
Chunk getChunk(int x , int z);
|
||||||
|
|
||||||
|
void saveChunk(Chunk chunk);
|
||||||
|
void saveChunk(Chunk... chunks);
|
||||||
|
}
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
package mc.core.world.chunk;
|
package mc.core.world.chunk;
|
||||||
|
|
||||||
import mc.core.world.Biome;
|
import mc.core.world.Biome;
|
||||||
import mc.core.world.World;
|
|
||||||
import mc.core.world.block.Block;
|
import mc.core.world.block.Block;
|
||||||
|
|
||||||
/* 16x16x16 */
|
/* 16x16x16 */
|
||||||
@@ -24,6 +23,4 @@ public interface ChunkSection {
|
|||||||
void setAddition(int x, int y, int z, int value);
|
void setAddition(int x, int y, int z, int value);
|
||||||
|
|
||||||
Biome getBiome(int localX, int localZ);
|
Biome getBiome(int localX, int localZ);
|
||||||
|
|
||||||
World getWorld();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|
||||||
|
|
||||||
class EntityLocationTest {
|
class EntityLocationTest {
|
||||||
private static final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
private static final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||||
@@ -42,6 +41,7 @@ class EntityLocationTest {
|
|||||||
EntityLocation locOrig = new EntityLocation(x, y, z, yaw, pitch);
|
EntityLocation locOrig = new EntityLocation(x, y, z, yaw, pitch);
|
||||||
EntityLocation locClone = locOrig.clone();
|
EntityLocation locClone = locOrig.clone();
|
||||||
assertEquals(locOrig, locClone);
|
assertEquals(locOrig, locClone);
|
||||||
|
assertNotSame(locOrig, locClone);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
# Flat world
|
|
||||||
|
|
||||||
Плоский мир
|
|
||||||
|
|
||||||
## Spring bean
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<bean id="flatWorld" class="mc.world.flat.FlatWorld">
|
|
||||||
<property name="spawn">
|
|
||||||
<bean class="mc.core.Location">
|
|
||||||
<constructor-arg index="0" type="double" value="8"/>
|
|
||||||
<constructor-arg index="1" type="double" value="6"/>
|
|
||||||
<constructor-arg index="2" type="double" value="8"/>
|
|
||||||
</bean>
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
```
|
|
||||||
|
|
||||||
`spawn` - точка спавна
|
|
||||||
@@ -12,6 +12,7 @@ import mc.core.player.PlayerManager;
|
|||||||
import mc.core.player.PlayerSettings;
|
import mc.core.player.PlayerSettings;
|
||||||
import mc.core.world.World;
|
import mc.core.world.World;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -26,8 +27,6 @@ public class H2PlayerManager implements PlayerManager {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private H2PlayerService h2PlayerService;
|
private H2PlayerService h2PlayerService;
|
||||||
private List<H2Player> playerList = Collections.synchronizedList(new ArrayList<>());
|
private List<H2Player> playerList = Collections.synchronizedList(new ArrayList<>());
|
||||||
@Autowired
|
|
||||||
private World world; //FIXME
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Player createPlayer(String name, EntityLocation location, World world) {
|
public Player createPlayer(String name, EntityLocation location, World world) {
|
||||||
@@ -91,25 +90,9 @@ public class H2PlayerManager implements PlayerManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Player getOfflinePlayer(String name) {
|
public Player getOfflinePlayer(String name) {
|
||||||
//TODO похоже в попытке где-то оптимизировать/сэконопить я сам себя ******[обманул]
|
return playerList.stream()
|
||||||
//необходимо этот участок кода переписать
|
|
||||||
//потому как похоже на экономию на спичках
|
|
||||||
H2Player h2Player = playerList.stream()
|
|
||||||
.filter(player -> player.getName().equals(name))
|
.filter(player -> player.getName().equals(name))
|
||||||
.filter(player -> !player.isOnline())
|
.filter(player -> !player.isOnline())
|
||||||
.findFirst().orElse(null);
|
.findFirst().orElseGet(() -> h2PlayerService.getByName(name));
|
||||||
|
|
||||||
if (h2Player == null) {
|
|
||||||
h2Player = h2PlayerService.getByName(name);
|
|
||||||
if (h2Player != null) {
|
|
||||||
h2Player.setWorld(world);
|
|
||||||
return h2Player;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
h2Player.setWorld(world);
|
|
||||||
return h2Player;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
import mc.core.h2db.H2Player;
|
import mc.core.h2db.H2Player;
|
||||||
|
import mc.core.world.World;
|
||||||
import org.hibernate.annotations.GenericGenerator;
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -55,11 +57,7 @@ public class H2PlayerEntity {
|
|||||||
this.locationZ = player.getLocation().getZ();
|
this.locationZ = player.getLocation().getZ();
|
||||||
this.locationYaw = player.getLocation().getYaw();
|
this.locationYaw = player.getLocation().getYaw();
|
||||||
this.locationPitch = player.getLocation().getPitch();
|
this.locationPitch = player.getLocation().getPitch();
|
||||||
if (player.getWorld() != null) { //FIXME
|
|
||||||
this.locationWorld = player.getWorld().getName();
|
this.locationWorld = player.getWorld().getName();
|
||||||
} else {
|
|
||||||
this.locationWorld = "null_world";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUuid(String uuid) {
|
public void setUuid(String uuid) {
|
||||||
@@ -78,12 +76,12 @@ public class H2PlayerEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public H2Player toPlayer() {
|
public H2Player toPlayer(ApplicationContext context) {
|
||||||
H2Player player = new H2Player();
|
H2Player player = new H2Player();
|
||||||
return toPlayer(player);
|
return toPlayer(player, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public H2Player toPlayer(H2Player player) {
|
public H2Player toPlayer(H2Player player, ApplicationContext context) {
|
||||||
player.setId(this.id.intValue());
|
player.setId(this.id.intValue());
|
||||||
player.setUuid(UUID.fromString(this.uuid));
|
player.setUuid(UUID.fromString(this.uuid));
|
||||||
player.setName(this.name);
|
player.setName(this.name);
|
||||||
@@ -97,7 +95,7 @@ public class H2PlayerEntity {
|
|||||||
player.getLocation().setYawPitch(this.locationYaw, this.locationPitch);
|
player.getLocation().setYawPitch(this.locationYaw, this.locationPitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
player.setWorld(null); //FIXME
|
player.setWorld(context.getBean(this.locationWorld, World.class));
|
||||||
|
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ import mc.core.h2db.H2Player;
|
|||||||
import mc.core.h2db.entity.H2PlayerEntity;
|
import mc.core.h2db.entity.H2PlayerEntity;
|
||||||
import mc.core.h2db.repository.H2PlayerEntityRepository;
|
import mc.core.h2db.repository.H2PlayerEntityRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class H2PlayerServiceImpl implements H2PlayerService {
|
public class H2PlayerServiceImpl implements H2PlayerService {
|
||||||
|
@Autowired
|
||||||
|
private ApplicationContext context;
|
||||||
@Autowired
|
@Autowired
|
||||||
private H2PlayerEntityRepository h2PlayerEntityRepository;
|
private H2PlayerEntityRepository h2PlayerEntityRepository;
|
||||||
|
|
||||||
@@ -19,7 +22,7 @@ public class H2PlayerServiceImpl implements H2PlayerService {
|
|||||||
//TODO возможно имеет смысл здесь оптимизация
|
//TODO возможно имеет смысл здесь оптимизация
|
||||||
//вместо toPlayer() сделать toPlayer(H2Player) который в существующий
|
//вместо toPlayer() сделать toPlayer(H2Player) который в существующий
|
||||||
//будет дописывать/обновлять данные
|
//будет дописывать/обновлять данные
|
||||||
return h2PlayerEntityRepository.saveAndFlush(entity).toPlayer(player);
|
return h2PlayerEntityRepository.saveAndFlush(entity).toPlayer(player, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -30,12 +33,12 @@ public class H2PlayerServiceImpl implements H2PlayerService {
|
|||||||
@Override
|
@Override
|
||||||
public H2Player getByName(String name) {
|
public H2Player getByName(String name) {
|
||||||
Optional<H2PlayerEntity> optEntity = h2PlayerEntityRepository.findByName(name);
|
Optional<H2PlayerEntity> optEntity = h2PlayerEntityRepository.findByName(name);
|
||||||
return optEntity.map(H2PlayerEntity::toPlayer).orElse(null);
|
return optEntity.map(entiry -> entiry.toPlayer(context)).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public H2Player getById(int id) {
|
public H2Player getById(int id) {
|
||||||
Optional<H2PlayerEntity> optEntity = h2PlayerEntityRepository.findById((long) id);
|
Optional<H2PlayerEntity> optEntity = h2PlayerEntityRepository.findById((long) id);
|
||||||
return optEntity.map(H2PlayerEntity::toPlayer).orElse(null);
|
return optEntity.map(entiry -> entiry.toPlayer(context)).orElse(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ public class TestSpringConfig {
|
|||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean("mockWorld")
|
||||||
public World mockWorld() {
|
public World mockWorld() {
|
||||||
World mockWorld = mock(World.class);
|
World mockWorld = mock(World.class);
|
||||||
when(mockWorld.getName()).thenReturn("mock_world");
|
when(mockWorld.getName()).thenReturn("mockWorld");
|
||||||
return mockWorld;
|
return mockWorld;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package mc.core.h2db.service;
|
|||||||
import mc.core.EntityLocation;
|
import mc.core.EntityLocation;
|
||||||
import mc.core.h2db.H2Player;
|
import mc.core.h2db.H2Player;
|
||||||
import mc.core.h2db.TestSpringConfig;
|
import mc.core.h2db.TestSpringConfig;
|
||||||
|
import mc.core.world.World;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -21,6 +22,8 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||||||
class H2PlayerServiceTest {
|
class H2PlayerServiceTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
private H2PlayerService h2PlayerService;
|
private H2PlayerService h2PlayerService;
|
||||||
|
@Autowired
|
||||||
|
private World world;
|
||||||
|
|
||||||
private H2Player buildPlayer() {
|
private H2Player buildPlayer() {
|
||||||
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||||
@@ -38,18 +41,26 @@ class H2PlayerServiceTest {
|
|||||||
rnd.nextFloat() * (maxF - minF) + minF,
|
rnd.nextFloat() * (maxF - minF) + minF,
|
||||||
rnd.nextFloat() * (maxF - minF) + minF
|
rnd.nextFloat() * (maxF - minF) + minF
|
||||||
));
|
));
|
||||||
player.setWorld(null); //FIXME
|
player.setWorld(world);
|
||||||
|
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertPlayers(H2Player expected, H2Player actual) {
|
||||||
|
assertEquals(expected, actual);
|
||||||
|
assertEquals(expected.getName(), actual.getName());
|
||||||
|
assertEquals(expected.getLocation(), actual.getLocation());
|
||||||
|
assertNotNull(actual.getWorld());
|
||||||
|
assertEquals(expected.getWorld(), actual.getWorld());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void save() {
|
void save() {
|
||||||
H2Player player = buildPlayer();
|
H2Player player = buildPlayer();
|
||||||
H2Player savedPlayer = h2PlayerService.save(player);
|
H2Player savedPlayer = h2PlayerService.save(player);
|
||||||
|
|
||||||
player.setId(savedPlayer.getId()); //FIXME костыль, однако
|
player.setId(savedPlayer.getId()); //FIXME костыль, однако
|
||||||
assertEquals(player, savedPlayer);
|
assertPlayers(player, savedPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -111,7 +122,7 @@ class H2PlayerServiceTest {
|
|||||||
H2Player player = h2PlayerService.save(buildPlayer());
|
H2Player player = h2PlayerService.save(buildPlayer());
|
||||||
|
|
||||||
H2Player player2 = h2PlayerService.getByName(player.getName());
|
H2Player player2 = h2PlayerService.getByName(player.getName());
|
||||||
assertEquals(player, player2);
|
assertPlayers(player, player2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -134,7 +145,7 @@ class H2PlayerServiceTest {
|
|||||||
H2Player player = h2PlayerService.save(buildPlayer());
|
H2Player player = h2PlayerService.save(buildPlayer());
|
||||||
|
|
||||||
H2Player player2 = h2PlayerService.getById(player.getId());
|
H2Player player2 = h2PlayerService.getById(player.getId());
|
||||||
assertEquals(player, player2);
|
assertPlayers(player, player2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
netStream.writeInt(z); // Chunk Y
|
netStream.writeInt(z); // Chunk Y
|
||||||
netStream.writeBoolean(initChunk); // Init Chunk
|
netStream.writeBoolean(initChunk); // Init Chunk
|
||||||
|
|
||||||
|
int maxH = 0;
|
||||||
if (sectionList == null && chunk != null) {
|
if (sectionList == null && chunk != null) {
|
||||||
int bitMask = 0;
|
int bitMask = 0;
|
||||||
for (int h = 15; h >= 0; h--) {
|
for (int h = 15; h >= 0; h--) {
|
||||||
@@ -107,6 +108,7 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
ChunkSection chunkSection = chunk.getChunkSection(h);
|
ChunkSection chunkSection = chunk.getChunkSection(h);
|
||||||
if (chunkSection != null && chunkSection.getY() == h) {
|
if (chunkSection != null && chunkSection.getY() == h) {
|
||||||
bitMask |= 0x01;
|
bitMask |= 0x01;
|
||||||
|
maxH++;
|
||||||
} else {
|
} else {
|
||||||
bitMask |= 0x00;
|
bitMask |= 0x00;
|
||||||
}
|
}
|
||||||
@@ -121,6 +123,7 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
ChunkSection chunkSection = sectionList.get(i);
|
ChunkSection chunkSection = sectionList.get(i);
|
||||||
if (chunkSection != null && chunkSection.getY() == h) {
|
if (chunkSection != null && chunkSection.getY() == h) {
|
||||||
bitMask |= 0x01;
|
bitMask |= 0x01;
|
||||||
|
maxH++;
|
||||||
} else {
|
} else {
|
||||||
bitMask |= 0x00;
|
bitMask |= 0x00;
|
||||||
}
|
}
|
||||||
@@ -136,7 +139,7 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
int dataItems = 0;
|
int dataItems = 0;
|
||||||
final int airBlockPalette = serializeBlockState(BlockType.AIR);
|
final int airBlockPalette = serializeBlockState(BlockType.AIR);
|
||||||
|
|
||||||
for (int h = 0; h < 16; h++) {
|
for (int h = 0; h < maxH; h++) {
|
||||||
ChunkSection chunkSection = null;
|
ChunkSection chunkSection = null;
|
||||||
|
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
rootProject.name = 'mc-server'
|
rootProject.name = 'mc-server'
|
||||||
|
|
||||||
include('core') // Core
|
include('core') // Core
|
||||||
include('flat_world')
|
include('simple_world')
|
||||||
include('h2_playermanager')
|
include('h2_playermanager')
|
||||||
include('vanilla_commands')
|
include('vanilla_commands')
|
||||||
include('proto_1.12.2') // Protocol 1.12.2
|
include('proto_1.12.2') // Protocol 1.12.2
|
||||||
|
|||||||
39
simple_world/README.MD
Normal file
39
simple_world/README.MD
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Simple world
|
||||||
|
|
||||||
|
Простая реализация мира
|
||||||
|
|
||||||
|
## Spring bean
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<bean id="simpleWorld" class="mc.world.simple.SimpleWorld">
|
||||||
|
<property name="spawn">
|
||||||
|
<bean class="mc.core.EntityLocation">
|
||||||
|
<constructor-arg index="0" type="double" value="8"/>
|
||||||
|
<constructor-arg index="1" type="double" value="6"/>
|
||||||
|
<constructor-arg index="2" type="double" value="8"/>
|
||||||
|
<constructor-arg index="3" type="float" value="0"/>
|
||||||
|
<constructor-arg index="4" type="float" value="0"/>
|
||||||
|
<constructor-arg index="5" type="mc.core.world.World">
|
||||||
|
<null/>
|
||||||
|
</constructor-arg>
|
||||||
|
</bean>
|
||||||
|
</property>
|
||||||
|
<property name="layersBlock">
|
||||||
|
<list value-type="java.lang.String">
|
||||||
|
<value>1;BEDROCK</value>
|
||||||
|
<value>2;DIRT</value>
|
||||||
|
<value>1;GRASS</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
```
|
||||||
|
|
||||||
|
`spawn` - точка спавна.
|
||||||
|
|
||||||
|
При указании точки спавна, указывать шестой параметр `World` не имеет смысла,
|
||||||
|
т.к. `SimpleWorld` всё равно перезапишет этот параметр.
|
||||||
|
|
||||||
|
`layersBlock` - слои блоков.
|
||||||
|
|
||||||
|
В качестве значения указывается спиток строк, каждая из которых описывает слой блоков.
|
||||||
|
Формат строк такой: `кол-во_слоёв;тип_блока`. Порядок строк такой: сверху нижние слои, а снизу - верхние.
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package mc.world.simple;
|
||||||
|
|
||||||
|
import mc.core.world.block.BlockType;
|
||||||
|
import mc.core.world.chunk.Chunk;
|
||||||
|
import mc.core.world.chunk.ChunkProvider;
|
||||||
|
import mc.core.world.chunk.ChunkSection;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FlatChunkProvider implements ChunkProvider {
|
||||||
|
private ChunkSection chunkSection;
|
||||||
|
|
||||||
|
public void setLayersBlockAsString(List<String> listOfLayers) {
|
||||||
|
List<BlockType> layoutsBlock = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String value : listOfLayers) {
|
||||||
|
String[] splitValue = value.split(";");
|
||||||
|
|
||||||
|
BlockType blockType;
|
||||||
|
try {
|
||||||
|
blockType = BlockType.valueOf(splitValue[1]);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Integer.parseInt(splitValue[0]); i++) {
|
||||||
|
layoutsBlock.add(blockType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLayersBlock(layoutsBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLayersBlock(List<BlockType> layoutsBlock) {
|
||||||
|
this.chunkSection = new SimpleChunkSection(layoutsBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk getChunk(int x, int z) {
|
||||||
|
Chunk chunk = new SimpleChunk(x, z);
|
||||||
|
chunk.setChunkSection(0, chunkSection);
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveChunk(Chunk chunk) {
|
||||||
|
//FIXME nope...
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveChunk(Chunk... chunks) {
|
||||||
|
//FIXME nope...
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +1,20 @@
|
|||||||
package mc.world.flat;
|
package mc.world.simple;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import mc.core.world.Biome;
|
import mc.core.world.Biome;
|
||||||
import mc.core.world.World;
|
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.chunk.Chunk;
|
||||||
import mc.core.world.chunk.ChunkSection;
|
import mc.core.world.chunk.ChunkSection;
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class SimpleChunk implements Chunk {
|
public class SimpleChunk implements Chunk {
|
||||||
@Getter
|
@Getter
|
||||||
private int x, z;
|
private final int x, z;
|
||||||
private Reference<World> refWorld;
|
|
||||||
private ChunkSection chunkSection;
|
private ChunkSection chunkSection;
|
||||||
private final Biome biome = Biome.PLAINS;
|
private final Biome biome = Biome.PLAINS;
|
||||||
|
|
||||||
public SimpleChunk(int x, int z, World world) {
|
|
||||||
this.x = x;
|
|
||||||
this.z = z;
|
|
||||||
setWorld(world);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChunkSection getChunkSection(int height) {
|
public ChunkSection getChunkSection(int height) {
|
||||||
return chunkSection;
|
return chunkSection;
|
||||||
@@ -43,19 +34,4 @@ public class SimpleChunk implements Chunk {
|
|||||||
public void setBiome(int localX, int localZ, Biome biome) {
|
public void setBiome(int localX, int localZ, Biome biome) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public World getWorld() {
|
|
||||||
if (refWorld.get() == null) {
|
|
||||||
log.error("World unloaded?");
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return refWorld.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWorld(World world) {
|
|
||||||
this.refWorld = new WeakReference<>(world);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,21 @@
|
|||||||
/*
|
package mc.world.simple;
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2018-04-28
|
|
||||||
*/
|
|
||||||
package mc.world.flat;
|
|
||||||
|
|
||||||
import mc.core.world.Biome;
|
import mc.core.world.Biome;
|
||||||
import mc.core.world.World;
|
|
||||||
import mc.core.world.block.Block;
|
import mc.core.world.block.Block;
|
||||||
import mc.core.world.block.BlockFactory;
|
import mc.core.world.block.BlockFactory;
|
||||||
import mc.core.world.block.BlockType;
|
import mc.core.world.block.BlockType;
|
||||||
import mc.core.world.chunk.ChunkSection;
|
import mc.core.world.chunk.ChunkSection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class SimpleChunkSection implements ChunkSection {
|
public class SimpleChunkSection implements ChunkSection {
|
||||||
|
private final BlockFactory blockFactory = new BlockFactory();
|
||||||
|
private final List<BlockType> layersBlock;
|
||||||
|
|
||||||
|
public SimpleChunkSection(List<BlockType> layersBlock) {
|
||||||
|
this.layersBlock = layersBlock;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z) {
|
public int getSkyLight(int x, int y, int z) {
|
||||||
if (y <= 3) return 0;
|
if (y <= 3) return 0;
|
||||||
@@ -57,16 +61,20 @@ public class SimpleChunkSection implements ChunkSection {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block getBlock(int x, int y, int z) {
|
public Block getBlock(int x, int y, int z) {
|
||||||
BlockFactory blockFactory = new BlockFactory();
|
if (x < 0) x = 0;
|
||||||
|
else if (x > 15) x = 15;
|
||||||
|
if (y < 0) y = 0;
|
||||||
|
else if (y > 15) y = 15;
|
||||||
|
if (z < 0) z = 0;
|
||||||
|
else if (z > 15) z = 15;
|
||||||
|
|
||||||
if (y == 0) return blockFactory.create(BlockType.BEDROCK, x, y, z);
|
if (y >= layersBlock.size()) {
|
||||||
else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, x, y, z);
|
return blockFactory.create(BlockType.AIR, x, y, z);
|
||||||
else if (y == 3) return blockFactory.create(BlockType.GRASS, x, y, z);
|
|
||||||
else return blockFactory.create(BlockType.AIR, x, y, z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
BlockType blockType = layersBlock.get(y);
|
||||||
public World getWorld() {
|
if (blockType == null) return blockFactory.create(BlockType.AIR, x, y, z);
|
||||||
return null;
|
|
||||||
|
return blockFactory.create(blockType, x, y, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
/*
|
package mc.world.simple;
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2018-04-28
|
|
||||||
*/
|
|
||||||
package mc.world.flat;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -11,37 +7,50 @@ import mc.core.EntityLocation;
|
|||||||
import mc.core.world.World;
|
import mc.core.world.World;
|
||||||
import mc.core.world.WorldType;
|
import mc.core.world.WorldType;
|
||||||
import mc.core.world.chunk.Chunk;
|
import mc.core.world.chunk.Chunk;
|
||||||
import mc.core.world.chunk.ChunkSection;
|
import mc.core.world.chunk.ChunkProvider;
|
||||||
|
import org.springframework.beans.factory.BeanNameAware;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class FlatWorld implements World {
|
@Component
|
||||||
|
public class SimpleWorld implements World, BeanNameAware {
|
||||||
@Getter
|
@Getter
|
||||||
private final String name = "flat";
|
private String name;
|
||||||
@Getter
|
@Getter
|
||||||
private final WorldType worldType = WorldType.FLAT;
|
private final WorldType worldType = WorldType.FLAT;
|
||||||
@Setter
|
|
||||||
private EntityLocation spawn;
|
private EntityLocation spawn;
|
||||||
private ChunkSection chunkSection = new SimpleChunkSection();
|
@Setter
|
||||||
|
private ChunkProvider chunkProvider;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityLocation getSpawn() {
|
public EntityLocation getSpawn() {
|
||||||
if (this.spawn == null) {
|
if (this.spawn == null) {
|
||||||
log.warn("Spawn is not defined! Set spawn [0, 6, 0]");
|
log.warn("Spawn is not defined! Set spawn [0, 6, 0]");
|
||||||
this.spawn = new EntityLocation(0d, 6d, 0d, 0f, 0f);
|
setSpawn(0d, 6d, 0d);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.spawn;
|
return this.spawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSpawn(EntityLocation location) {
|
||||||
|
this.spawn = location;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Chunk getChunk(int x, int z) {
|
public Chunk getChunk(int x, int z) {
|
||||||
Chunk chunk = new SimpleChunk(x, z, this);
|
return chunkProvider.getChunk(x, z);
|
||||||
chunk.setChunkSection(0, chunkSection);
|
|
||||||
return chunk;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setChunk(int x, int z, Chunk chunk) {
|
public void setChunk(int x, int z, Chunk chunk) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanName(@Nonnull String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package mc.world.simple;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import mc.core.world.block.Block;
|
||||||
|
import mc.core.world.block.BlockType;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class SimpleChunkSectionTest {
|
||||||
|
private SimpleChunkSection chunkSection;
|
||||||
|
private List<BlockType> layersBlock;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void before() {
|
||||||
|
layersBlock = Lists.newArrayList(
|
||||||
|
BlockType.BEDROCK,
|
||||||
|
BlockType.DIRT,
|
||||||
|
BlockType.DIRT,
|
||||||
|
BlockType.GRASS
|
||||||
|
);
|
||||||
|
|
||||||
|
chunkSection = new SimpleChunkSection(layersBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getBlock() {
|
||||||
|
for (int y = 15; y >= 0; y--) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
Block block = chunkSection.getBlock(x, y, z);
|
||||||
|
if (y > layersBlock.size()-1) {
|
||||||
|
assertEquals(block.getBlockType(), BlockType.AIR);
|
||||||
|
} else {
|
||||||
|
assertEquals(block.getBlockType(), layersBlock.get(y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package mc.world.simple;
|
||||||
|
|
||||||
|
import mc.core.EntityLocation;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@ContextConfiguration(classes = {TestSpringConfig.class})
|
||||||
|
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
|
||||||
|
class SimpleWorldTest {
|
||||||
|
@Autowired
|
||||||
|
private SimpleWorld world;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void spawn() {
|
||||||
|
final EntityLocation location = new EntityLocation(1d, 2d, 3d,4f, 5f);
|
||||||
|
|
||||||
|
world.setSpawn(location);
|
||||||
|
assertEquals(location, world.getSpawn());
|
||||||
|
assertSame(location, world.getSpawn());
|
||||||
|
|
||||||
|
world.setSpawn(1d, 2d, 3d, 4f, 5f);
|
||||||
|
assertEquals(location, world.getSpawn());
|
||||||
|
assertNotSame(location, world.getSpawn());
|
||||||
|
|
||||||
|
location.setYawPitch(0, 0);
|
||||||
|
world.setSpawn(1d, 2d, 3d);
|
||||||
|
assertEquals(location, world.getSpawn());
|
||||||
|
assertNotSame(location, world.getSpawn());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package mc.world.simple;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import mc.core.world.block.BlockType;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan("mc.world.simple")
|
||||||
|
public class TestSpringConfig {
|
||||||
|
@Bean
|
||||||
|
public List<BlockType> layersBlock() {
|
||||||
|
return Lists.newArrayList(
|
||||||
|
BlockType.BEDROCK,
|
||||||
|
BlockType.DIRT,
|
||||||
|
BlockType.DIRT,
|
||||||
|
BlockType.GRASS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SimpleChunkSection chunkSection(List<BlockType> layersBlock) {
|
||||||
|
return new SimpleChunkSection(layersBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SimpleWorld simpleWorld(List<BlockType> layersBlock) {
|
||||||
|
FlatChunkProvider chunkProvider = new FlatChunkProvider();
|
||||||
|
chunkProvider.setLayersBlock(layersBlock);
|
||||||
|
|
||||||
|
SimpleWorld world = new SimpleWorld();
|
||||||
|
world.setChunkProvider(chunkProvider);
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user