Fix round-down division bug causing issues with block position

This fixes rendering issues with weird transparent blocks.
Also deletes underscore pointer manager, replacing it with
std::unique_ptr.
master
Dorian Wouters 2015-08-24 18:42:54 +02:00
parent ad6aed5179
commit 47ecebae40
16 changed files with 126 additions and 190 deletions

View File

@ -3,7 +3,7 @@
2. Backward compatibility is for the weak
(i.e. If mod shit breaks, that's none of the engine developers' problems.)
- There's a sight chance it breaks
- I can break
- It can break
- Expect it to break
- It will likely break
- It WILL break

View File

@ -29,8 +29,8 @@ void main(void) {
#endif
vec3 coord = coord.xyz;
#ifdef WAVE
if (wave != 0) {
float yShift = sin(time+(coord.x+coord.z)/16.0*6*PI)*wave - wave;
if (wave != 0.0) {
float yShift = sin(time+(coord.x+coord.z)/16.0*6.0*PI)*wave - wave;
coord.y += yShift;
//v_texcoord.y -= yShift/8.0;
}

View File

@ -1,10 +1,10 @@
Diggler save/network format spec
Hexedryne save/network format spec
[TOC]
## Binary format details
# Binary format details
### Numbers
## Numbers
Number types are denoted by the following table:
Symbol | C(++) type
------------|--------------
@ -20,7 +20,7 @@ Symbol | C(++) type
`d` | `double` (64-bit)
All specified formats are little-endian, and floats/doubles are IEEE 754.
### Varints
## Varints
(`u`)`varint`s are variable-length integers, stored in a big-endian fashion, each byte's most significant bit indicating continuation, and the actual binary data in the lower 7 bits.
`uvarint`s are, are their name implies, unsigned. Their signed counterpart (`varint`s) are encoded using a zigzag encoding, that is, `n` is encoded as `(n << 1) ^ (n >> B-1)` where `B` is the original integer's bit length.
Their max bit length are specified by a suffix, e.g. `varint64` -- note therefore (`u`)`varint8` would be pointless.
@ -33,11 +33,11 @@ Their names are shortened to, respectively
They come from [Google's Protobuf](https://developers.google.com/protocol-buffers/docs/encoding) library.
### Vectors
## Vectors
Vectors can be of dimensions 2 to 4. They are simply stored member-by-member, in `<x><y>[z][w]` order, with the type determined by the prefix.
E.g. `fvec3` is a 3-dimensional vector stored as 3 consecutive 32-bit IEEE754 floating-point numbers.
### Strings
## Strings
Strings are arrays of arbitrary binary data -- usually text, in which case the UTF-8 enoding is used.
* `string` = `uv32 length; byte data[length];`
@ -45,36 +45,30 @@ Strings are arrays of arbitrary binary data -- usually text, in which case the U
* `mstring` (medium string) = `u16 length; byte data[length];`
* `lstring` (long string) = `u32 length; byte data[length];`
### Arrays
## Arrays
Arrays are sequences of tightly-packed data of an unique type.
#### Static arrays
Their length is either hard-coded or determined from another variable, and their type is fixed and must be known in advance.
They are denoted by *`type`*`[SIZE]`, e.g. `int[42]`.
Their length as well as their type can be either hard-coded or determined from another variable.
They are denoted by:
* *`type`*`[SIZE]`, e.g. `int[42]`
* *`type name`*`[SIZE]` when named
#### Variable arrays
```
u8 type;
v32 length;
@type data[length];
```
Where `type` is the `TypeID` (see below) of the data elements.
Denoted by *`type`*`[]`, e.g. `byte[]`. Can be nested, too, i.e. it is possible to have *`type`*`[][]`.
### Datrees
## Datrees
Datrees (*Data Trees*) are key/value maps able to hold a variety of data types bound to a `string` key.
```
v64 nElements;
nElements times {
uv32 entryCount;
struct DatreeEntry {
string key;
TypeID type;
@type data;
}
} entries[entryCount];
```
Type is represented by `datree`, and a hint about a sole data type is given by writing `datree<type>` (this does not, however, replace each entry's `type` field, and any badly-formatted data encountered should be discarded/ignored).
### TypeIDs
## TypeIDs
A `TypeID` is a `uv16` defining a type, of all presented above. It is made of two parts (bitwise diagram):
```
15 14 7 6 0
@ -113,8 +107,8 @@ XType | Modifier
3 | `vec3`
4 | `vec4`
### Other ID/status tables
#### Compression
## Other ID/status tables
### Compression
ID | Compression algorithm
---|----------------------
0 | None
@ -125,7 +119,7 @@ ID | Compression algorithm
*: Unimplemented
°: Have a dictionary that can be relocated/shared
#### Chunk status
### Chunk status
ID | Status
---|-------
0 | Unemerged
@ -135,6 +129,8 @@ ID | Status
4 | Emerged, modified by non-player action (mobs, map update...)
5 | Emerged, modified by player action
# Save files
## Overall structure
Universes are stored in folders containing the worlds it is made of as well as other (meta)data files.
@ -142,13 +138,13 @@ Universes are stored in folders containing the worlds it is made of as well as o
### Header
Type | Name | Value
---------:|:------|-----------------
`byte[8]` | `HDs` | `\x01\xD1GLRusv`
`byte[8]` | `HDs` | `\x01HX\xEDNusv`
`u32` | `Hui` | Universe ID
`u8` | `Hst` | Save file type
`u64` | `HTs` | [UNIX Timestamp](https://en.wikipedia.org/wiki/Unix_time) of last edit
`uv32` | `Hfv` | Save format version
`u32` | `Hfv` | Save format version
`v` | `Hfl` | Flags
`u8` | `HDc` | XOR checksum of previous bytes
`u8` | `HDc` | XOR checksum of previous bytes, `0xAA` as starting byte
`u8` | `HDe` | `\x02`
### Footer
@ -156,7 +152,7 @@ Type | Name | Value
Type | Name | Value
---------:|:------|-----------------
`uint64` | `Fcs` | 64-bit FastHash checksum of all previous bytes
`byte[8]` | `FTs` | `eu\xD1GLR\x04\x1C`
`byte[8]` | `FTs` | `euHX\xEDN\x04\x1C`
## Save file types
### Universe Root (`Hst = 0x00`)
@ -177,7 +173,7 @@ uint16 areasIDs[];
```
### World Area (`Hst = 0x02`)
An Area equates to 8×8×8 = 512 Chunks, themselves storing 16×16×16 blocks each, resulting in a maximum of 2 097 152 blocks stored, 8 MB of raw data if no extra buffers are added.
An Area equates to 8×8×8 = 512 Chunks, themselves storing 16×16×16 blocks each, resulting in a maximum of 2 097 152 blocks stored, 8 MB of (uncompressed) raw data if no extra buffers are added.
#### Chunk
```c++
@ -190,20 +186,22 @@ struct Chunk {
compressed using @compID {
uint16 ids[16*16*16]; // Block IDs
uint16 data[16*16*16]; // Block data
datree<?[16*16*16]> extraBuffers;
datree metadata[];
datree<?[16*16*16]> buffers; // See Bufferspecs section
uint16 metadataCount;
datree metadata[metadataCount];
}
}
// Entity data
uv32 entityCount;
struct Entity {
uint64 id;
fvec3 position; // Relative to the current Chunk's origin
fvec3 velocity;
datree properties;
} entities[];
} entities[entityCount];
};
```
Block IDs are indexed in the flat array by `index = x + y*16 + z*16*16`.
Block IDs and data are indexed in the flat array by `index = x + y*16 + z*16*16`.
Block data (let's call it `bdata`) matching the bitmask `0x8000`indicate a metadata pointer -- that is, said block has a metadata Datree stored in `metadata` at index `bdata & 0x7FFFF`. This Datree can contain arbitrarily-defined data (as mods please) about the block. It has a special entry called `__data` containing the block's actual `bdata` if it wasn't a metadata pointer and isn't zero, and is the value returned by functions getting the block's data.
@ -234,3 +232,17 @@ Registered by mods upon their load. Like block names, they are prefixed with the
* TBD (2nd light computation)
* `equilibrium`
* Params TBD (conductivity, ...)
# Network
## Messages
All network communication in Diggler is done via sequential messages, delivered by the [ENet library](http://enet.bespin.org) on multiple ENet channels.
### Message channels
Channel | Usage
--------|------
0 | Base
1 | Chat
2 | Life (player/entity spawn/death)
3 | Movement (player/entity movement)
4 | Metadata (Universe/World/entity metadata transfer)
5 | ChunkTransfer
6 | ChunkUpdate

View File

@ -1,4 +1,4 @@
local D = require('Diggler')
local H = require('hexedryne')
local TestMod = {
id = "TestMod",
@ -6,18 +6,24 @@ local TestMod = {
version = 1,
versionStr = "1.0.0",
description = "A mod to test Lua scripting ability",
tags = {"test"},
authors = {"gravgun"},
license = "GPLv3",
deps = {},
optdeps = {},
clientside = true,
serverside = true
serverside = true,
providesInterfaces = {
"diggler.isBlockUseless",
}
}
function TestMod.init()
print("Hey i'm " .. CurrentMod.id)
D.registerBlock('test', {
H.registerBlock('test', {
dispname = 'block.test.name',
sandboxTab = 'blocks',
harvest = { pickaxe = 0, shovel = 10000 },
@ -30,6 +36,6 @@ function TestMod.deinit()
print("Bye")
end
print(D.mods)
print(H.mods)
return TestMod

View File

@ -1,16 +1,16 @@
require('io')
local Diggler = {
local hexedryne = {
mods = {},
exportedFuncs = {}
}
function Diggler.export(name, func)
Diggler.exportedFuncs[name] = func
function hexedryne.export(name, func)
hexedryne.exportedFuncs[name] = func
end
package.loaded['Diggler'] = Diggler
package.loaded['hexedryne'] = hexedryne
local function setoverlay(tab, orig)
local mt = getmetatable(tab) or {}
@ -24,7 +24,7 @@ local function setoverlay(tab, orig)
setmetatable(tab, mt)
end
Diggler.MODSTATUS = {
hexedryne.MODSTATUS = {
UNAVAILABLE = 0,
DISABLED = 1,
ERRORED = 2,
@ -34,9 +34,9 @@ Diggler.MODSTATUS = {
UNLOADED = 100
}
function Diggler.loadModLua(path)
function hexedryne.loadModLua(path)
local digglerOverlay = {}
local packageOverlay = { ['path'] = path .. '/?.lua;' .. package.path, ['loaded'] = packageLoadedOverlay }
local packageOverlay = { ['path'] = path .. '/?.lua;' .. package.path }
setoverlay(packageOverlay, package)
local env = {
['package'] = packageOverlay,
@ -44,7 +44,7 @@ function Diggler.loadModLua(path)
print("<init>", ...)
end,
['require'] = function (module)
if module == 'Diggler' then
if module == 'hexedryne' then
return digglerOverlay
end
return require(module)
@ -70,7 +70,7 @@ function Diggler.loadModLua(path)
env.print = function (...)
print(env.CurrentMod.id..":", ...)
end
for name, func in pairs(Diggler.exportedFuncs) do
for name, func in pairs(hexedryne.exportedFuncs) do
digglerOverlay[name] = function (...)
func(env.CurrentMod, ...)
end
@ -82,14 +82,14 @@ function Diggler.loadModLua(path)
return r1, r2
end
function Diggler.loadMod(path)
local mod, err = Diggler.loadModLua(path)
function hexedryne.loadMod(path)
local mod, err = hexedryne.loadModLua(path)
if mod then
if Diggler.mods[mod.id] then
if hexedryne.mods[mod.id] then
error("Mod already loaded")
end
mod.status = Diggler.MODSTATUS.LOADED
Diggler.mods[mod.id] = mod
mod.status = hexedryne.MODSTATUS.LOADED
hexedryne.mods[mod.id] = mod
print("Loaded mod '" .. mod.name .. "' <" .. mod.id .. "> v" .. mod.versionStr .. " (" .. mod.version .. ")")
return mod
else
@ -98,21 +98,20 @@ function Diggler.loadMod(path)
return nil
end
function Diggler.initMod(id)
local mod = Diggler.mods[id]
function hexedryne.initMod(mod)
mod.init()
mod.status = Diggler.MODSTATUS.INITIALIZED
mod.status = hexedryne.MODSTATUS.INITIALIZED
end
function Diggler.getMod(mod, id)
return Diggler.mods[id]
function hexedryne.getMod(mod, id)
return hexedryne.mods[id]
end
Diggler.export("getMod", Diggler.getMod)
hexedryne.export("getMod", hexedryne.getMod)
function Diggler.registerBlock(mod, name, block)
function hexedryne.registerBlock(mod, name, block)
print("Calling registerBlock from mod " .. (mod and mod.id or "<none>"))
end
Diggler.export("registerBlock", Diggler.registerBlock)
hexedryne.export("registerBlock", hexedryne.registerBlock)
Diggler.loadMod('TestMod')
Diggler.initMod('TestMod')
local m = hexedryne.loadMod('TestMod')
hexedryne.initMod(m)

View File

@ -227,16 +227,12 @@ void CaveGenerator::Generate(WorldRef wr, const GenConf &gc, ChunkRef cr) {
c.setBlock(x, y, 0, Content::BlockUnknownId);
c.setBlock(x, y, CZ-1, Content::BlockUnknownId);
}*/
/*glm::ivec3 cp = c.getWorldChunkPos() * glm::ivec3(CX, CY, CZ);
glm::ivec3 cp = c.getWorldChunkPos() * glm::ivec3(CX, CY, CZ);
for (int y = 0; y < CY; ++y)
for (int x = 0; x < CX; ++x)
for (int z = 0; z < CZ; ++z)
c.setBlock(x, y, z, stb_perlin_noise3((cp.x + x)/8.f, (cp.y + y)/8.f, (cp.z + z)/8.f) > 0 ? Content::BlockUnknownId : Content::BlockAirId);
*/
for (int y = 0; y < CY; ++y)
for (int x = 0; x < CX; ++x)
for (int z = 0; z < CZ; ++z)
c.setBlock(x, y, z, !(x==0||x==15||y==0||y==15||z==0||z==15) ? Content::BlockUnknownId : Content::BlockAirId);
#if 0
if (gc.ore.enabled)

View File

@ -16,7 +16,7 @@
#define CXY (CX*CY)
#define I(x,y,z) (x+y*CX+z*CXY)
#define SHOW_CHUNK_UPDATES 0
#define SHOW_CHUNK_UPDATES 1
namespace Diggler {
@ -73,8 +73,9 @@ void Chunk::ChangeHelper::discard(){
}
Chunk::Chunk(Game *G, WorldRef W, int X, int Y, int Z) : scx(X), scy(Y), scz(Z),
data(nullptr), data2(nullptr), G(G), W(W), vbo(nullptr), CH(*this),
state(State::Unavailable) {
G(G), W(W), vbo(nullptr), data(nullptr), data2(nullptr),
state(State::Unavailable),
CH(*this) {
dirty = true;
data = new Data;
data->clear();
@ -319,9 +320,9 @@ void Chunk::updateClient() {
BlockId bt, bu /*BlockUp*/, bn /*BlockNear*/;
bool mayDisp;
const AtlasCreator::Coord *tc;
for(uint8 x = 0; x < CX; x++) {
for(uint8 y = 0; y < CY; y++) {
for(uint8 z = 0; z < CZ; z++) {
for(int8 x = 0; x < CX; x++) {
for(int8 y = 0; y < CY; y++) {
for(int8 z = 0; z < CZ; z++) {
bt = data->id[I(x,y,z)];
// Empty block?
@ -482,7 +483,7 @@ void Chunk::updateClient() {
void Chunk::render(const glm::mat4& transform) {
#if SHOW_CHUNK_UPDATES
glUniform4f(R.uni_unicolor, 1.f, changed ? 0.f : 1.f, changed ? 0.f : 1.f, 1.f);
glUniform4f(R.uni_unicolor, 1.f, dirty ? 0.f : 1.f, dirty ? 0.f : 1.f, 1.f);
#endif
if (dirty)
updateClient();

View File

@ -236,6 +236,11 @@ void GameState::onKey(int key, int scancode, int action, int mods) {
G->U->getWorld(0)->onRenderPropertiesChanged();
}
break;
case GLFW_KEY_F8:
if (action == GLFW_PRESS) {
G->U->getWorld(0)->refresh();
}
break;
default:
break;
}
@ -771,7 +776,10 @@ void GameState::updateUI() {
"vy: " << LP.velocity.y << std::endl <<
"rx: " << LP.angle << std::endl <<
// TODO reintroduce "chunk tris: " << lastVertCount / 3 << std::endl <<
"chunk mem: " << chunkMem / 1024 << " kib / " << (chunkMem*100/maxChunkMem) << '%';
"chunk mem: " << chunkMem / 1024 << " kib / " << (chunkMem*100/maxChunkMem) << '%' << std::endl <<
"Pointing at: " << LP.W->getBlockId(m_pointedBlock.x, m_pointedBlock.y, m_pointedBlock.z) << " @ " <<
m_pointedBlock.x << ' ' << m_pointedBlock.y << ' ' << m_pointedBlock.z <<
" C: " << divrd(m_pointedBlock.x, CX) << ' ' << divrd(m_pointedBlock.y, CZ) << ' ' << divrd(m_pointedBlock.z, CZ);
UI.DebugInfo->setText(oss.str());
}
}

View File

@ -86,8 +86,8 @@ void LocalPlayer::update(float delta) {
// Apply gravity
if (hasGravity) {
if (!onGround && velocity.y <= HurtYVelocity) {
BlockId b = W->get(position.x, position.y-1, position.z);
onGround = !Blocks::canGoThrough(b, team) && (b != BlockType::Jump);
BlockId b = W->getBlockId(position.x, position.y-1, position.z);
onGround = !b; //!Blocks::canGoThrough(b, team) && (b != BlockType::Jump);
if (onGround) {
if (velocity.y <= LethalYVelocity) {
setDead(true, DeathReason::Fall, true);
@ -105,13 +105,13 @@ void LocalPlayer::update(float delta) {
}
}
if (onGround) {
BlockType b = G->SC->get(position.x, position.y-1, position.z);
onGround = !Blocks::canGoThrough(b, team);
if (onRoad) {
BlockId b = W->getBlockId(position.x, position.y-1, position.z);
onGround = !b; //!Blocks::canGoThrough(b, team);
/*if (onRoad) {
onRoad = (!onGround || b == BlockType::Road || b == BlockType::Jump);
} else {
onRoad = (b == BlockType::Road);
}
}*/
}
if (!onGround)
velocity.y -= Gravity * delta;
@ -143,8 +143,8 @@ void LocalPlayer::update(float delta) {
#if 0
else {
float x = destPos.x, y = destPos.y, z = destPos.z;
BlockType bTop = G->SC->get(x, y+size.y, z),
bBottom = G->SC->get(x, y, z);
BlockId bTop = W->getBlockId(x, floor(y+size.y), z),
bBottom = W->getBlockId(x, y, z);
if (velocity.y > 0.f)
if (!Blocks::canGoThrough(bTop, team)) {
velocity.y = 0.f;

View File

@ -1,5 +1,4 @@
#include "MessageState.hpp"
#include "_.hpp"
#include "ui/Text.hpp"
#include "Game.hpp"
#include "GlobalProperties.hpp"

View File

@ -143,15 +143,17 @@ double rmod(double x, double y);
/// Divide rounding down / Modulo quotient
/// @returns x/y rounded down / Q in modulus' A=B*Q+R equation
///
/*[[gnu::always_inline]]*/ inline int divrd(int x, uint y) {
return x/(int)y - (x < 0 ? 1 : 0);
/*[[gnu::always_inline]] constexpr*/ inline int divrd(int x, uint y) {
if (x < 0)
return (x+1)/(int)y - 1;
return x/(int)y;
}
///
/// @return Floored value of f, as an integer
/// @see ::std::floor For results as float or double
///
/*[[gnu::always_inline]]*/ inline int floor(const float f) {
/*[[gnu::always_inline]] constexpr*/ inline int floor(const float f) {
if (f >= 0)
return (int)f;
return ((int)f)-1;

View File

@ -85,9 +85,9 @@ void Server::handlePlayerJoin(InMessage &msg, Peer &peer) {
H.send(p.P, broadcast, Tfer::Rel);
}
getOutputStream() << plr.name << " joined from " << peer.getHost() << endl;
for (int x = -8; x < 0; ++x)
for (int y = -1; y < 0; ++y)
for (int z = -8; z < 0; ++z)
for (int x = -2; x < 2; ++x)
for (int y = -2; y < 2; ++y)
for (int z = -2; z < 2; ++z)
schedSendChunk(G.U->getWorld(0)->getChunkEx(x, y, z), plr);
}

View File

@ -19,7 +19,7 @@ class OutMessage;
typedef int WorldId;
struct WorldChunkMapSorter {
/*constexpr*/ bool operator()(const glm::ivec3& lhs, const glm::ivec3& rhs) const {
/*constexpr*/ bool operator()(const glm::ivec3 &lhs, const glm::ivec3 &rhs) const {
if (lhs.x == rhs.x)
if (lhs.y == rhs.y)
if (lhs.z == rhs.z)

View File

@ -1,87 +0,0 @@
#ifndef UNDERSCORE_HPP
#define UNDERSCORE_HPP
#include <utility>
template<class T> struct _ {
T *ptr;
// Construct
_() : ptr(nullptr) {}
_(decltype(nullptr)) : ptr(nullptr) {}
_(T *t) : ptr(t) {}
template<typename... Args> _(Args&&... args) {
ptr = new T(std::forward<Args>(args)...);
}
// No copy
_(const _&) = delete;
_& operator=(const _&) = delete;
// Move
_(_ &&o) {
delete ptr;
ptr = o.ptr;
o.ptr = nullptr;
}
_& operator=(_ &&o) {
delete ptr;
ptr = o.ptr;
o.ptr = nullptr;
return *this;
}
// Assign
_& operator=(T *t) {
delete ptr;
ptr = t;
return *this;
}
// Comparison
bool operator==(T *t) const {
return t == ptr;
}
bool operator!=(T *t) const {
return t != ptr;
}
// Get
T* get() const {
return ptr;
}
T& operator[](int i) const {
return ptr[i];
}
T& operator*() const {
return *ptr;
}
T* operator->() const {
return ptr;
}
// Addressof, use at your own risk
T** operator&() const {
return &ptr;
}
// Cast
operator T*() const {
return ptr;
}
operator const T*() const {
return ptr;
}
template<typename R> operator R*() const {
return (R*)ptr;
}
operator bool() const {
return ptr;
}
// Destruct
~_() {
delete ptr;
}
};
#endif

View File

@ -36,7 +36,7 @@ void Manager::setup(Game *G) {
RR.uni_mvp = RR.prog->uni("mvp");
RR.uni_unicolor = RR.prog->uni("unicolor");
}
m_rectVbo = new VBO();
m_rectVbo.reset(new VBO);
uint8 verts[6*4] = {
0, 0, 0, 1,
1, 0, 1, 1,
@ -59,11 +59,11 @@ void Manager::add(Element *e) {
void Manager::remove(Element *e) {
m_elements.remove_if([&e](_<Element> &l) -> bool { return l == e; });
m_elements.remove_if([&e](std::unique_ptr<Element> &l) -> bool { return l.get() == e; });
}
void Manager::render() {
for (_<Element>& e : m_elements) {
for (std::unique_ptr<Element> &e : m_elements) {
if (e->m_isVisible)
e->render();
}

View File

@ -1,8 +1,8 @@
#ifndef UI_MANAGER_HPP
#define UI_MANAGER_HPP
#include <list>
#include <memory>
#include "Element.hpp"
#include "../_.hpp"
namespace Diggler {
@ -14,8 +14,8 @@ namespace UI {
class Manager {
private:
_<VBO> m_rectVbo;
std::list<_<Element>> m_elements;
std::unique_ptr<VBO> m_rectVbo;
std::list<std::unique_ptr<Element>> m_elements;
glm::mat4 m_projMatrix, m_projMat1, m_projMat1V;
friend GameWindow;