public Universe(ISaveFile saveFile, Mod mod) { SaveFile = saveFile; _mod = mod; _startWorld = new World(this); _startWorld.Generator = new WorldGenerator(_startWorld); _modData = new ModData { Materials = mod.Materials.Values.Select((m, i) => { m.Index = i; return m; }).ToList(), Models = mod.MobTypes.Values.Select((m, i) => { m.Model.Index = i; return m.Model; }).ToList(), }; for (int i = 0; i < 20; ++i) { MobType type = null; if (_mod.MobTypes.Count > 0) { string nextMobType = _mod.MobTypes.Keys.ElementAt(i % _mod.MobTypes.Count); type = _mod.MobTypes[nextMobType]; } var e = new Entity() { PositionData = new PositionData(), IsAiControlled = true, MobName = type?.Name, ModelIndex = type?.Model.Index }; Movement.Respawn(e.PositionData); _entities.Add(e); } var thread = new Thread(() => RunUniverse()); thread.IsBackground = true; thread.Start(); }
public WorldGenerator(World world) { _world = world; }
private static void SetPositionFromCollisionPosition(PhysicsValues physicsValues, World world, PositionData positionData) { if (positionData.IsFalling) { positionData.Placement.Pos = positionData.InternalPos; return; } var entityPos = positionData.InternalPos; var blockPos = (BlockPos)entityPos; /* * When standing on an edge, the entities bottom center might be hanging in the air. * Find the true floor position by iterating downward and looking for the floor. */ if (world[blockPos] == 0 && world[blockPos - BlockOffset.UnitY] == 0) { blockPos -= BlockOffset.UnitY; entityPos -= EntityOffset.UnitY; if (world[blockPos - new BlockOffset(0, 2, 0)] == 0) { blockPos -= BlockOffset.UnitY; entityPos -= EntityOffset.UnitY; } } var entityOffset = entityPos - blockPos; double yOffset = 0; /* * Take the integral of all floor heights in a 2 by 2 area around the center. * Since the height is piecewise constant, this is a weighted sum of the heights around the entity position. */ yOffset += (1 - entityOffset.X) * FindHeight(world, blockPos - BlockOffset.UnitX); yOffset += entityOffset.X * FindHeight(world, blockPos + BlockOffset.UnitX); yOffset += (1 - entityOffset.Z) * FindHeight(world, blockPos - BlockOffset.UnitZ); yOffset += entityOffset.Z * FindHeight(world, blockPos + BlockOffset.UnitZ); yOffset += (1 - entityOffset.X) * (1 - entityOffset.Z) * FindHeight(world, blockPos + new BlockOffset(-1, 0, -1)); yOffset += (1 - entityOffset.X) * entityOffset.Z * FindHeight(world, blockPos + new BlockOffset(-1, 0, 1)); yOffset += entityOffset.X * (1 - entityOffset.Z) * FindHeight(world, blockPos + new BlockOffset(1, 0, -1)); yOffset += entityOffset.X * entityOffset.Z * FindHeight(world, blockPos + new BlockOffset(1, 0, 1)); // Normalize. yOffset *= 0.25; entityPos += new EntityOffset(0, yOffset, 0); positionData.Placement.Pos = entityPos; }
private static bool MoveZ(PhysicsValues physicsValues, World world, PositionData positionData, double distance) { EntityPos position = positionData.InternalPos; long p = position.Z; int cx0 = GetBlockCoordinate(position.X - (long)(0.5 * physicsValues.PlayerWidth * (1L << 32)) + 1); int cx1 = GetBlockCoordinate(position.X + (long)(0.5 * physicsValues.PlayerWidth * (1L << 32)) - 1); int cy0 = GetBlockCoordinate(position.Y + 1); int cy1 = GetBlockCoordinate(position.Y + (long)(physicsValues.PlayerHeight * (1L << 32)) - 1); bool hasCollided = MoveInternal(p, physicsValues.PlayerWidth * 0.5, distance, cz => AllPassable(world, new BlockPos(cx0, cy0, cz), new BlockPos(cx1, cy1, cz)), out p); position.Z = p; positionData.InternalPos = position; return hasCollided; }
public static void MoveEntity(PhysicsValues physicsValues, World world, PositionData positionData, GameDuration elapsedDuration, EntityOffset offset) { offset.Y -= 0.5 * elapsedDuration.Seconds * physicsValues.Gravity; if (MoveY(physicsValues, world, positionData, offset.Y * elapsedDuration.Seconds)) { positionData.IsFalling = false; } else { if (!positionData.IsFalling) { /* Re-evaluate the fall from the apparent position. */ positionData.InternalPos = positionData.Placement.Pos; MoveY(physicsValues, world, positionData, offset.Y * elapsedDuration.Seconds); positionData.IsFalling = true; } } if (positionData.IsFalling) { offset.Y -= 0.5 * elapsedDuration.Seconds * physicsValues.Gravity; } else { if (Math.Abs(offset.Y) > Math.Sqrt(2 * physicsValues.Gravity * physicsValues.TerminalHeight)) { Respawn(positionData); } offset.Y = 0; } if (offset.X != 0 || offset.Z != 0) { long savedY = positionData.InternalPos.Y; if (!positionData.IsFalling && world[(BlockPos)positionData.InternalPos - BlockOffset.UnitY] != 0) { // Temporarily move the character up a block so that it can climb up stairs. MoveY(physicsValues, world, positionData, 1); } EntityPos positionBeforeMovement = positionData.InternalPos; double moveX = offset.X * elapsedDuration.Seconds; double moveZ = offset.Z * elapsedDuration.Seconds; if (offset.X > offset.Z) { MoveX(physicsValues, world, positionData, moveX); MoveZ(physicsValues, world, positionData, moveZ); } else { MoveZ(physicsValues, world, positionData, moveZ); MoveX(physicsValues, world, positionData, moveX); } var moveDelta = positionData.InternalPos - positionBeforeMovement; moveX -= moveDelta.X; moveZ -= moveDelta.Z; if (!positionData.IsFalling) { // Attempt to move the character back down to the ground in case we didn't climb a stair. MoveY(physicsValues, world, positionData, (savedY - positionData.InternalPos.Y) / (double)(1L << 32)); savedY = positionData.InternalPos.Y; // Attempt to move the caracter down an additional block so that it can walk down stairs. if (!MoveY(physicsValues, world, positionData, -((1L << 32) + 1) / (double)(1L << 32))) { positionData.InternalPos.Y = savedY; positionData.IsFalling = true; } } // Attempt to continue movement at this new (lower) Y position. if (offset.X > offset.Z) { if (MoveX(physicsValues, world, positionData, moveX)) offset.X = 0; if (MoveZ(physicsValues, world, positionData, moveZ)) offset.Z = 0; } else { if (MoveZ(physicsValues, world, positionData, moveZ)) offset.Z = 0; if (MoveX(physicsValues, world, positionData, moveX)) offset.X = 0; } } positionData.Velocity = offset; SetPositionFromCollisionPosition(physicsValues, world, positionData); }
private static double FindHeight(World world, BlockPos blockPos) { if (world[blockPos] != 0) return 1; if (world[blockPos] == 0 && world[blockPos - BlockOffset.UnitY] == 0) return -1; return 0; }
private static bool AllPassable(World world, BlockPos block0, BlockPos block1) { for (int x = block0.X; x <= block1.X; ++x) { for (int y = block0.Y; y <= block1.Y; ++y) { for (int z = block0.Z; z <= block1.Z; ++z) { var blockPos = new BlockPos(x, y, z); var chunk = world.GetChunk((ChunkPos)blockPos); if (!chunk.IsCreated) return false; if (world[blockPos] != 0) { return false; } } } } return true; }
public Chunk(World world, ChunkPos chunkPos) { World = world; Pos = chunkPos; }