mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
Store the player position on the server to prioritize terrain generation.
This commit is contained in:
parent
cfc7b903e6
commit
4d092126cc
14
src/game.zig
14
src/game.zig
@ -45,8 +45,7 @@ pub const camera = struct {
|
||||
};
|
||||
|
||||
pub const Player = struct {
|
||||
pub var pos: Vec3d = Vec3d{0, 0, 0};
|
||||
pub var vel: Vec3d = Vec3d{0, 0, 0};
|
||||
pub var super: main.server.Entity = .{};
|
||||
pub var id: u32 = 0;
|
||||
pub var isFlying: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(true);
|
||||
pub var mutex: std.Thread.Mutex = std.Thread.Mutex{};
|
||||
@ -56,26 +55,26 @@ pub const Player = struct {
|
||||
pub var health: f32 = 4.5;
|
||||
|
||||
fn loadFrom(json: JsonElement) !void {
|
||||
// TODO: super.loadFrom(json);
|
||||
super.loadFrom(json);
|
||||
try inventory__SEND_CHANGES_TO_SERVER.loadFromJson(json.getChild("inventory"));
|
||||
}
|
||||
|
||||
pub fn setPosBlocking(newPos: Vec3d) void {
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
pos = newPos;
|
||||
super.pos = newPos;
|
||||
}
|
||||
|
||||
pub fn getPosBlocking() Vec3d {
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
return pos;
|
||||
return super.pos;
|
||||
}
|
||||
|
||||
pub fn getVelBlocking() Vec3d {
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
return vel;
|
||||
return super.vel;
|
||||
}
|
||||
};
|
||||
|
||||
@ -152,7 +151,6 @@ pub const World = struct {
|
||||
// ModLoader.postWorldGen(registries);
|
||||
try assets.loadWorldAssets("serverAssets", self.blockPalette);
|
||||
try Player.loadFrom(json.getChild("player"));
|
||||
Player.pos = .{-2000, 100, 4000}; // TODO
|
||||
Player.id = json.get(u32, "player_id", std.math.maxInt(u32));
|
||||
}
|
||||
|
||||
@ -347,7 +345,7 @@ pub fn update(deltaTime: f64) !void {
|
||||
{
|
||||
Player.mutex.lock();
|
||||
defer Player.mutex.unlock();
|
||||
Player.pos += movement*@splat(3, deltaTime);
|
||||
Player.super.pos += movement*@splat(3, deltaTime);
|
||||
}
|
||||
try world.?.update();
|
||||
}
|
@ -164,7 +164,11 @@ pub const JsonElement = union(JsonType) {
|
||||
}
|
||||
},
|
||||
else => {
|
||||
@compileError("Unknown value type.");
|
||||
if(@TypeOf(value) == JsonElement) {
|
||||
return value;
|
||||
} else {
|
||||
@compileError("Unknown value type.");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -538,7 +538,7 @@ pub fn main() !void {
|
||||
try renderer.init();
|
||||
defer renderer.deinit();
|
||||
|
||||
network.init();
|
||||
try network.init();
|
||||
|
||||
try renderer.RenderStructure.init();
|
||||
defer renderer.RenderStructure.deinit();
|
||||
|
@ -80,7 +80,7 @@ const Socket = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn init() void {
|
||||
pub fn init() !void {
|
||||
try Socket.startup();
|
||||
inline for(@typeInfo(Protocols).Struct.decls) |decl| {
|
||||
if(@TypeOf(@field(Protocols, decl.name)) == type) {
|
||||
@ -610,15 +610,16 @@ pub const Protocols = struct {
|
||||
try conn.user.?.initPlayer(name);
|
||||
const jsonObject = try JsonElement.initObject(main.threadAllocator);
|
||||
defer jsonObject.free(main.threadAllocator);
|
||||
try jsonObject.put("player", try conn.user.?.player.save(main.threadAllocator));
|
||||
// TODO:
|
||||
// jsonObject.put("player", ((User)conn).player.save());
|
||||
// jsonObject.put("player_id", ((User)conn).player.id);
|
||||
// jsonObject.put("blockPalette", Server.world.blockPalette.save());
|
||||
// JsonObject spawn = new JsonObject();
|
||||
// spawn.put("x", Server.world.spawn.x);
|
||||
// spawn.put("y", Server.world.spawn.y);
|
||||
// spawn.put("z", Server.world.spawn.z);
|
||||
// jsonObject.put("spawn", spawn);
|
||||
const spawn = try JsonElement.initObject(main.threadAllocator);
|
||||
try spawn.put("x", main.server.world.?.spawn[0]);
|
||||
try spawn.put("y", main.server.world.?.spawn[1]);
|
||||
try spawn.put("z", main.server.world.?.spawn[2]);
|
||||
try jsonObject.put("spawn", spawn);
|
||||
|
||||
const outData = try jsonObject.toStringEfficient(main.threadAllocator, &[1]u8{stepServerData});
|
||||
defer main.threadAllocator.free(outData);
|
||||
try conn.sendImportant(id, outData);
|
||||
@ -751,9 +752,7 @@ pub const Protocols = struct {
|
||||
pub const playerPosition = struct {
|
||||
const id: u8 = 4;
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
_ = conn;
|
||||
_ = data;
|
||||
// TODO: ((User)conn).receiveData(data, offset);
|
||||
conn.user.?.receiveData(data);
|
||||
}
|
||||
var lastPositionSent: u16 = 0;
|
||||
pub fn send(conn: *Connection, playerPos: Vec3d, playerVel: Vec3d, time: u16) !void {
|
||||
@ -1053,7 +1052,7 @@ pub const Protocols = struct {
|
||||
try sendInventory_full(conn, game.Player.inventory__SEND_CHANGES_TO_SERVER);
|
||||
if(remaining != 0) {
|
||||
// Couldn't collect everything → drop it again.
|
||||
try itemStackDrop(conn, ItemStack{.item=item, .amount=remaining}, game.Player.pos, Vec3f{0, 0, 0}, 0);
|
||||
try itemStackDrop(conn, ItemStack{.item=item, .amount=remaining}, game.Player.super.pos, Vec3f{0, 0, 0}, 0);
|
||||
}
|
||||
},
|
||||
type_timeAndBiome => {
|
||||
@ -1167,13 +1166,15 @@ pub const Protocols = struct {
|
||||
try addHeaderAndSendImportant(conn, type_itemStackCollect, string);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// public void sendTimeAndBiome(User user, ServerWorld world) {
|
||||
// JsonObject data = new JsonObject();
|
||||
// data.put("time", world.gameTime);
|
||||
// data.put("biome", world.getBiome((int)user.player.getPosition().x, (int)user.player.getPosition().y, (int)user.player.getPosition().z).getRegistryID().toString());
|
||||
// addHeaderAndSendUnimportant(user, TIME_AND_BIOME, data.toString().getBytes(StandardCharsets.UTF_8));
|
||||
// }
|
||||
pub fn sendTimeAndBiome(conn: *Connection, world: *const main.server.ServerWorld) !void {
|
||||
var json = try JsonElement.initObject(main.threadAllocator);
|
||||
defer json.free(main.threadAllocator);
|
||||
try json.put("time", world.gameTime);
|
||||
// TODO: json.put("biome", world.getBiome((int)user.player.getPosition().x, (int)user.player.getPosition().y, (int)user.player.getPosition().z).getRegistryID().toString());
|
||||
const string = try json.toString(main.threadAllocator);
|
||||
defer main.threadAllocator.free(string);
|
||||
try addHeaderAndSendUnimportant(conn, type_timeAndBiome, string);
|
||||
}
|
||||
};
|
||||
pub const chat = struct {
|
||||
const id: u8 = 10;
|
||||
|
511
src/server/Entity.zig
Normal file
511
src/server/Entity.zig
Normal file
@ -0,0 +1,511 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const main = @import("root");
|
||||
const JsonElement = main.JsonElement;
|
||||
const vec = main.vec;
|
||||
const Vec3f = vec.Vec3f;
|
||||
const Vec3d = vec.Vec3d;
|
||||
|
||||
pos: Vec3d = .{0, 0, 0},
|
||||
vel: Vec3d = .{0, 0, 0},
|
||||
rot: Vec3f = .{0, 0, 0},
|
||||
|
||||
fn loadVec3f(json: JsonElement) Vec3f {
|
||||
return .{
|
||||
json.get(f32, "x", 0),
|
||||
json.get(f32, "y", 0),
|
||||
json.get(f32, "z", 0),
|
||||
};
|
||||
}
|
||||
|
||||
fn loadVec3d(json: JsonElement) Vec3d {
|
||||
return .{
|
||||
json.get(f64, "x", 0),
|
||||
json.get(f64, "y", 0),
|
||||
json.get(f64, "z", 0),
|
||||
};
|
||||
}
|
||||
|
||||
fn saveVec3(allocator: Allocator, vector: anytype) !JsonElement {
|
||||
const json = try JsonElement.initObject(allocator);
|
||||
try json.put("x", vector[0]);
|
||||
try json.put("y", vector[1]);
|
||||
try json.put("z", vector[2]);
|
||||
return json;
|
||||
}
|
||||
|
||||
pub fn loadFrom(self: *@This(), json: JsonElement) void {
|
||||
self.pos = loadVec3d(json.getChild("position"));
|
||||
self.vel = loadVec3d(json.getChild("velocity"));
|
||||
self.rot = loadVec3f(json.getChild("rotation"));
|
||||
// TODO:
|
||||
// health = json.getFloat("health", maxHealth);
|
||||
// hunger = json.getFloat("hunger", maxHunger);
|
||||
// name = json.getString("name", "");
|
||||
}
|
||||
|
||||
pub fn save(self: *@This(), allocator: Allocator) !JsonElement {
|
||||
const json = try JsonElement.initObject(allocator);
|
||||
// TODO: json.put("id", type.getRegistryID().toString());
|
||||
try json.put("position", try saveVec3(allocator, self.pos));
|
||||
try json.put("velocity", try saveVec3(allocator, self.vel));
|
||||
try json.put("rotation", try saveVec3(allocator, self.rot));
|
||||
// TODO:
|
||||
// json.put("health", health);
|
||||
// json.put("hunger", hunger);
|
||||
// if(!name.isEmpty()) {
|
||||
// json.put("name", name);
|
||||
// }
|
||||
return json;
|
||||
}
|
||||
|
||||
// Entity {
|
||||
|
||||
// protected World world;
|
||||
// public double targetVX, targetVZ; // The velocity the AI wants the entity to have.
|
||||
|
||||
// protected double scale = 1f;
|
||||
// public final double stepHeight;
|
||||
|
||||
// private final EntityType type;
|
||||
|
||||
// private final EntityAI entityAI;
|
||||
|
||||
// public float health, hunger;
|
||||
// public final float maxHealth, maxHunger;
|
||||
|
||||
// public int id;
|
||||
|
||||
// public String name = "";
|
||||
|
||||
// private static int currentID = 0;
|
||||
|
||||
// /**
|
||||
// * Used as hitbox.
|
||||
// */
|
||||
// public double width = CubyzMath.roundToAvoidPrecisionProblems(0.35), height = CubyzMath.roundToAvoidPrecisionProblems(1.8); // TODO: Make this a proper interface or switch to fixed-point arithmetic.
|
||||
// /**
|
||||
// * @param type
|
||||
// * @param ai
|
||||
// * @param world
|
||||
// * @param maxHealth
|
||||
// * @param maxHunger
|
||||
// * @param stepHeight height the entity can move upwards without jumping.
|
||||
// */
|
||||
// public Entity(EntityType type, EntityAI ai, World world, float maxHealth, float maxHunger, float stepHeight) {
|
||||
// this.type = type;
|
||||
// this.world = world;
|
||||
// this.maxHealth = health = maxHealth;
|
||||
// this.maxHunger = hunger = maxHunger;
|
||||
// this.stepHeight = stepHeight;
|
||||
// entityAI = ai;
|
||||
|
||||
// id = currentID++;
|
||||
// }
|
||||
|
||||
// public double getScale() {
|
||||
// return scale;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Checks collision against all blocks within the hitbox and updates positions.
|
||||
// * @return The height of the step taken. Needed for hunger calculations.
|
||||
// */
|
||||
// protected double collisionDetection(float deltaTime) {
|
||||
// // Simulate movement in all directions and prevent movement in a direction that would get the player into a block:
|
||||
// int minX = (int)Math.floor(position.x - width);
|
||||
// int maxX = (int)Math.ceil(position.x + width) - 1;
|
||||
// int minY = (int)Math.floor(position.y);
|
||||
// int maxY = (int)Math.ceil(position.y + height) - 1;
|
||||
// int minZ = (int)Math.floor(position.z - width);
|
||||
// int maxZ = (int)Math.ceil(position.z + width) - 1;
|
||||
// double deltaX = vx*deltaTime;
|
||||
// double deltaY = vy*deltaTime;
|
||||
// double deltaZ = vz*deltaTime;
|
||||
// Vector4d change = new Vector4d(deltaX, 0, 0, 0);
|
||||
// double step = 0.0f;
|
||||
// if (deltaX < 0) {
|
||||
// int minX2 = (int)Math.floor(position.x - width + deltaX);
|
||||
// // First check for partial blocks:
|
||||
// for(int y = minY; y <= maxY; y++) {
|
||||
// for(int z = minZ; z <= maxZ; z++) {
|
||||
// checkBlock(minX, y, z, change);
|
||||
// }
|
||||
// }
|
||||
// if (minX2 != minX && deltaX == change.x) {
|
||||
// outer:
|
||||
// for(int y = minY; y <= maxY; y++) {
|
||||
// for(int z = minZ; z <= maxZ; z++) {
|
||||
// if (checkBlock(minX2, y, z, change)) {
|
||||
// change.x = 0;
|
||||
// position.x = minX2 + 1 + width;
|
||||
// break outer;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else if (deltaX > 0) {
|
||||
// int maxX2 = (int)Math.floor(position.x + width + deltaX);
|
||||
// // First check for partial blocks:
|
||||
// for(int y = minY; y <= maxY; y++) {
|
||||
// for(int z = minZ; z <= maxZ; z++) {
|
||||
// checkBlock(maxX, y, z, change);
|
||||
// }
|
||||
// }
|
||||
// if (maxX2 != maxX && deltaX == change.x) {
|
||||
// outer:
|
||||
// for(int y = minY; y <= maxY; y++) {
|
||||
// for(int z = minZ; z <= maxZ; z++) {
|
||||
// if (checkBlock(maxX2, y, z, change)) {
|
||||
// change.x = 0;
|
||||
// position.x = maxX2 - width;
|
||||
// break outer;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// position.x += change.x;
|
||||
// if (deltaX != change.x) {
|
||||
// vx = 0;
|
||||
// change.w = 0; // Don't step if the player walks into a wall.
|
||||
// }
|
||||
// step = Math.max(step, change.w);
|
||||
// change.x = 0;
|
||||
// change.y = deltaY;
|
||||
// minX = (int)Math.floor(position.x - width);
|
||||
// maxX = (int)Math.ceil(position.x + width) - 1;
|
||||
// if (deltaY < 0) {
|
||||
// int minY2 = (int)Math.floor(position.y + deltaY);
|
||||
// // First check for partial blocks:
|
||||
// for(int x = minX; x <= maxX; x++) {
|
||||
// for(int z = minZ; z <= maxZ; z++) {
|
||||
// checkBlock(x, minY, z, change);
|
||||
// }
|
||||
// }
|
||||
// if (minY2 != minY && deltaY == change.y) {
|
||||
// outer:
|
||||
// for(int x = minX; x <= maxX; x++) {
|
||||
// for(int z = minZ; z <= maxZ; z++) {
|
||||
// if (checkBlock(x, minY2, z, change)) {
|
||||
// change.y = 0;
|
||||
// position.y = minY2 + 1;
|
||||
// break outer;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else if (deltaY > 0) {
|
||||
// int maxY2 = (int)Math.floor(position.y + height + deltaY);
|
||||
// // First check for partial blocks:
|
||||
// for(int x = minX; x <= maxX; x++) {
|
||||
// for(int z = minZ; z <= maxZ; z++) {
|
||||
// checkBlock(x, maxY, z, change);
|
||||
// }
|
||||
// }
|
||||
// if (maxY2 != maxY && deltaY == change.y) {
|
||||
// outer:
|
||||
// for(int x = minX; x <= maxX; x++) {
|
||||
// for(int z = minZ; z <= maxZ; z++) {
|
||||
// if (checkBlock(x, maxY2, z, change)) {
|
||||
// change.y = 0;
|
||||
// position.y = maxY2 - height;
|
||||
// break outer;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// position.y += change.y;
|
||||
// if (deltaY != change.y) {
|
||||
// stopVY();
|
||||
// }
|
||||
// change.w = 0; // Don't step in y-direction.
|
||||
// step = Math.max(step, change.w);
|
||||
// change.y = 0;
|
||||
// change.z = deltaZ;
|
||||
// minY = (int)Math.floor(position.y);
|
||||
// maxY = (int)Math.ceil(position.y + height) - 1;
|
||||
// if (deltaZ < 0) {
|
||||
// int minZ2 = (int)Math.floor(position.z - width + deltaZ);
|
||||
// // First check for partial blocks:
|
||||
// for(int x = minX; x <= maxX; x++) {
|
||||
// for(int y = minY; y <= maxY; y++) {
|
||||
// checkBlock(x, y, minZ, change);
|
||||
// }
|
||||
// }
|
||||
// if (minZ2 != minZ && change.z == deltaZ) {
|
||||
// outer:
|
||||
// for(int x = minX; x <= maxX; x++) {
|
||||
// for(int y = minY; y <= maxY; y++) {
|
||||
// if (checkBlock(x, y, minZ2, change)) {
|
||||
// change.z = 0;
|
||||
// position.z = minZ2 + 1 + width;
|
||||
// break outer;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else if (deltaZ > 0) {
|
||||
// int maxZ2 = (int)Math.floor(position.z + width + deltaZ);
|
||||
// // First check for partial blocks:
|
||||
// for(int x = minX; x <= maxX; x++) {
|
||||
// for(int y = minY; y <= maxY; y++) {
|
||||
// checkBlock(x, y, maxZ, change);
|
||||
// }
|
||||
// }
|
||||
// if (maxZ2 != maxZ && deltaZ == change.z) {
|
||||
// outer:
|
||||
// for(int x = minX; x <= maxX; x++) {
|
||||
// for(int y = minY; y <= maxY; y++) {
|
||||
// if (checkBlock(x, y, maxZ2, change)) {
|
||||
// change.z = 0;
|
||||
// position.z = maxZ2 - width;
|
||||
// break outer;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// position.z += change.z;
|
||||
// if (deltaZ != change.z) {
|
||||
// vz = 0;
|
||||
// change.w = 0; // Don't step if the player walks into a wall.
|
||||
// }
|
||||
// step = Math.max(step, change.w);
|
||||
// // And finally consider the stepping component:
|
||||
// position.y += step;
|
||||
// if (step != 0) vy = 0;
|
||||
// return step;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * All damage taken should get channeled through this function to remove redundant checks if the entity is dead.
|
||||
// * @param amount
|
||||
// */
|
||||
// public void takeDamage(float amount) {
|
||||
// health -= amount;
|
||||
// if (health <= 0) {
|
||||
// type.die(this);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public void stopVY() {
|
||||
// takeDamage(calculateFallDamage());
|
||||
// vy = 0;
|
||||
// }
|
||||
|
||||
// public int calculateFallDamage() {
|
||||
// if (vy < 0)
|
||||
// return (int)(8*vy*vy/900);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// public boolean checkBlock(int x, int y, int z, Vector4d displacement) {
|
||||
// int b = getBlock(x, y, z);
|
||||
// if (b != 0 && Blocks.solid(b)) {
|
||||
// if (Blocks.mode(b).changesHitbox()) {
|
||||
// return Blocks.mode(b).checkEntityAndDoCollision(this, displacement, x, y, z, b);
|
||||
// }
|
||||
// // Check for stepping:
|
||||
// if (y + 1 - position.y > 0 && y + 1 - position.y <= stepHeight) {
|
||||
// displacement.w = Math.max(displacement.w, y + 1 - position.y);
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// protected int getBlock(int x, int y, int z) {
|
||||
// return world.getBlock(x, y, z);
|
||||
// }
|
||||
|
||||
// public boolean checkBlock(int x, int y, int z) {
|
||||
// int b = getBlock(x, y, z);
|
||||
// if (b != 0 && Blocks.solid(b)) {
|
||||
// if (Blocks.mode(b).changesHitbox()) {
|
||||
// return Blocks.mode(b).checkEntity(position, width, height, x, y, z, b);
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// public boolean isOnGround() {
|
||||
// // Determine if the entity is on the ground by virtually displacing it by 0.2 below its current position:
|
||||
// Vector4d displacement = new Vector4d(0, -0.2f, 0, 0);
|
||||
// checkBlock((int)Math.floor(position.x), (int)Math.floor(position.y), (int)Math.floor(position.z), displacement);
|
||||
// if (checkBlock((int)Math.floor(position.x), (int)Math.floor(position.y + displacement.y), (int)Math.floor(position.z), displacement)) {
|
||||
// return true;
|
||||
// }
|
||||
// return displacement.y != -0.2f || displacement.w != 0;
|
||||
// }
|
||||
|
||||
// public void hit(Tool weapon, Vector3f direction) {
|
||||
// if (weapon == null) {
|
||||
// takeDamage(1);
|
||||
// vx += direction.x*0.2;
|
||||
// vy += direction.y*0.2;
|
||||
// vz += direction.z*0.2;
|
||||
// } else {
|
||||
// takeDamage(weapon.getDamage());
|
||||
// // TODO: Weapon specific knockback.
|
||||
// vx += direction.x*0.2;
|
||||
// vy += direction.y*0.2;
|
||||
// vz += direction.z*0.2;
|
||||
// }
|
||||
// }
|
||||
|
||||
// public void update(float deltaTime) {
|
||||
// double step = collisionDetection(deltaTime);
|
||||
// if (entityAI != null)
|
||||
// entityAI.update(this);
|
||||
// updateVelocity(deltaTime);
|
||||
|
||||
// // clamp health between 0 and maxHealth
|
||||
// if (health < 0)
|
||||
// health = 0;
|
||||
// if (health > maxHealth)
|
||||
// health = maxHealth;
|
||||
|
||||
// if (maxHunger > 0) {
|
||||
// hungerMechanics((float)step, deltaTime);
|
||||
// }
|
||||
// }
|
||||
|
||||
// double oldVY = 0;
|
||||
// /**
|
||||
// * Simulates the hunger system. TODO: Make dependent on mass
|
||||
// * @param step How high the entity stepped in this update cycle.
|
||||
// */
|
||||
// protected void hungerMechanics(float step, float deltaTime) {
|
||||
// // Passive energy consumption:
|
||||
// hunger -= 0.00013333*deltaTime; // Will deplete hunger after 22 minutes of standing still.
|
||||
// // Energy consumption due to movement:
|
||||
// hunger -= (vx*vx + vz*vz)/900/16*deltaTime;
|
||||
|
||||
// // Jumping:
|
||||
// if (oldVY < vy) { // Only care about positive changes.
|
||||
// // Determine the difference in "signed" kinetic energy.
|
||||
// double deltaE = vy*vy*Math.signum(vy) - oldVY*oldVY*Math.signum(oldVY);
|
||||
// hunger -= (float)deltaE/900;
|
||||
// }
|
||||
// oldVY = vy;
|
||||
|
||||
// // Stepping: Consider potential energy of the step taken V = m·g·h
|
||||
// hunger -= World.GRAVITY*step/900;
|
||||
// hunger = Math.max(0, hunger);
|
||||
|
||||
// // Examples:
|
||||
// // At 3 blocks/second(player base speed) the cost of movement is about twice as high as the passive consumption.
|
||||
// // So when walking on a flat ground in one direction without sprinting the hunger bar will be empty after 22/3≈7 minutes.
|
||||
// // When sprinting however the speed is twice as high, so the energy consumption is 4 times higher, meaning the hunger will be empty after only 2 minutes.
|
||||
// // Jumping takes 0.05 hunger on jump and on land.
|
||||
|
||||
// // Heal if hunger is more than half full:
|
||||
// if (hunger > maxHunger/2 && health < maxHealth) {
|
||||
// // Maximum healing effect is 1% maxHealth per second:
|
||||
// float healing = Math.min(maxHealth*deltaTime*0.01f, maxHealth-health);
|
||||
// health += healing;
|
||||
// hunger -= healing;
|
||||
// }
|
||||
// }
|
||||
|
||||
// protected void updateVelocity(float deltaTime) {
|
||||
// // TODO: Use the entities mass, force and ground structure to calculate a realistic velocity change.
|
||||
// vx += (targetVX-vx)/5*deltaTime;
|
||||
// vz += (targetVZ-vz)/5*deltaTime;
|
||||
// vy -= World.GRAVITY*deltaTime;
|
||||
// }
|
||||
|
||||
// // NDT related
|
||||
|
||||
// public EntityType getType() {
|
||||
// return type;
|
||||
// }
|
||||
|
||||
// public World getWorld() {
|
||||
// return world;
|
||||
// }
|
||||
|
||||
// public Vector3d getPosition() {
|
||||
// return position;
|
||||
// }
|
||||
|
||||
// public void setPosition(Vector3i position) {
|
||||
// this.position.x = position.x;
|
||||
// this.position.y = position.y;
|
||||
// this.position.z = position.z;
|
||||
// }
|
||||
|
||||
// public void setPosition(Vector3d position) {
|
||||
// this.position = position;
|
||||
// }
|
||||
|
||||
// public Vector3f getRotation() {
|
||||
// return rotation;
|
||||
// }
|
||||
|
||||
// public void setRotation(Vector3f rotation) {
|
||||
// this.rotation = rotation;
|
||||
// }
|
||||
|
||||
// public Inventory getInventory() {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// public static boolean aabCollision(double x1, double y1, double z1, double w1, double h1, double d1, double x2, double y2, double z2, double w2, double h2, double d2) {
|
||||
// return x1 + w1 >= x2
|
||||
// && x1 <= x2 + w2
|
||||
// && y1 + h1 >= y2
|
||||
// && y1 <= y2 + h2
|
||||
// && z1 + d1 >= z2
|
||||
// && z1 <= z2 + d2;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @param vel
|
||||
// * @param x0
|
||||
// * @param y0
|
||||
// * @param z0
|
||||
// * @param w width in x direction
|
||||
// * @param h height in y direction
|
||||
// * @param d depth in z direction
|
||||
// * @param block
|
||||
// * @return
|
||||
// */
|
||||
// public void aabCollision(Vector4d vel, double x0, double y0, double z0, double w, double h, double d, int block) {
|
||||
// // check if the displacement is inside the box:
|
||||
// if (aabCollision(position.x - width + vel.x, position.y + vel.y, position.z - width + vel.z, width*2, height, width*2, x0, y0, z0, w, h, d)) {
|
||||
// // Check if the entity can step on it:
|
||||
// if (y0 + h - position.y > 0 && y0 + h - position.y <= stepHeight) {
|
||||
// vel.w = Math.max(vel.w, y0 + h - position.y);
|
||||
// return;
|
||||
// }
|
||||
// // Only collide if the previous position was outside:
|
||||
// if (!aabCollision(position.x - width, position.y, position.z - width, width*2, height, width*2, x0, y0, z0, w, h, d)) {
|
||||
// // Check in which direction the current displacement goes and changes accordingly:
|
||||
// if (vel.x < 0) {
|
||||
// vel.x = x0 + w - (position.x - width) + 0.01f;
|
||||
// } else if (vel.x > 0) {
|
||||
// vel.x = x0 - (position.x + width) - 0.01f;
|
||||
// }
|
||||
// else if (vel.y < 0) {
|
||||
// vel.y = y0 + h - (position.y) + 0.01f;
|
||||
// }
|
||||
// else if (vel.y > 0) {
|
||||
// vel.y = y0 - (position.y + height) - 0.01f;
|
||||
// }
|
||||
// else if (vel.z < 0) {
|
||||
// vel.z = z0 + d - (position.z - width) + 0.01f;
|
||||
// } else if (vel.z > 0) {
|
||||
// vel.z = z0 - (position.z + width) - 0.01f;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// }
|
@ -10,11 +10,12 @@ const Vec3d = vec.Vec3d;
|
||||
|
||||
pub const ServerWorld = @import("world.zig").ServerWorld;
|
||||
pub const terrain = @import("terrain/terrain.zig");
|
||||
pub const Entity = @import("Entity.zig");
|
||||
|
||||
|
||||
pub const User = struct {
|
||||
conn: *Connection,
|
||||
//TODO: public Player player;
|
||||
conn: *Connection,
|
||||
player: Entity = .{},
|
||||
timeDifference: utils.TimeDifference = .{},
|
||||
interpolation: utils.GenericInterpolation(3) = undefined,
|
||||
lastTime: i16 = undefined,
|
||||
@ -22,8 +23,6 @@ pub const User = struct {
|
||||
renderDistance: u16 = undefined,
|
||||
lodFactor: f32 = undefined,
|
||||
receivedFirstEntityData: bool = false,
|
||||
pos: [3]f64 = undefined, // TODO: Use position from te entity.
|
||||
vel: [3]f64 = undefined,
|
||||
// TODO: ipPort: []const u8,
|
||||
// TODO: public Thread waitingThread;
|
||||
|
||||
@ -33,8 +32,7 @@ pub const User = struct {
|
||||
.conn = try Connection.init(manager, ipPort),
|
||||
};
|
||||
self.conn.user = self;
|
||||
self.interpolation.init(&self.pos, &self.vel);
|
||||
// TODO: self.interpolation.init(&player.pos, &player.vel);
|
||||
self.interpolation.init(@ptrCast(*[3]f64, &self.player.pos), @ptrCast(*[3]f64, &self.player.vel));
|
||||
network.Protocols.handShake.serverSide(self.conn);
|
||||
// TODO:
|
||||
// synchronized(this) {
|
||||
@ -58,28 +56,13 @@ pub const User = struct {
|
||||
|
||||
pub fn initPlayer(self: *User, name: []const u8) !void {
|
||||
self.name = try main.globalAllocator.dupe(u8, name);
|
||||
// TODO:
|
||||
// assert(player == null);
|
||||
// player = Server.world.findPlayer(this);
|
||||
// interpolation.outPosition[0] = player.getPosition().x;
|
||||
// interpolation.outPosition[1] = player.getPosition().y;
|
||||
// interpolation.outPosition[2] = player.getPosition().z;
|
||||
// interpolation.outVelocity[0] = player.vx;
|
||||
// interpolation.outVelocity[1] = player.vy;
|
||||
// interpolation.outVelocity[2] = player.vz;
|
||||
try world.?.findPlayer(self);
|
||||
}
|
||||
|
||||
pub fn update(self: *User) void {
|
||||
var time = @truncate(i16, std.time.milliTimestamp()) -% main.settings.entityLookback;
|
||||
time -= self.timeDifference.difference.load(.Monotonic);
|
||||
self.interpolation.update(time, self.lastTime);
|
||||
// TODO:
|
||||
// player.getPosition().x = interpolation.outPosition[0];
|
||||
// player.getPosition().y = interpolation.outPosition[1];
|
||||
// player.getPosition().z = interpolation.outPosition[2];
|
||||
// player.vx = interpolation.outVelocity[0];
|
||||
// player.vy = interpolation.outVelocity[1];
|
||||
// player.vz = interpolation.outVelocity[2];
|
||||
self.lastTime = time;
|
||||
}
|
||||
|
||||
@ -99,8 +82,7 @@ pub const User = struct {
|
||||
@bitCast(f32, std.mem.readIntBig(u32, data[52..56])),
|
||||
@bitCast(f32, std.mem.readIntBig(u32, data[56..60])),
|
||||
};
|
||||
_ = rotation;
|
||||
// TODO: player.getRotation().set(rotation);
|
||||
self.player.rot = rotation;
|
||||
const time = std.mem.readIntBig(i16, data[60..62]);
|
||||
self.timeDifference.addDataPoint(time);
|
||||
self.interpolation.updatePosition(&position, &velocity, time);
|
||||
@ -156,7 +138,7 @@ fn deinit() void {
|
||||
}
|
||||
|
||||
fn update() !void {
|
||||
world.?.update();
|
||||
try world.?.update();
|
||||
mutex.lock();
|
||||
for(users.items) |user| {
|
||||
user.update();
|
||||
|
@ -20,6 +20,7 @@ const terrain = server.terrain;
|
||||
|
||||
const server = @import("server.zig");
|
||||
const User = server.User;
|
||||
const Entity = server.Entity;
|
||||
|
||||
const ChunkManager = struct {
|
||||
world: *ServerWorld,
|
||||
@ -52,9 +53,11 @@ const ChunkManager = struct {
|
||||
}
|
||||
|
||||
pub fn getPriority(self: *ChunkLoadTask) f32 {
|
||||
_ = self;
|
||||
return 0;
|
||||
// TODO: return self.pos.getPriority(self.source.player.getPosBlocking()); // TODO: This is called in loop, find a way to do this without calling the mutex every time.
|
||||
if(self.source) |user| {
|
||||
return self.pos.getPriority(user.player.pos);
|
||||
} else {
|
||||
return std.math.floatMax(f32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isStillNeeded(self: *ChunkLoadTask) bool {
|
||||
@ -74,19 +77,20 @@ const ChunkManager = struct {
|
||||
// }
|
||||
}
|
||||
if(std.time.milliTimestamp() - self.creationTime > 10000) { // Only remove stuff after 10 seconds to account for trouble when for example teleporting.
|
||||
// TODO:
|
||||
// for(User user : Server.users) {
|
||||
// double minDistSquare = ch.getMinDistanceSquared(user.player.getPosition().x, user.player.getPosition().y, user.player.getPosition().z);
|
||||
// // ↓ Margin for error. (diagonal of 1 chunk)
|
||||
// double targetRenderDistance = (user.renderDistance*Chunk.chunkSize + Chunk.chunkSize*Math.sqrt(3));//*Math.pow(user.LODFactor, Math.log(ch.voxelSize)/Math.log(2));
|
||||
// if(ch.voxelSize != 1) {
|
||||
// targetRenderDistance *= ch.voxelSize*user.LODFactor;
|
||||
// }
|
||||
// if(minDistSquare <= targetRenderDistance*targetRenderDistance) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
server.mutex.lock();
|
||||
defer server.mutex.unlock();
|
||||
for(server.users.items) |user| {
|
||||
const minDistSquare = self.pos.getMinDistanceSquared(user.player.pos);
|
||||
// ↓ Margin for error. (diagonal of 1 chunk)
|
||||
var targetRenderDistance = (@intToFloat(f32, user.renderDistance*chunk.chunkSize) + @intToFloat(f32, chunk.chunkSize)*@sqrt(3.0));
|
||||
if(self.pos.voxelSize != 1) {
|
||||
targetRenderDistance *= @intToFloat(f32, self.pos.voxelSize)*user.lodFactor;
|
||||
}
|
||||
if(minDistSquare <= targetRenderDistance*targetRenderDistance) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -361,26 +365,27 @@ pub const ServerWorld = struct {
|
||||
std.log.info("Trying ({}, {})", .{self.spawn[0], self.spawn[2]});
|
||||
if(try self.isValidSpawnLocation(self.spawn[0], self.spawn[2])) break;
|
||||
}
|
||||
// TODO: spawn[1] = chunkManager.getOrGenerateMapFragment(spawn.x, spawn.z, 1).getHeight(spawn.x, spawn.z);
|
||||
self.spawn[1] = 0;// TODO: spawn[1] = chunkManager.getOrGenerateMapFragment(spawn.x, spawn.z, 1).getHeight(spawn.x, spawn.z);
|
||||
}
|
||||
self.generated = true;
|
||||
try self.wio.saveWorldData();
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// public Player findPlayer(User user) {
|
||||
// JsonObject playerData = JsonParser.parseObjectFromFile("saves/" + name + "/players/" + Utils.escapeFolderName(user.name) + ".json");
|
||||
// Player player = new Player(this, user.name);
|
||||
// if(playerData.map.isEmpty()) {
|
||||
// // Generate a new player:
|
||||
// player.setPosition(spawn);
|
||||
// } else {
|
||||
// player.loadFrom(playerData);
|
||||
// }
|
||||
// addEntity(player);
|
||||
// return player;
|
||||
// }
|
||||
//
|
||||
|
||||
pub fn findPlayer(self: *ServerWorld, user: *User) !void {
|
||||
var buf: [1024]u8 = undefined;
|
||||
const playerData = files.readToJson(main.threadAllocator, try std.fmt.bufPrint(&buf, "saves/{s}/player/{s}.json", .{self.name, user.name})) catch .JsonNull; // TODO: Utils.escapeFolderName(user.name)
|
||||
defer playerData.free(main.threadAllocator);
|
||||
const player = &user.player;
|
||||
if(playerData == .JsonNull) {
|
||||
// Generate a new player:
|
||||
player.pos = vec.intToFloat(f64, self.spawn);
|
||||
} else {
|
||||
player.loadFrom(playerData);
|
||||
}
|
||||
// TODO: addEntity(player);
|
||||
}
|
||||
|
||||
// private void savePlayers() {
|
||||
// for(User user : Server.users) {
|
||||
// try {
|
||||
@ -466,12 +471,12 @@ pub const ServerWorld = struct {
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn update(self: *ServerWorld) void {
|
||||
pub fn update(self: *ServerWorld) !void {
|
||||
const newTime = std.time.milliTimestamp();
|
||||
var deltaTime = @intToFloat(f32, newTime - self.lastUpdateTime)/1000.0;
|
||||
self.lastUpdateTime = newTime;
|
||||
if(deltaTime > 0.3) {
|
||||
std.log.warn("Update time is getting too high. It's alread at {} s!", .{deltaTime});
|
||||
std.log.warn("Update time is getting too high. It's already at {} s!", .{deltaTime});
|
||||
deltaTime = 0.3;
|
||||
}
|
||||
|
||||
@ -481,10 +486,9 @@ pub const ServerWorld = struct {
|
||||
}
|
||||
if(self.lastUnimportantDataSent + 2000 < newTime) {// Send unimportant data every ~2s.
|
||||
self.lastUnimportantDataSent = newTime;
|
||||
// TODO:
|
||||
// for(User user : Server.users) {
|
||||
// Protocols.GENERIC_UPDATE.sendTimeAndBiome(user, this);
|
||||
// }
|
||||
for(server.users.items) |user| {
|
||||
try main.network.Protocols.genericUpdate.sendTimeAndBiome(user.conn, self);
|
||||
}
|
||||
}
|
||||
// TODO:
|
||||
// // Entities
|
||||
|
Loading…
x
Reference in New Issue
Block a user