Began work on integrating the new Contexts. Compiles but does not work
- All TickContexts including TickContextMutable are deleted - Previous occurrences of TickContexts are replaced by appropriate ServerContexts - Added Context.popAndReturn methods for convenience Current known problems: - World does not generate properly on startup - No bulk methods in the new API (the likes of forEachTile, etc.) - AbsFace/RelFace ambiguity in the new API (see TestTileLogicGrass.java:68) - TestTileLogicGrass.java:53 is disabled for some reason
This commit is contained in:
parent
5fb4c601ff
commit
0a45613e45
@ -136,4 +136,24 @@ public interface Context {
|
||||
*/
|
||||
void pop();
|
||||
|
||||
default <T> T popAndReturn(T result) {
|
||||
pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
default boolean popAndReturn(boolean result) {
|
||||
pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
default int popAndReturn(int result) {
|
||||
pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
default float popAndReturn(float result) {
|
||||
pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,9 @@ import ru.windcorp.progressia.server.management.load.ChunkRequestDaemon;
|
||||
import ru.windcorp.progressia.server.management.load.EntityRequestDaemon;
|
||||
import ru.windcorp.progressia.server.management.load.LoadManager;
|
||||
import ru.windcorp.progressia.server.world.DefaultWorldLogic;
|
||||
import ru.windcorp.progressia.server.world.context.ServerWorldContext;
|
||||
import ru.windcorp.progressia.server.world.context.impl.DefaultServerContext;
|
||||
import ru.windcorp.progressia.server.world.context.impl.ReportingServerContext;
|
||||
import ru.windcorp.progressia.server.world.tasks.WorldAccessor;
|
||||
import ru.windcorp.progressia.server.world.ticking.Change;
|
||||
import ru.windcorp.progressia.server.world.ticking.Evaluation;
|
||||
@ -97,6 +100,19 @@ public class Server {
|
||||
return world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates and returns an new {@link ServerWorldContext} instance
|
||||
* suitable for read and write access to the server's world. This is the
|
||||
* preferred way to query or change the world.
|
||||
*
|
||||
* @return the context
|
||||
*/
|
||||
public ServerWorldContext createContext() {
|
||||
|
||||
return new ReportingServerContext(DefaultServerContext.empty().inRealWorldOf(this).build()).withListener(worldAccessor);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this server's {@link ClientManager}. Use this to deal with
|
||||
* communications, e.g. send packets.
|
||||
@ -219,16 +235,20 @@ public class Server {
|
||||
return this.serverThread.getTicker().getUptimeTicks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link WorldAccessor} object for this server. Use the
|
||||
* provided accessor to request common {@link Evaluation}s and
|
||||
* {@link Change}s.
|
||||
*
|
||||
* @return a {@link WorldAccessor}
|
||||
* @see #requestChange(Change)
|
||||
* @see #requestEvaluation(Evaluation)
|
||||
*/
|
||||
public WorldAccessor getWorldAccessor() {
|
||||
// /**
|
||||
// * Returns the {@link WorldAccessor} object for this server. Use the
|
||||
// * provided accessor to request common {@link Evaluation}s and
|
||||
// * {@link Change}s.
|
||||
// *
|
||||
// * @return a {@link WorldAccessor}
|
||||
// * @see #requestChange(Change)
|
||||
// * @see #requestEvaluation(Evaluation)
|
||||
// */
|
||||
// public WorldAccessor getWorldAccessor() {
|
||||
// return worldAccessor;
|
||||
// }
|
||||
|
||||
public WorldAccessor getWorldAccessor___really_bad_dont_use() {
|
||||
return worldAccessor;
|
||||
}
|
||||
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.server.world;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.world.DefaultChunkData;
|
||||
import ru.windcorp.progressia.common.world.generic.GenericChunks;
|
||||
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||
import ru.windcorp.progressia.server.world.block.BlockTickContext;
|
||||
|
||||
public interface ChunkTickContext extends TickContext {
|
||||
|
||||
Vec3i getChunk();
|
||||
|
||||
default DefaultChunkLogic getChunkLogic() {
|
||||
return getWorld().getChunk(getChunk());
|
||||
}
|
||||
|
||||
default DefaultChunkData getChunkData() {
|
||||
DefaultChunkLogic chunkLogic = getChunkLogic();
|
||||
return chunkLogic == null ? null : chunkLogic.getData();
|
||||
}
|
||||
|
||||
default AbsFace getUp() {
|
||||
return getChunkData().getUp();
|
||||
}
|
||||
|
||||
default void forEachBlock(Consumer<BlockTickContext> action) {
|
||||
TickContextMutable context = TickContextMutable.uninitialized();
|
||||
|
||||
GenericChunks.forEachBiC(blockInChunk -> {
|
||||
context.rebuild().withServer(getServer()).withChunk(getChunk()).withBlockInChunk(blockInChunk).build();
|
||||
action.accept(context);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -34,9 +34,13 @@ import ru.windcorp.progressia.common.world.rels.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.rels.RelFace;
|
||||
import ru.windcorp.progressia.common.world.TileDataStack;
|
||||
import ru.windcorp.progressia.common.world.TileDataReference;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogic;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogicRegistry;
|
||||
import ru.windcorp.progressia.server.world.block.TickableBlock;
|
||||
import ru.windcorp.progressia.server.world.context.ServerBlockContextRO;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContextRO;
|
||||
import ru.windcorp.progressia.server.world.context.ServerWorldContextRO;
|
||||
import ru.windcorp.progressia.server.world.tasks.TickChunk;
|
||||
import ru.windcorp.progressia.server.world.ticking.TickingPolicy;
|
||||
import ru.windcorp.progressia.server.world.tile.TickableTile;
|
||||
@ -221,28 +225,45 @@ public class DefaultChunkLogic implements ChunkLogic {
|
||||
}
|
||||
|
||||
private void tmp_generateTickLists() {
|
||||
ChunkTickContext context = TickContextMutable.start().withChunk(this).build();
|
||||
ServerWorldContextRO context = Server.getCurrentServer().createContext();
|
||||
Vec3i blockInChunk = new Vec3i();
|
||||
|
||||
context.forEachBlock(bctxt -> {
|
||||
BlockLogic block = bctxt.getBlock();
|
||||
forEachBiW(location -> {
|
||||
|
||||
ServerBlockContextRO blockContext = context.push(location);
|
||||
|
||||
BlockLogic block = blockContext.logic().getBlock();
|
||||
Coordinates.convertInWorldToInChunk(location, blockInChunk);
|
||||
|
||||
if (!(block instanceof TickableBlock))
|
||||
return;
|
||||
|
||||
if (((TickableBlock) block).getTickingPolicy(bctxt) == TickingPolicy.REGULAR) {
|
||||
tickingBlocks.add(Coordinates.convertInWorldToInChunk(bctxt.getBlockInWorld(), null));
|
||||
if (((TickableBlock) block).getTickingPolicy(blockContext) == TickingPolicy.REGULAR) {
|
||||
tickingBlocks.add(blockInChunk);
|
||||
}
|
||||
|
||||
bctxt.forEachFace(fctxt -> fctxt.forEachTile(tctxt -> {
|
||||
TileLogic tile = tctxt.getTile();
|
||||
for (RelFace face : RelFace.getFaces()) {
|
||||
TileLogicStack stack = getTilesOrNull(blockInChunk, face);
|
||||
if (stack == null || stack.isEmpty()) continue;
|
||||
|
||||
for (int i = 0; i < stack.size(); ++i) {
|
||||
ServerTileContextRO tileContext = blockContext.push(face, i);
|
||||
|
||||
TileLogic tile = stack.get(i);
|
||||
|
||||
if (!(tile instanceof TickableTile))
|
||||
return;
|
||||
|
||||
if (((TickableTile) tile).getTickingPolicy(tctxt) == TickingPolicy.REGULAR) {
|
||||
tickingTiles.add(tctxt.getReference());
|
||||
if (((TickableTile) tile).getTickingPolicy(tileContext) == TickingPolicy.REGULAR) {
|
||||
tickingTiles.add(stack.getData().getReference(i));
|
||||
}
|
||||
}));
|
||||
|
||||
tileContext.pop();
|
||||
}
|
||||
}
|
||||
|
||||
blockContext.pop();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ public class DefaultWorldLogic implements WorldLogic {
|
||||
}
|
||||
});
|
||||
|
||||
data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server)));
|
||||
data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server.getWorldAccessor___really_bad_dont_use())));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,19 +24,26 @@ import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.common.world.rels.BlockFace;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogic;
|
||||
import ru.windcorp.progressia.server.world.block.BlockTickContext;
|
||||
import ru.windcorp.progressia.server.world.block.TickableBlock;
|
||||
import ru.windcorp.progressia.server.world.block.UpdateableBlock;
|
||||
import ru.windcorp.progressia.server.world.context.ServerBlockContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileStackContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerWorldContext;
|
||||
import ru.windcorp.progressia.server.world.entity.EntityLogic;
|
||||
import ru.windcorp.progressia.server.world.entity.EntityLogicRegistry;
|
||||
import ru.windcorp.progressia.server.world.tile.TickableTile;
|
||||
import ru.windcorp.progressia.server.world.tile.TileLogic;
|
||||
import ru.windcorp.progressia.server.world.tile.TileTickContext;
|
||||
import ru.windcorp.progressia.server.world.tile.UpdateableTile;
|
||||
|
||||
public class TickAndUpdateUtil {
|
||||
|
||||
public static void tickBlock(TickableBlock block, BlockTickContext context) {
|
||||
public static void tickBlock(ServerBlockContext context) {
|
||||
BlockLogic uncheckedBlock = context.logic().getBlock();
|
||||
if (!(uncheckedBlock instanceof BlockLogic)) {
|
||||
return;
|
||||
}
|
||||
TickableBlock block = (TickableBlock) uncheckedBlock;
|
||||
try {
|
||||
block.tick(context);
|
||||
} catch (Exception e) {
|
||||
@ -44,16 +51,21 @@ public class TickAndUpdateUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void tickBlock(DefaultWorldLogic world, Vec3i blockInWorld) {
|
||||
BlockLogic block = world.getBlock(blockInWorld);
|
||||
if (!(block instanceof TickableBlock))
|
||||
return; // also checks nulls
|
||||
|
||||
BlockTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).build();
|
||||
tickBlock((TickableBlock) block, tickContext);
|
||||
public static void tickBlock(Server server, Vec3i blockInWorld) {
|
||||
BlockLogic block = server.getWorld().getBlock(blockInWorld);
|
||||
if (!(block instanceof TickableBlock)) {
|
||||
return;
|
||||
}
|
||||
ServerBlockContext context = server.createContext().push(blockInWorld);
|
||||
tickBlock(context);
|
||||
}
|
||||
|
||||
public static void tickTile(TickableTile tile, TileTickContext context) {
|
||||
public static void tickTile(ServerTileContext context) {
|
||||
TileLogic uncheckedTile = context.logic().getTile();
|
||||
if (!(uncheckedTile instanceof TickableTile)) {
|
||||
return;
|
||||
}
|
||||
TickableTile tile = (TickableTile) uncheckedTile;
|
||||
try {
|
||||
tile.tick(context);
|
||||
} catch (Exception e) {
|
||||
@ -61,82 +73,88 @@ public class TickAndUpdateUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void tickTile(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) {
|
||||
TileLogic tile = world.getTile(blockInWorld, face, layer);
|
||||
public static void tickTile(Server server, Vec3i blockInWorld, BlockFace face, int layer) {
|
||||
TileLogic tile = server.getWorld().getTile(blockInWorld, face, layer);
|
||||
if (!(tile instanceof TickableTile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face)
|
||||
.withLayer(layer);
|
||||
tickTile((TickableTile) tile, tickContext);
|
||||
ServerTileContext context = server.createContext()
|
||||
.push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld)), layer);
|
||||
tickTile(context);
|
||||
}
|
||||
|
||||
public static void tickTiles(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face) {
|
||||
if (!world.isLocationLoaded(blockInWorld)) {
|
||||
public static void tickTiles(Server server, Vec3i blockInWorld, BlockFace face) {
|
||||
if (!server.getWorld().hasTiles(blockInWorld, face)) {
|
||||
return;
|
||||
}
|
||||
|
||||
TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build()
|
||||
.forEachTile(context -> {
|
||||
TileLogic tile = context.getTile();
|
||||
if (tile instanceof TickableTile) {
|
||||
tickTile((TickableTile) tile, context);
|
||||
ServerTileStackContext context = server.createContext()
|
||||
.push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld)));
|
||||
for (int i = 0; i < context.getTileCount(); ++i) {
|
||||
tickTile(context.push(i));
|
||||
context.pop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void updateBlock(UpdateableBlock block, BlockTickContext context) {
|
||||
public static void updateBlock(ServerBlockContext context) {
|
||||
BlockLogic uncheckedBlock = context.logic().getBlock();
|
||||
if (!(uncheckedBlock instanceof BlockLogic)) {
|
||||
return;
|
||||
}
|
||||
UpdateableBlock block = (UpdateableBlock) uncheckedBlock;
|
||||
try {
|
||||
block.update(context);
|
||||
} catch (Exception e) {
|
||||
throw CrashReports.report(e, "Could not update block {}", block);
|
||||
throw CrashReports.report(e, "Could not update block %s", block);
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateBlock(DefaultWorldLogic world, Vec3i blockInWorld) {
|
||||
BlockLogic block = world.getBlock(blockInWorld);
|
||||
if (!(block instanceof UpdateableBlock))
|
||||
return; // also checks nulls
|
||||
|
||||
BlockTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).build();
|
||||
updateBlock((UpdateableBlock) block, tickContext);
|
||||
public static void updateBlock(Server server, Vec3i blockInWorld) {
|
||||
BlockLogic block = server.getWorld().getBlock(blockInWorld);
|
||||
if (!(block instanceof UpdateableBlock)) {
|
||||
return;
|
||||
}
|
||||
ServerBlockContext context = server.createContext().push(blockInWorld);
|
||||
updateBlock(context);
|
||||
}
|
||||
|
||||
public static void updateTile(UpdateableTile tile, TileTickContext context) {
|
||||
public static void updateTile(ServerTileContext context) {
|
||||
TileLogic uncheckedTile = context.logic().getTile();
|
||||
if (!(uncheckedTile instanceof UpdateableTile)) {
|
||||
return;
|
||||
}
|
||||
UpdateableTile tile = (UpdateableTile) uncheckedTile;
|
||||
try {
|
||||
tile.update(context);
|
||||
} catch (Exception e) {
|
||||
throw CrashReports.report(e, "Could not update tile {}", tile);
|
||||
throw CrashReports.report(e, "Could not tick tile %s", tile);
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateTile(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) {
|
||||
TileLogic tile = world.getTile(blockInWorld, face, layer);
|
||||
public static void updateTile(Server server, Vec3i blockInWorld, BlockFace face, int layer) {
|
||||
TileLogic tile = server.getWorld().getTile(blockInWorld, face, layer);
|
||||
if (!(tile instanceof UpdateableTile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face)
|
||||
.withLayer(layer);
|
||||
updateTile((UpdateableTile) tile, tickContext);
|
||||
ServerTileContext context = server.createContext()
|
||||
.push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld)), layer);
|
||||
updateTile(context);
|
||||
}
|
||||
|
||||
public static void updateTiles(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face) {
|
||||
if (!world.isLocationLoaded(blockInWorld)) {
|
||||
public static void updateTiles(Server server, Vec3i blockInWorld, BlockFace face) {
|
||||
if (!server.getWorld().hasTiles(blockInWorld, face)) {
|
||||
return;
|
||||
}
|
||||
|
||||
TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build()
|
||||
.forEachTile(context -> {
|
||||
TileLogic tile = context.getTile();
|
||||
if (tile instanceof UpdateableTile) {
|
||||
updateTile((UpdateableTile) tile, context);
|
||||
ServerTileStackContext context = server.createContext()
|
||||
.push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld)));
|
||||
for (int i = 0; i < context.getTileCount(); ++i) {
|
||||
updateTile(context.push(i));
|
||||
context.pop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void tickEntity(EntityLogic logic, EntityData data, TickContext context) {
|
||||
public static void tickEntity(EntityLogic logic, EntityData data, ServerWorldContext context) {
|
||||
try {
|
||||
logic.tick(data, context);
|
||||
} catch (Exception e) {
|
||||
@ -148,7 +166,7 @@ public class TickAndUpdateUtil {
|
||||
tickEntity(
|
||||
EntityLogicRegistry.getInstance().get(data.getId()),
|
||||
data,
|
||||
TickContextMutable.start().withServer(server).build()
|
||||
server.createContext()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.server.world;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.tasks.WorldAccessor;
|
||||
|
||||
public interface TickContext {
|
||||
|
||||
float getTickLength();
|
||||
|
||||
Server getServer();
|
||||
|
||||
default DefaultWorldLogic getWorld() {
|
||||
return getServer().getWorld();
|
||||
}
|
||||
|
||||
default WorldAccessor getAccessor() {
|
||||
return getServer().getWorldAccessor();
|
||||
}
|
||||
|
||||
default Random getRandom() {
|
||||
return getServer().getAdHocRandom();
|
||||
}
|
||||
|
||||
default DefaultWorldData getWorldData() {
|
||||
return getWorld().getData();
|
||||
}
|
||||
|
||||
}
|
@ -1,497 +0,0 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.server.world;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.world.DefaultChunkData;
|
||||
import ru.windcorp.progressia.common.world.Coordinates;
|
||||
import ru.windcorp.progressia.common.world.generic.TileGenericStackRO;
|
||||
import ru.windcorp.progressia.common.world.rels.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.rels.RelFace;
|
||||
import ru.windcorp.progressia.common.world.TileDataStack;
|
||||
import ru.windcorp.progressia.common.world.TileDataReference;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.block.BlockTickContext;
|
||||
import ru.windcorp.progressia.server.world.tile.TSTickContext;
|
||||
import ru.windcorp.progressia.server.world.tile.TileTickContext;
|
||||
|
||||
public abstract class TickContextMutable implements BlockTickContext, TSTickContext, TileTickContext {
|
||||
|
||||
private static enum Role {
|
||||
NONE, WORLD, CHUNK, BLOCK, TILE_STACK, TILE;
|
||||
}
|
||||
|
||||
/*
|
||||
* TickContextMutable interface
|
||||
*/
|
||||
|
||||
// Only TickContextMutable.Impl can extend; extend Impl if need be
|
||||
private TickContextMutable() {
|
||||
}
|
||||
|
||||
public abstract Builder.Empty rebuild();
|
||||
|
||||
/*
|
||||
* Static methods
|
||||
*/
|
||||
|
||||
public static TickContextMutable uninitialized() {
|
||||
return new Impl();
|
||||
}
|
||||
|
||||
public static Builder.Empty start() {
|
||||
return uninitialized().rebuild();
|
||||
}
|
||||
|
||||
public static Builder.World copyWorld(TickContext context) {
|
||||
return start().withServer(context.getServer());
|
||||
}
|
||||
|
||||
public static Builder.Chunk copyChunk(ChunkTickContext context) {
|
||||
return start().withChunk(context.getChunkLogic());
|
||||
}
|
||||
|
||||
public static Builder.Block copyBlock(BlockTickContext context) {
|
||||
return copyWorld(context).withBlock(context.getBlockInWorld());
|
||||
}
|
||||
|
||||
public static Builder.TileStack copyTS(TSTickContext context) {
|
||||
return copyBlock(context).withFace(context.getFace());
|
||||
}
|
||||
|
||||
public static TileTickContext copyTile(TileTickContext context) {
|
||||
return copyTS(context).withLayer(context.getLayer());
|
||||
}
|
||||
|
||||
/*
|
||||
* Builder interfaces
|
||||
*/
|
||||
|
||||
public static interface Builder {
|
||||
TickContextMutable build();
|
||||
|
||||
public static interface Empty /* does not extend Builder */ {
|
||||
World withServer(Server server);
|
||||
|
||||
default Builder.World withWorld(DefaultWorldLogic world) {
|
||||
Objects.requireNonNull(world, "world");
|
||||
return withServer(world.getServer());
|
||||
}
|
||||
|
||||
default Builder.Chunk withChunk(DefaultChunkLogic chunk) {
|
||||
Objects.requireNonNull(chunk, "chunk");
|
||||
return withWorld(chunk.getWorld()).withChunk(chunk.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public static interface World extends Builder {
|
||||
Chunk withChunk(Vec3i chunk);
|
||||
|
||||
Block withBlock(Vec3i blockInWorld);
|
||||
|
||||
TileStack withTS(TileGenericStackRO<?, ?, ?, ?, ?> tileStack);
|
||||
|
||||
default Builder.Chunk withChunk(DefaultChunkData chunk) {
|
||||
Objects.requireNonNull(chunk, "chunk");
|
||||
return withChunk(chunk.getPosition());
|
||||
}
|
||||
|
||||
default TileTickContext withTile(TileDataReference ref) {
|
||||
Objects.requireNonNull(ref, "ref");
|
||||
return withTS(ref.getStack()).withLayer(ref.getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
public static interface Chunk extends Builder {
|
||||
Builder.Block withBlockInChunk(Vec3i blockInChunk);
|
||||
}
|
||||
|
||||
public static interface Block extends Builder {
|
||||
Builder.TileStack withFace(BlockFace face);
|
||||
}
|
||||
|
||||
public static interface TileStack extends Builder {
|
||||
TickContextMutable withLayer(int layer);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Impl
|
||||
*/
|
||||
|
||||
public static class Impl
|
||||
extends TickContextMutable
|
||||
implements Builder.Empty, Builder.World, Builder.Chunk, Builder.Block, Builder.TileStack {
|
||||
|
||||
protected Impl() {
|
||||
}
|
||||
|
||||
protected Server server;
|
||||
protected final Vec3i chunk = new Vec3i();
|
||||
protected final Vec3i blockInWorld = new Vec3i();
|
||||
protected RelFace face;
|
||||
protected int layer;
|
||||
|
||||
protected Role role = Role.NONE;
|
||||
protected boolean isBeingBuilt = false;
|
||||
|
||||
/**
|
||||
* Updated lazily
|
||||
*/
|
||||
protected final Vec3i blockInChunk = new Vec3i();
|
||||
|
||||
/*
|
||||
* TickContextMutable
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Server getServer() {
|
||||
checkContextState(Role.WORLD);
|
||||
return this.server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTickLength() {
|
||||
checkContextState(Role.WORLD);
|
||||
return (float) this.server.getTickLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i getChunk() {
|
||||
checkContextState(Role.CHUNK);
|
||||
return this.chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i getBlockInWorld() {
|
||||
checkContextState(Role.BLOCK);
|
||||
return this.blockInWorld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelFace getFace() {
|
||||
checkContextState(Role.TILE_STACK);
|
||||
return this.face;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayer() {
|
||||
checkContextState(Role.TILE);
|
||||
return this.layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder.Empty rebuild() {
|
||||
this.role = Role.NONE;
|
||||
this.isBeingBuilt = true;
|
||||
|
||||
this.server = null;
|
||||
this.chunk.set(0);
|
||||
this.blockInWorld.set(0);
|
||||
this.face = null;
|
||||
this.layer = -1;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Builder
|
||||
* memo: do NOT use Context getters, they throw ISEs
|
||||
*/
|
||||
|
||||
@Override
|
||||
public TickContextMutable build() {
|
||||
checkBuilderState(null);
|
||||
this.isBeingBuilt = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public World withServer(Server server) {
|
||||
Objects.requireNonNull(server, "server");
|
||||
checkBuilderState(Role.NONE);
|
||||
this.server = server;
|
||||
this.role = Role.WORLD;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk withChunk(Vec3i chunk) {
|
||||
Objects.requireNonNull(chunk, "chunk");
|
||||
checkBuilderState(Role.WORLD);
|
||||
|
||||
this.chunk.set(chunk.x, chunk.y, chunk.z);
|
||||
|
||||
this.role = Role.CHUNK;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block withBlock(Vec3i blockInWorld) {
|
||||
Objects.requireNonNull(blockInWorld, "blockInWorld");
|
||||
checkBuilderState(Role.WORLD);
|
||||
|
||||
this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z);
|
||||
Coordinates.convertInWorldToChunk(blockInWorld, this.chunk);
|
||||
|
||||
this.role = Role.BLOCK;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileStack withTS(TileGenericStackRO<?, ?, ?, ?, ?> tileStack) {
|
||||
Objects.requireNonNull(tileStack, "tileStack");
|
||||
|
||||
return withBlock(
|
||||
tileStack.getBlockInWorld(this.blockInWorld) // This is safe
|
||||
).withFace(tileStack.getFace());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block withBlockInChunk(Vec3i blockInChunk) {
|
||||
Objects.requireNonNull(blockInChunk, "blockInChunk");
|
||||
checkBuilderState(Role.CHUNK);
|
||||
|
||||
Coordinates.getInWorld(this.chunk, blockInChunk, this.blockInWorld);
|
||||
|
||||
this.role = Role.BLOCK;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileStack withFace(BlockFace face) {
|
||||
Objects.requireNonNull(face, "face");
|
||||
checkBuilderState(Role.BLOCK);
|
||||
|
||||
this.face = face.relativize(server.getWorld().getChunk(chunk).getUp());
|
||||
|
||||
this.role = Role.TILE_STACK;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickContextMutable withLayer(int layer) {
|
||||
checkBuilderState(Role.TILE);
|
||||
|
||||
this.layer = layer;
|
||||
|
||||
this.role = Role.TILE;
|
||||
return build();
|
||||
}
|
||||
|
||||
/*
|
||||
* Optimization
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Vec3i getBlockInChunk() {
|
||||
return Coordinates.convertInWorldToInChunk(getBlockInWorld(), this.blockInChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachBlock(Consumer<BlockTickContext> action) {
|
||||
checkContextState(Role.CHUNK);
|
||||
|
||||
Vec3i v = this.blockInWorld;
|
||||
|
||||
int previousX = v.x;
|
||||
int previousY = v.y;
|
||||
int previousZ = v.z;
|
||||
Role previousRole = this.role;
|
||||
|
||||
this.role = Role.BLOCK;
|
||||
|
||||
final int minX = Coordinates.getInWorld(chunk.x, 0);
|
||||
final int minY = Coordinates.getInWorld(chunk.y, 0);
|
||||
final int minZ = Coordinates.getInWorld(chunk.z, 0);
|
||||
final int size = DefaultChunkData.BLOCKS_PER_CHUNK;
|
||||
|
||||
for (v.x = minX; v.x < minX + size; ++v.x) {
|
||||
for (v.y = minY; v.y < minY + size; ++v.y) {
|
||||
for (v.z = minZ; v.z < minZ + size; ++v.z) {
|
||||
action.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.role = previousRole;
|
||||
blockInWorld.set(previousX, previousY, previousZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachFace(Consumer<TSTickContext> action) {
|
||||
checkContextState(Role.BLOCK);
|
||||
RelFace previousFace = this.face;
|
||||
Role previousRole = this.role;
|
||||
|
||||
this.role = Role.TILE_STACK;
|
||||
for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) {
|
||||
this.face = RelFace.getFaces().get(i);
|
||||
action.accept(this);
|
||||
}
|
||||
|
||||
this.role = previousRole;
|
||||
this.face = previousFace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R evalNeighbor(Vec3i direction, Function<BlockTickContext, R> action) {
|
||||
this.blockInWorld.add(direction);
|
||||
R result = action.apply(this);
|
||||
this.blockInWorld.sub(direction);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forNeighbor(Vec3i direction, Consumer<BlockTickContext> action) {
|
||||
this.blockInWorld.add(direction);
|
||||
action.accept(this);
|
||||
this.blockInWorld.sub(direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean forEachTile(Consumer<TileTickContext> action) {
|
||||
checkContextState(Role.TILE_STACK);
|
||||
int previousLayer = this.layer;
|
||||
Role previousRole = this.role;
|
||||
|
||||
this.role = Role.TILE;
|
||||
TileDataStack stack = getTDSOrNull();
|
||||
if (stack == null || stack.isEmpty())
|
||||
return false;
|
||||
|
||||
for (this.layer = 0; this.layer < stack.size(); ++this.layer) {
|
||||
action.accept(this);
|
||||
}
|
||||
|
||||
this.role = previousRole;
|
||||
this.layer = previousLayer;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R evalComplementary(Function<TSTickContext, R> action) {
|
||||
Objects.requireNonNull(action, "action");
|
||||
checkContextState(Role.TILE_STACK);
|
||||
|
||||
Vec3i vector = this.face.getVector(getUp());
|
||||
|
||||
this.blockInWorld.add(vector);
|
||||
this.face = this.face.getCounter();
|
||||
R result = action.apply(this);
|
||||
this.face = this.face.getCounter();
|
||||
this.blockInWorld.sub(vector);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forComplementary(Consumer<TSTickContext> action) {
|
||||
Objects.requireNonNull(action, "action");
|
||||
checkContextState(Role.TILE_STACK);
|
||||
|
||||
Vec3i vector = this.face.getVector(getUp());
|
||||
|
||||
this.blockInWorld.add(vector);
|
||||
this.face = this.face.getCounter();
|
||||
action.accept(this);
|
||||
this.face = this.face.getCounter();
|
||||
this.blockInWorld.sub(vector);
|
||||
}
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
|
||||
protected void checkContextState(Role requiredRole) {
|
||||
if (isBeingBuilt) {
|
||||
throw new IllegalStateException("This context is still being built");
|
||||
}
|
||||
|
||||
if ((role == null) || (requiredRole.compareTo(role) > 0)) {
|
||||
throw new IllegalStateException(
|
||||
"This context is currently initialized as " + role + "; requested " + requiredRole
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkBuilderState(Role requiredRole) {
|
||||
if (!isBeingBuilt) {
|
||||
throw new IllegalStateException("This context is already built");
|
||||
}
|
||||
|
||||
if (requiredRole == null) {
|
||||
if (role == Role.NONE) {
|
||||
throw new IllegalStateException("This context is currently not initialized");
|
||||
}
|
||||
} else {
|
||||
if (role != requiredRole) {
|
||||
throw new IllegalStateException(
|
||||
"This context is currently initialized as " + role + "; requested " + requiredRole
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final String format;
|
||||
|
||||
switch (this.role) {
|
||||
case WORLD:
|
||||
format = "TickContext";
|
||||
break;
|
||||
case CHUNK:
|
||||
format = "(%2$d; %3$d; %4$d)";
|
||||
break;
|
||||
case BLOCK:
|
||||
format = "(%5$d; %6$d; %7$d)";
|
||||
break;
|
||||
case TILE_STACK:
|
||||
format = "((%5$d; %6$d; %7$d); %8$6s)";
|
||||
break;
|
||||
case TILE:
|
||||
format = "((%5$d; %6$d; %7$d); %8$6s; %9$d)";
|
||||
break;
|
||||
case NONE:
|
||||
default:
|
||||
format = "Uninitialized TickContextMutable";
|
||||
break;
|
||||
}
|
||||
|
||||
return String.format(
|
||||
format,
|
||||
this.chunk.x,
|
||||
this.chunk.y,
|
||||
this.chunk.z,
|
||||
this.blockInWorld.x,
|
||||
this.blockInWorld.y,
|
||||
this.blockInWorld.z,
|
||||
this.face,
|
||||
this.layer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -25,14 +25,14 @@ import ru.windcorp.progressia.common.world.Coordinates;
|
||||
import ru.windcorp.progressia.common.world.block.BlockData;
|
||||
import ru.windcorp.progressia.common.world.rels.RelFace;
|
||||
import ru.windcorp.progressia.common.world.tile.TileData;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.tasks.WorldAccessor;
|
||||
|
||||
public class UpdateTriggerer implements ChunkDataListener {
|
||||
|
||||
private final Server server;
|
||||
private final WorldAccessor worldAccessor;
|
||||
|
||||
public UpdateTriggerer(Server server) {
|
||||
this.server = server;
|
||||
public UpdateTriggerer(WorldAccessor worldAccessor) {
|
||||
this.worldAccessor = worldAccessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -42,7 +42,7 @@ public class UpdateTriggerer implements ChunkDataListener {
|
||||
BlockData previous,
|
||||
BlockData current
|
||||
) {
|
||||
server.getWorldAccessor().triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null));
|
||||
worldAccessor.triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,7 +53,7 @@ public class UpdateTriggerer implements ChunkDataListener {
|
||||
TileData tile,
|
||||
boolean wasAdded
|
||||
) {
|
||||
server.getWorldAccessor().triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null), face);
|
||||
worldAccessor.triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null), face);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ package ru.windcorp.progressia.server.world.block;
|
||||
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||
import ru.windcorp.progressia.common.world.generic.BlockGeneric;
|
||||
import ru.windcorp.progressia.common.world.rels.RelFace;
|
||||
import ru.windcorp.progressia.server.world.context.ServerBlockContextRO;
|
||||
|
||||
public class BlockLogic extends Namespaced implements BlockGeneric {
|
||||
|
||||
@ -28,7 +29,7 @@ public class BlockLogic extends Namespaced implements BlockGeneric {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public boolean isSolid(BlockTickContext context, RelFace face) {
|
||||
public boolean isSolid(ServerBlockContextRO context, RelFace face) {
|
||||
return isSolid(face);
|
||||
}
|
||||
|
||||
@ -36,7 +37,7 @@ public class BlockLogic extends Namespaced implements BlockGeneric {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isTransparent(BlockTickContext context) {
|
||||
public boolean isTransparent(ServerBlockContextRO context) {
|
||||
return isTransparent();
|
||||
}
|
||||
|
||||
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.server.world.block;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.world.Coordinates;
|
||||
import ru.windcorp.progressia.common.world.block.BlockData;
|
||||
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||
import ru.windcorp.progressia.common.world.rels.BlockRelation;
|
||||
import ru.windcorp.progressia.server.world.ChunkTickContext;
|
||||
import ru.windcorp.progressia.server.world.TickContextMutable;
|
||||
import ru.windcorp.progressia.server.world.tile.TSTickContext;
|
||||
|
||||
public interface BlockTickContext extends ChunkTickContext {
|
||||
|
||||
/**
|
||||
* Returns the current world coordinates.
|
||||
*
|
||||
* @return the world coordinates of the block being ticked
|
||||
*/
|
||||
Vec3i getBlockInWorld();
|
||||
|
||||
default Vec3i getBlockInChunk() {
|
||||
return Coordinates.convertInWorldToInChunk(getBlockInWorld(), null);
|
||||
}
|
||||
|
||||
default BlockLogic getBlock() {
|
||||
return getWorld().getBlock(getBlockInWorld());
|
||||
}
|
||||
|
||||
default BlockData getBlockData() {
|
||||
return getWorldData().getBlock(getBlockInWorld());
|
||||
}
|
||||
|
||||
default void forEachFace(Consumer<TSTickContext> action) {
|
||||
Objects.requireNonNull(action, "action");
|
||||
TickContextMutable context = TickContextMutable.uninitialized();
|
||||
|
||||
for (AbsFace face : AbsFace.getFaces()) {
|
||||
context.rebuild().withServer(getServer()).withBlock(getBlockInWorld()).withFace(face).build();
|
||||
action.accept(context);
|
||||
}
|
||||
}
|
||||
|
||||
default BlockTickContext getNeighbor(Vec3i direction) {
|
||||
Objects.requireNonNull(direction, "direction");
|
||||
return TickContextMutable.copyWorld(this).withBlock(getBlockInWorld().add_(direction)).build();
|
||||
}
|
||||
|
||||
default BlockTickContext getNeighbor(BlockRelation relation) {
|
||||
Objects.requireNonNull(relation, "relation");
|
||||
return getNeighbor(relation.getVector(getChunkData().getUp()));
|
||||
}
|
||||
|
||||
default <R> R evalNeighbor(Vec3i direction, Function<BlockTickContext, R> action) {
|
||||
Objects.requireNonNull(action, "action");
|
||||
Objects.requireNonNull(direction, "direction");
|
||||
return action.apply(getNeighbor(direction));
|
||||
}
|
||||
|
||||
default <R> R evalNeighbor(BlockRelation relation, Function<BlockTickContext, R> action) {
|
||||
Objects.requireNonNull(action, "action");
|
||||
Objects.requireNonNull(relation, "relation");
|
||||
return evalNeighbor(relation.getVector(getChunkData().getUp()), action);
|
||||
}
|
||||
|
||||
default void forNeighbor(Vec3i direction, Consumer<BlockTickContext> action) {
|
||||
Objects.requireNonNull(action, "action");
|
||||
Objects.requireNonNull(direction, "direction");
|
||||
evalNeighbor(direction, (Function<BlockTickContext, Void>) ctxt -> {
|
||||
action.accept(ctxt);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
default void forNeighbor(BlockRelation relation, Consumer<BlockTickContext> action) {
|
||||
Objects.requireNonNull(action, "action");
|
||||
Objects.requireNonNull(relation, "relation");
|
||||
forNeighbor(relation.getVector(getChunkData().getUp()), action);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convenience methods - changes
|
||||
*/
|
||||
|
||||
default void setThisBlock(BlockData block) {
|
||||
getAccessor().setBlock(getBlockInWorld(), block);
|
||||
}
|
||||
|
||||
default void setThisBlock(String id) {
|
||||
getAccessor().setBlock(getBlockInWorld(), id);
|
||||
}
|
||||
|
||||
}
|
@ -18,12 +18,14 @@
|
||||
|
||||
package ru.windcorp.progressia.server.world.block;
|
||||
|
||||
import ru.windcorp.progressia.server.world.context.ServerBlockContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerBlockContextRO;
|
||||
import ru.windcorp.progressia.server.world.ticking.TickingPolicy;
|
||||
|
||||
public interface TickableBlock {
|
||||
|
||||
void tick(BlockTickContext context);
|
||||
void tick(ServerBlockContext context);
|
||||
|
||||
TickingPolicy getTickingPolicy(BlockTickContext context);
|
||||
TickingPolicy getTickingPolicy(ServerBlockContextRO context);
|
||||
|
||||
}
|
||||
|
@ -18,18 +18,10 @@
|
||||
|
||||
package ru.windcorp.progressia.server.world.block;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import ru.windcorp.progressia.server.world.context.ServerBlockContext;
|
||||
|
||||
public interface UpdateableBlock {
|
||||
|
||||
default void update(BlockTickContext context) {
|
||||
LogManager.getLogger().info(
|
||||
"Updating block {} @ ({}; {}; {})",
|
||||
context.getBlock(),
|
||||
context.getBlockInWorld().x,
|
||||
context.getBlockInWorld().y,
|
||||
context.getBlockInWorld().z
|
||||
);
|
||||
}
|
||||
void update(ServerBlockContext context);
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ package ru.windcorp.progressia.server.world.entity;
|
||||
|
||||
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.server.world.TickContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerWorldContext;
|
||||
|
||||
public class EntityLogic extends Namespaced {
|
||||
|
||||
@ -28,7 +28,7 @@ public class EntityLogic extends Namespaced {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public void tick(EntityData entity, TickContext context) {
|
||||
public void tick(EntityData entity, ServerWorldContext context) {
|
||||
entity.incrementAge(context.getTickLength());
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ import ru.windcorp.progressia.common.world.Coordinates;
|
||||
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.TickAndUpdateUtil;
|
||||
import ru.windcorp.progressia.server.world.DefaultWorldLogic;
|
||||
|
||||
class BlockTriggeredUpdate extends CachedEvaluation {
|
||||
|
||||
@ -39,13 +38,11 @@ class BlockTriggeredUpdate extends CachedEvaluation {
|
||||
public void evaluate(Server server) {
|
||||
Vec3i cursor = new Vec3i(blockInWorld.x, blockInWorld.y, blockInWorld.z);
|
||||
|
||||
DefaultWorldLogic world = server.getWorld();
|
||||
|
||||
for (AbsFace face : AbsFace.getFaces()) {
|
||||
TickAndUpdateUtil.updateTiles(world, cursor, face);
|
||||
TickAndUpdateUtil.updateTiles(server, cursor, face);
|
||||
cursor.add(face.getVector());
|
||||
TickAndUpdateUtil.updateBlock(world, cursor);
|
||||
TickAndUpdateUtil.updateTiles(world, cursor, face.getCounter());
|
||||
TickAndUpdateUtil.updateBlock(server, cursor);
|
||||
TickAndUpdateUtil.updateTiles(server, cursor, face.getCounter());
|
||||
cursor.sub(face.getVector());
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ package ru.windcorp.progressia.server.world.tasks;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.state.StateChange;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.common.world.entity.PacketChangeEntity;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
@ -36,7 +37,7 @@ class ChangeEntity extends CachedChange {
|
||||
super(disposer);
|
||||
}
|
||||
|
||||
public <T extends EntityData> void set(T entity, StateChange<T> change) {
|
||||
public void set(EntityData entity, StateChange<?> change) {
|
||||
if (this.entity != null)
|
||||
throw new IllegalStateException("Entity is not null. Current: " + this.entity + "; requested: " + entity);
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.server.world.tasks;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface StateChange<T> {
|
||||
void change(T object);
|
||||
}
|
@ -27,17 +27,22 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.util.FloatMathUtil;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
import ru.windcorp.progressia.common.world.Coordinates;
|
||||
import ru.windcorp.progressia.common.world.DefaultChunkData;
|
||||
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||
import ru.windcorp.progressia.common.world.TileDataStack;
|
||||
import ru.windcorp.progressia.common.world.generic.ChunkGenericRO;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.DefaultChunkLogic;
|
||||
import ru.windcorp.progressia.server.world.TickContextMutable;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogic;
|
||||
import ru.windcorp.progressia.server.world.block.TickableBlock;
|
||||
import ru.windcorp.progressia.server.world.context.ServerBlockContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileStackContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerWorldContext;
|
||||
import ru.windcorp.progressia.server.world.ticking.Evaluation;
|
||||
import ru.windcorp.progressia.server.world.ticking.TickingPolicy;
|
||||
import ru.windcorp.progressia.server.world.tile.TSTickContext;
|
||||
import ru.windcorp.progressia.server.world.tile.TickableTile;
|
||||
import ru.windcorp.progressia.server.world.tile.TileLogic;
|
||||
import static ru.windcorp.progressia.common.world.DefaultChunkData.BLOCKS_PER_CHUNK;
|
||||
@ -82,11 +87,11 @@ public class TickChunk extends Evaluation {
|
||||
if (!chunk.hasTickingBlocks())
|
||||
return;
|
||||
|
||||
TickContextMutable context = TickContextMutable.uninitialized();
|
||||
ServerWorldContext context = server.createContext();
|
||||
|
||||
chunk.forEachTickingBlock((blockInChunk, block) -> {
|
||||
context.rebuild().withChunk(chunk).withBlockInChunk(blockInChunk).build();
|
||||
((TickableBlock) block).tick(context);
|
||||
((TickableBlock) block).tick(contextPushBiC(context, chunk, blockInChunk));
|
||||
context.pop();
|
||||
});
|
||||
}
|
||||
|
||||
@ -94,11 +99,14 @@ public class TickChunk extends Evaluation {
|
||||
if (!chunk.hasTickingTiles())
|
||||
return;
|
||||
|
||||
TickContextMutable context = TickContextMutable.uninitialized();
|
||||
ServerWorldContext context = server.createContext();
|
||||
Vec3i blockInWorld = new Vec3i();
|
||||
|
||||
chunk.forEachTickingTile((ref, tile) -> {
|
||||
context.rebuild().withServer(server).withTile(ref);
|
||||
((TickableTile) tile).tick(context);
|
||||
((TickableTile) tile).tick(
|
||||
context.push(ref.getStack().getBlockInWorld(blockInWorld), ref.getStack().getFace(), ref.getIndex())
|
||||
);
|
||||
context.pop();
|
||||
});
|
||||
}
|
||||
|
||||
@ -144,7 +152,7 @@ public class TickChunk extends Evaluation {
|
||||
return;
|
||||
TickableBlock tickable = (TickableBlock) block;
|
||||
|
||||
TickContextMutable context = TickContextMutable.start().withChunk(chunk).withBlockInChunk(blockInChunk).build();
|
||||
ServerBlockContext context = contextPushBiC(server.createContext(), chunk, blockInChunk);
|
||||
|
||||
if (tickable.getTickingPolicy(context) != TickingPolicy.RANDOM)
|
||||
return;
|
||||
@ -164,18 +172,22 @@ public class TickChunk extends Evaluation {
|
||||
if (tiles == null || tiles.isEmpty())
|
||||
return;
|
||||
|
||||
TSTickContext context = TickContextMutable.start().withServer(server).withTS(tiles).build();
|
||||
ServerTileStackContext context = contextPushBiC(server.createContext(), chunk, blockInChunk).push(face.relativize(chunk.getUp()));
|
||||
|
||||
context.forEachTile(tctxt -> {
|
||||
TileLogic logic = tctxt.getTile();
|
||||
for (int i = 0; i < tiles.size(); ++i) {
|
||||
ServerTileContext tileContext = context.push(i);
|
||||
|
||||
TileLogic logic = tileContext.logic().getTile();
|
||||
if (!(logic instanceof TickableTile))
|
||||
return;
|
||||
TickableTile tickable = (TickableTile) logic;
|
||||
|
||||
if (tickable.getTickingPolicy(tctxt) != TickingPolicy.RANDOM)
|
||||
if (tickable.getTickingPolicy(tileContext) != TickingPolicy.RANDOM)
|
||||
return;
|
||||
tickable.tick(tctxt);
|
||||
});
|
||||
tickable.tick(tileContext);
|
||||
|
||||
tileContext.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private float computeRandomTicks(Server server) {
|
||||
@ -184,6 +196,18 @@ public class TickChunk extends Evaluation {
|
||||
server.getTickLength());
|
||||
}
|
||||
|
||||
private ServerBlockContext contextPushBiC(
|
||||
ServerWorldContext context,
|
||||
ChunkGenericRO<?, ?, ?, ?, ?> chunk,
|
||||
Vec3i blockInChunk
|
||||
) {
|
||||
Vec3i blockInWorld = Vectors.grab3i();
|
||||
Coordinates.getInWorld(chunk.getPosition(), blockInChunk, blockInWorld);
|
||||
ServerBlockContext blockContext = context.push(blockInWorld);
|
||||
Vectors.release(blockInWorld);
|
||||
return blockContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getRelevantChunk(Vec3i output) {
|
||||
Vec3i p = chunk.getData().getPosition();
|
||||
|
@ -25,7 +25,6 @@ import ru.windcorp.progressia.common.world.Coordinates;
|
||||
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.TickAndUpdateUtil;
|
||||
import ru.windcorp.progressia.server.world.DefaultWorldLogic;
|
||||
|
||||
class TileTriggeredUpdate extends CachedEvaluation {
|
||||
|
||||
@ -40,17 +39,15 @@ class TileTriggeredUpdate extends CachedEvaluation {
|
||||
public void evaluate(Server server) {
|
||||
Vec3i cursor = new Vec3i(blockInWorld.x, blockInWorld.y, blockInWorld.z);
|
||||
|
||||
DefaultWorldLogic world = server.getWorld();
|
||||
|
||||
TickAndUpdateUtil.updateTiles(world, cursor, face); // Update facemates
|
||||
// (also self)
|
||||
TickAndUpdateUtil.updateBlock(world, cursor); // Update block on one
|
||||
// side
|
||||
// Update facemates (also self)
|
||||
TickAndUpdateUtil.updateTiles(server, cursor, face);
|
||||
// Update block on one side
|
||||
TickAndUpdateUtil.updateBlock(server, cursor);
|
||||
cursor.add(face.getVector());
|
||||
TickAndUpdateUtil.updateBlock(world, cursor); // Update block on the
|
||||
// other side
|
||||
TickAndUpdateUtil.updateTiles(world, cursor, face.getCounter()); // Update
|
||||
// complement
|
||||
// Update block on the other side
|
||||
TickAndUpdateUtil.updateBlock(server, cursor);
|
||||
// Update complement
|
||||
TickAndUpdateUtil.updateTiles(server, cursor, face.getCounter());
|
||||
}
|
||||
|
||||
public void init(Vec3i blockInWorld, AbsFace face) {
|
||||
|
@ -21,17 +21,19 @@ package ru.windcorp.progressia.server.world.tasks;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.state.StateChange;
|
||||
import ru.windcorp.progressia.common.state.StatefulObject;
|
||||
import ru.windcorp.progressia.common.util.MultiLOC;
|
||||
import ru.windcorp.progressia.common.world.block.BlockData;
|
||||
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.common.world.generic.EntityGeneric;
|
||||
import ru.windcorp.progressia.common.world.rels.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.tile.TileData;
|
||||
import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.context.impl.ReportingServerContext;
|
||||
import ru.windcorp.progressia.server.world.ticking.TickerTask;
|
||||
|
||||
public class WorldAccessor {
|
||||
public class WorldAccessor implements ReportingServerContext.ChangeListener {
|
||||
|
||||
private final MultiLOC cache;
|
||||
{
|
||||
@ -54,38 +56,52 @@ public class WorldAccessor {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void setBlock(Vec3i blockInWorld, BlockData block) {
|
||||
@Override
|
||||
public void onBlockSet(Vec3i blockInWorld, BlockData block) {
|
||||
SetBlock change = cache.grab(SetBlock.class);
|
||||
change.getPacket().set(block, blockInWorld);
|
||||
server.requestChange(change);
|
||||
}
|
||||
|
||||
public void setBlock(Vec3i blockInWorld, String id) {
|
||||
setBlock(blockInWorld, BlockDataRegistry.getInstance().get(id));
|
||||
}
|
||||
|
||||
public void addTile(Vec3i blockInWorld, BlockFace face, TileData tile) {
|
||||
@Override
|
||||
public void onTileAdded(Vec3i blockInWorld, BlockFace face, TileData tile) {
|
||||
AddTile change = cache.grab(AddTile.class);
|
||||
change.getPacket().set(tile, blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld)));
|
||||
server.requestChange(change);
|
||||
}
|
||||
|
||||
public void addTile(Vec3i blockInWorld, BlockFace face, String id) {
|
||||
addTile(blockInWorld, face, TileDataRegistry.getInstance().get(id));
|
||||
}
|
||||
|
||||
public void removeTile(Vec3i blockInWorld, BlockFace face, int tag) {
|
||||
@Override
|
||||
public void onTileRemoved(Vec3i blockInWorld, BlockFace face, int tag) {
|
||||
RemoveTile change = cache.grab(RemoveTile.class);
|
||||
change.getPacket().set(blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld)), tag);
|
||||
server.requestChange(change);
|
||||
}
|
||||
|
||||
public <T extends EntityData> void changeEntity(
|
||||
T entity,
|
||||
StateChange<T> stateChange
|
||||
@Override
|
||||
public void onEntityAdded(EntityData entity) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityRemoved(long entityId) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeChanged(float change) {
|
||||
// TODO Auto-generated method stub
|
||||
System.err.println("WorldAccessor.onTimeChanged() NYI!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <SE extends StatefulObject & EntityGeneric> void onEntityChanged(
|
||||
SE entity,
|
||||
StateChange<SE> stateChange
|
||||
) {
|
||||
ChangeEntity change = cache.grab(ChangeEntity.class);
|
||||
change.set(entity, stateChange);
|
||||
change.set((EntityData) entity, stateChange);
|
||||
server.requestChange(change);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogic;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContextRO;
|
||||
|
||||
public class HangingTileLogic extends TileLogic implements UpdateableTile {
|
||||
|
||||
@ -27,15 +29,15 @@ public class HangingTileLogic extends TileLogic implements UpdateableTile {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(TileTickContext context) {
|
||||
public void update(ServerTileContext context) {
|
||||
if (!canOccupyFace(context)) {
|
||||
context.removeThisTile();
|
||||
context.removeTile();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canOccupyFace(TileTickContext context) {
|
||||
BlockLogic host = context.getBlock();
|
||||
public boolean canOccupyFace(ServerTileContextRO context) {
|
||||
BlockLogic host = context.logic().getBlock();
|
||||
if (host == null)
|
||||
return false;
|
||||
|
||||
@ -45,13 +47,14 @@ public class HangingTileLogic extends TileLogic implements UpdateableTile {
|
||||
if (canBeSquashed(context))
|
||||
return true;
|
||||
|
||||
return context.evalComplementary(ctxt -> {
|
||||
BlockLogic complHost = ctxt.getBlock();
|
||||
return complHost == null || !complHost.isSolid(ctxt, context.getFace());
|
||||
});
|
||||
context.pushOpposite();
|
||||
BlockLogic complHost = context.logic().getBlock();
|
||||
boolean result = complHost == null || !complHost.isSolid(context, context.getFace());
|
||||
context.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean canBeSquashed(TileTickContext context) {
|
||||
public boolean canBeSquashed(ServerTileContextRO context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import ru.windcorp.progressia.common.world.DefaultChunkData;
|
||||
import ru.windcorp.progressia.common.world.rels.RelFace;
|
||||
import ru.windcorp.progressia.common.world.TileDataStack;
|
||||
import ru.windcorp.progressia.server.world.DefaultChunkLogic;
|
||||
import ru.windcorp.progressia.server.world.TickContextMutable;
|
||||
import ru.windcorp.progressia.server.world.TileLogicStackRO;
|
||||
import ru.windcorp.progressia.server.world.block.BlockTickContext;
|
||||
|
||||
public interface TSTickContext extends BlockTickContext {
|
||||
|
||||
/*
|
||||
* Specifications
|
||||
*/
|
||||
|
||||
RelFace getFace();
|
||||
|
||||
/*
|
||||
* Getters
|
||||
*/
|
||||
|
||||
default TileLogicStackRO getTLSOrNull() {
|
||||
DefaultChunkLogic chunkLogic = getChunkLogic();
|
||||
if (chunkLogic == null)
|
||||
return null;
|
||||
|
||||
return chunkLogic.getTilesOrNull(getBlockInChunk(), getFace());
|
||||
}
|
||||
|
||||
default TileLogicStackRO getTLS() {
|
||||
return getChunkLogic().getTiles(getBlockInChunk(), getFace());
|
||||
}
|
||||
|
||||
default TileDataStack getTDSOrNull() {
|
||||
DefaultChunkData chunkData = getChunkData();
|
||||
if (chunkData == null)
|
||||
return null;
|
||||
|
||||
return chunkData.getTilesOrNull(getBlockInChunk(), getFace());
|
||||
}
|
||||
|
||||
default TileDataStack getTDS() {
|
||||
return getChunkData().getTiles(getBlockInChunk(), getFace());
|
||||
}
|
||||
|
||||
/*
|
||||
* Contexts
|
||||
*/
|
||||
|
||||
default TileTickContext forLayer(int layer) {
|
||||
return TickContextMutable.start().withServer(getServer()).withBlock(getBlockInWorld()).withFace(getFace())
|
||||
.withLayer(layer);
|
||||
}
|
||||
|
||||
default boolean forEachTile(Consumer<TileTickContext> action) {
|
||||
TickContextMutable context = TickContextMutable.uninitialized();
|
||||
|
||||
TileDataStack stack = getTDSOrNull();
|
||||
if (stack == null || stack.isEmpty())
|
||||
return false;
|
||||
|
||||
for (int layer = 0; layer < stack.size(); ++layer) {
|
||||
context.rebuild().withServer(getServer()).withBlock(getBlockInWorld()).withFace(getFace()).withLayer(layer);
|
||||
action.accept(context);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
default TSTickContext getComplementary() {
|
||||
return TickContextMutable.copyWorld(this)
|
||||
.withBlock(getBlockInWorld().add_(getFace().getVector(getUp())))
|
||||
.withFace(getFace().getCounter())
|
||||
.build();
|
||||
}
|
||||
|
||||
default <R> R evalComplementary(Function<TSTickContext, R> action) {
|
||||
Objects.requireNonNull(action, "action");
|
||||
return action.apply(getComplementary());
|
||||
}
|
||||
|
||||
default void forComplementary(Consumer<TSTickContext> action) {
|
||||
Objects.requireNonNull(action, "action");
|
||||
evalComplementary((Function<TSTickContext, Void>) ctxt -> {
|
||||
action.accept(ctxt);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -18,12 +18,14 @@
|
||||
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContextRO;
|
||||
import ru.windcorp.progressia.server.world.ticking.TickingPolicy;
|
||||
|
||||
public interface TickableTile {
|
||||
|
||||
void tick(TileTickContext context);
|
||||
void tick(ServerTileContext context);
|
||||
|
||||
TickingPolicy getTickingPolicy(TileTickContext context);
|
||||
TickingPolicy getTickingPolicy(ServerTileContextRO context);
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ package ru.windcorp.progressia.server.world.tile;
|
||||
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||
import ru.windcorp.progressia.common.world.generic.TileGeneric;
|
||||
import ru.windcorp.progressia.common.world.rels.RelFace;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContextRO;
|
||||
|
||||
public class TileLogic extends Namespaced implements TileGeneric {
|
||||
|
||||
@ -28,7 +29,7 @@ public class TileLogic extends Namespaced implements TileGeneric {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public boolean canOccupyFace(TileTickContext context) {
|
||||
public boolean canOccupyFace(ServerTileContextRO context) {
|
||||
return canOccupyFace(context.getFace());
|
||||
}
|
||||
|
||||
@ -36,7 +37,7 @@ public class TileLogic extends Namespaced implements TileGeneric {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isSolid(TileTickContext context) {
|
||||
public boolean isSolid(ServerTileContextRO context) {
|
||||
return isSolid();
|
||||
}
|
||||
|
||||
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import ru.windcorp.progressia.common.world.tile.TileData;
|
||||
import ru.windcorp.progressia.server.world.TileLogicStackRO;
|
||||
import ru.windcorp.progressia.common.world.TileDataStack;
|
||||
import ru.windcorp.progressia.common.world.TileDataReference;
|
||||
|
||||
public interface TileTickContext extends TSTickContext {
|
||||
|
||||
/*
|
||||
* Specifications
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the current layer.
|
||||
*
|
||||
* @return the layer that the tile being ticked occupies in the tile stack
|
||||
*/
|
||||
int getLayer();
|
||||
|
||||
/*
|
||||
* Getters
|
||||
*/
|
||||
|
||||
default TileLogic getTile() {
|
||||
TileLogicStackRO stack = getTLSOrNull();
|
||||
if (stack == null)
|
||||
return null;
|
||||
return stack.get(getLayer());
|
||||
}
|
||||
|
||||
default TileData getTileData() {
|
||||
TileDataStack stack = getTDSOrNull();
|
||||
if (stack == null)
|
||||
return null;
|
||||
return stack.get(getLayer());
|
||||
}
|
||||
|
||||
default TileDataReference getReference() {
|
||||
return getTDS().getReference(getLayer());
|
||||
}
|
||||
|
||||
default int getTag() {
|
||||
return getTDS().getTagByIndex(getLayer());
|
||||
}
|
||||
|
||||
/*
|
||||
* Contexts
|
||||
*/
|
||||
|
||||
/*
|
||||
* Convenience methods - changes
|
||||
*/
|
||||
|
||||
default void removeThisTile() {
|
||||
getAccessor().removeTile(getBlockInWorld(), getFace(), getTag());
|
||||
}
|
||||
|
||||
}
|
@ -18,8 +18,10 @@
|
||||
|
||||
package ru.windcorp.progressia.server.world.tile;
|
||||
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContext;
|
||||
|
||||
public interface UpdateableTile {
|
||||
|
||||
void update(TileTickContext context);
|
||||
void update(ServerTileContext context);
|
||||
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ public class TestContent {
|
||||
ru.windcorp.progressia.server.comms.Client client
|
||||
) {
|
||||
Vec3i blockInWorld = ((ControlBreakBlockData) packet.getControl()).getBlockInWorld();
|
||||
server.getWorldAccessor().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air"));
|
||||
server.createContext().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air"));
|
||||
}
|
||||
|
||||
private static void onBlockPlaceTrigger(ControlData control) {
|
||||
@ -403,7 +403,7 @@ public class TestContent {
|
||||
Vec3i blockInWorld = controlData.getBlockInWorld();
|
||||
if (server.getWorld().getData().getChunkByBlock(blockInWorld) == null)
|
||||
return;
|
||||
server.getWorldAccessor().setBlock(blockInWorld, block);
|
||||
server.createContext().setBlock(blockInWorld, block);
|
||||
}
|
||||
|
||||
private static void onTilePlaceTrigger(ControlData control) {
|
||||
@ -428,7 +428,7 @@ public class TestContent {
|
||||
return;
|
||||
if (server.getWorld().getData().getTiles(blockInWorld, face).isFull())
|
||||
return;
|
||||
server.getWorldAccessor().addTile(blockInWorld, face, tile);
|
||||
server.createContext().addTile(blockInWorld, face, tile);
|
||||
}
|
||||
|
||||
private static void registerMisc() {
|
||||
|
@ -19,7 +19,7 @@
|
||||
package ru.windcorp.progressia.test;
|
||||
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.server.world.TickContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerWorldContext;
|
||||
import ru.windcorp.progressia.server.world.entity.EntityLogic;
|
||||
|
||||
public class TestEntityLogicStatie extends EntityLogic {
|
||||
@ -29,13 +29,13 @@ public class TestEntityLogicStatie extends EntityLogic {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(EntityData entity, TickContext context) {
|
||||
public void tick(EntityData entity, ServerWorldContext context) {
|
||||
super.tick(entity, context);
|
||||
|
||||
TestEntityDataStatie statie = (TestEntityDataStatie) entity;
|
||||
|
||||
int size = (int) (18 + 6 * Math.sin(entity.getAge()));
|
||||
context.getServer().getWorldAccessor().changeEntity(statie, e -> e.setSizeNow(size));
|
||||
context.changeEntity(statie, e -> e.setSizeNow(size));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,11 +20,11 @@ package ru.windcorp.progressia.test;
|
||||
|
||||
import ru.windcorp.progressia.common.world.rels.RelFace;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogic;
|
||||
import ru.windcorp.progressia.server.world.block.BlockTickContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContext;
|
||||
import ru.windcorp.progressia.server.world.context.ServerTileContextRO;
|
||||
import ru.windcorp.progressia.server.world.ticking.TickingPolicy;
|
||||
import ru.windcorp.progressia.server.world.tile.HangingTileLogic;
|
||||
import ru.windcorp.progressia.server.world.tile.TickableTile;
|
||||
import ru.windcorp.progressia.server.world.tile.TileTickContext;
|
||||
|
||||
public class TestTileLogicGrass extends HangingTileLogic implements TickableTile {
|
||||
|
||||
@ -33,7 +33,7 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canOccupyFace(TileTickContext context) {
|
||||
public boolean canOccupyFace(ServerTileContextRO context) {
|
||||
return context.getFace() != RelFace.DOWN && super.canOccupyFace(context);
|
||||
}
|
||||
|
||||
@ -43,34 +43,31 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickingPolicy getTickingPolicy(TileTickContext context) {
|
||||
public TickingPolicy getTickingPolicy(ServerTileContextRO context) {
|
||||
return TickingPolicy.RANDOM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(TileTickContext context) {
|
||||
public void tick(ServerTileContext context) {
|
||||
if (!isLocationSuitable(context)) {
|
||||
// context.removeThisTile();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeSquashed(TileTickContext context) {
|
||||
public boolean canBeSquashed(ServerTileContextRO context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isLocationSuitable(TileTickContext context) {
|
||||
private boolean isLocationSuitable(ServerTileContextRO context) {
|
||||
return canOccupyFace(context) && isBlockAboveTransparent(context);
|
||||
}
|
||||
|
||||
private boolean isBlockAboveTransparent(BlockTickContext context) {
|
||||
return context.evalNeighbor(RelFace.UP, bctxt -> {
|
||||
BlockLogic block = bctxt.getBlock();
|
||||
if (block == null)
|
||||
return true;
|
||||
|
||||
return block.isTransparent(bctxt);
|
||||
});
|
||||
private boolean isBlockAboveTransparent(ServerTileContextRO context) {
|
||||
// TODO rework
|
||||
context.pushRelative(RelFace.UP.resolve(context.getServer().getWorld().getUp(context.getLocation())));
|
||||
BlockLogic block = context.logic().getBlock();
|
||||
return context.popAndReturn(block == null || block.isTransparent(context));
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user