Add files via upload

master
EliasFleckenstein03 2020-02-14 17:44:21 +01:00 committed by GitHub
parent 0100b74f8e
commit 79a2a56c3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1282 additions and 0 deletions

25
CMakeLists.txt Normal file
View File

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.0)
project(dragonblocks)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
add_executable(dragonblocks
src/game.cpp
src/graphics.cpp
src/inventory.cpp
src/main.cpp
src/map.cpp
src/mapgen.cpp
src/mods.cpp
src/node.cpp
src/texture.cpp
src/threads.cpp
src/util.cpp
)
target_link_libraries(dragonblocks
GL
freeglut
lua5.3
pthread
png16
m
)

82
README.txt Normal file
View File

@ -0,0 +1,82 @@
DRAGONBLOCKS BEDROCK EDITION
Written in C++
An Open Source Project by Elias Fleckenstein
1. General
1.1. What this is about
Dragonblocks originaly was a Browsergame I made that should be some kind of 2D Minetest (Minetest (www.minetest.net) is a game similar to
Minecraft, except Minetest is free & open source and is meant to be modded). The JavaScript Edition is hosted at www.dragonblocks.tk and
further developed then this C++ Version, through the C++ Version has advantages like map saving and lot larger map. I decided to call the
C++ Version "Bedrock Edition" as a joke for the Minecraft C++ Version is Called Bedrock or Pocket Edition.
1.2. Version
This is the Dragonblocks Bedrock Edition 3.0.
1.4. Bugs
Please Report Bugs to eliasfleckenstein@web.de.
1.5. License
Copyright 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
2. Starting the Game
2.1. Platform Compability
This Game was developed on linux, therefore following instructions are only for linux users, basically because I have no idea how to
port the game to other platforms. Feel free to add building instructions for other systems over github.
2.3. Download
You can download the game using git:
$ git clone https://
2.2. Dependencies:
You need Freeglut, OpenGl, Cmake, Liblua and Libpng.
If you are on Debian/Ubuntu You can install them over apt:
$ sudo apt install liblua5.3-dev freeglut3-dev libgl1-mesa-dev cmake libpng-dev
2.3. Building
to Build dragonblocks run:
$ cd dragonblocks
$ cmake .
$ make
2.4. Exectute
2.4.1. Run-In-Place
Invoke dragonblocks by typing:
$ cd dragonblocks
$ bin/dragonblocks --worldname <your_worldname>
To see a list of worlds do:
$ bin/dragonblocks --worldlist
You can select a world from this list or create a new one.
For more info run:
$ bin/dragonblocks --help
2.4.2. Installation
You can install dragonblocks by doing:
$ sudo ./install.sh
It will copy the dragonblocks directory to /usr/share/dragonblocks and place a script in
/usr/bin/dragonblocks that starts dragonblocks.
3. Developing
3.1. The Lua Modding API
If you want to add a lua file to the game, place it in the game folder and add a dofile() in game/init.lua
Note: The lua api currently consists of only two functions. If you want to add something I'm open to ideas or code.
dragonblocks.register_node(obj)
Register a new node
obj has to contain:
name: string - the itemstring. It should follow the convention "modulename:nodename"
texture: string - the texture path. Textures should be placed in the textures folder and have to be 16 x 16 px.
obj can contain:
stable: boolean - Nodes like water or air are unstable. [default = true]
hidden: boolean - The Node will be hidden in the invenotry. [default = false]
translucent: boolean - Whether the node's texture should be transparent. [default = false]
dragonblocks.log(text)
Log something.
3.2. The C++ API
The C++ API is probably to big to explain here, but if you do C++ you should understand it. In case you have questions, feel free to
ask them on github. You can also contribute code if you want.

5
builtin/cpp.lua Normal file
View File

@ -0,0 +1,5 @@
local cpp_last_node = 0
function cpp_get_next_node()
cpp_last_node = cpp_last_node + 1
return core.nodes[cpp_last_node]
end

3
builtin/functions.lua Normal file
View File

@ -0,0 +1,3 @@
dragonblocks.log = function(text)
print("[LUA] "..text)
end

15
builtin/init.lua Normal file
View File

@ -0,0 +1,15 @@
core = {}
dragonblocks = {}
dragonblocks.settings = {}
dofile("builtin/register.lua")
dofile("builtin/functions.lua")
dofile("builtin/cpp.lua")
--local popenfile = io.popen("ls game")
--for filename in popenfile:lines() do
-- dofile("game/"..filename.."/init.lua")
--end
--popenfile:close()
dofile("game/init.lua")

20
builtin/register.lua Normal file
View File

@ -0,0 +1,20 @@
core.nodes = {}
dragonblocks.register_node = function(obj)
if obj and obj.name and obj.texture then
core.nodes[#core.nodes+1] = {}
core.nodes[#core.nodes].name = obj.name
core.nodes[#core.nodes].texture = obj.texture
core.nodes[#core.nodes].stable = false
if obj.stable == nil or obj.stable == true then
core.nodes[#core.nodes].stable = true
end
core.nodes[#core.nodes].hidden = false
if obj.hidden then
core.nodes[#core.nodes].hidden = true
end
core.nodes[#core.nodes].translucent = false
if obj.translucent then
core.nodes[#core.nodes].translucent = true
end
end
end

7
game/init.lua Normal file
View File

@ -0,0 +1,7 @@
dragonblocks.log(" ____ _ _ _ ")
dragonblocks.log("| _ \\ _ __ __ _ __ _ ___ _ __ | |__ | | ___ ___| | _____ ")
dragonblocks.log("| | | | '__/ _` |/ _` |/ _ \\| '_ \\| '_ \\| |/ _ \\ / __| |/ / __| ")
dragonblocks.log("| |_| | | | (_| | (_| | (_) | | | | |_) | | (_) | (__| <\\__ \\ ")
dragonblocks.log("|____/|_| \\__,_|\\__, |\\___/|_| |_|_.__/|_|\\___/ \\___|_|\\_\\___/ ")
dragonblocks.log(" |___/ ")
dofile("game/nodes.lua")

50
game/nodes.lua Normal file
View File

@ -0,0 +1,50 @@
dragonblocks.register_node({
name = "dragonblocks:air",
texture = "textures/air.png",
stable = false,
hidden = true,
translucent = true,
})
dragonblocks.register_node({
name = "dragonblocks:stone",
texture = "textures/stone.png"
})
dragonblocks.register_node({
name = "dragonblocks:dirt",
texture = "textures/dirt.png"
})
dragonblocks.register_node({
name = "dragonblocks:grass",
texture = "textures/grass.png"
})
dragonblocks.register_node({
name = "dragonblocks:wood",
texture = "textures/wood.png"
})
dragonblocks.register_node({
name = "dragonblocks:water",
texture = "textures/water.png",
stable = false,
translucent = true,
})
dragonblocks.register_node({
name = "dragonblocks:leaves",
texture = "textures/leaves.png",
translucent = true,
})
dragonblocks.register_node({
name = "dragonblocks:bedrock",
texture = "textures/bedrock.png"
})
dragonblocks.register_node({
name = "dragonblocks:mese",
texture = "textures/mese.png"
})
dragonblocks.register_node({
name = "dragonblocks:sand",
texture = "textures/sand.png"
})
dragonblocks.register_node({
name = "dragonblocks:cobble",
texture = "textures/cobble.png"
})

7
install.sh Normal file
View File

@ -0,0 +1,7 @@
#! /bin/bash
cp . /usr/share/dragonblocks -R
echo "
cd /usr/share/dragonblocks
bin/dragonblocks \$*
" > /usr/bin/dragonblocks
chmod +x /usr/bin/dragonblocks

84
src/game.cpp Normal file
View File

@ -0,0 +1,84 @@
#include <string>
#include <iostream>
#include <cstdio>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <unistd.h>
#include "mods.h"
#include "game.h"
using namespace std;
void Game::log(string text, int level){
string prefix;
int color;
switch(level){
case WARNING:
color = ORANGE;
prefix = "WARNING";
break;
case ERROR:
color = RED;
prefix = "ERROR";
break;
case INFO:
color = LIGHTBLUE;
prefix = "INFO";
break;
case LOG:
color = BLUE;
prefix = "LOG";
break;
case EASTEREGG:
color = VIOLET;
prefix = "EASTEREGG";
default: break;
}
cout << "\e[3" << color << "m" << "[" << prefix << "] \e[0m" << text << endl;
if(logfile_fd)
fprintf(logfile_fd, "[%s] %s\n", prefix.c_str(), text.c_str());
}
void Game::log(string text){
log(text, LOG);
}
void Game::help(){
cout << "Usage: " << argv[0] << "[OPTIONS]" << endl;
cout << "Options:" << endl;
cout << "\t" << "-h" << "\t" << "--help" << "\t\t\t" << "Display this help and exit." << endl;
cout << "\t" << "-v" << "\t" << "--version" << "\t\t" << "Display version info." << endl;
cout << "\t" << "-p" << "\t" << "--worldpath [PATH]" << "\t" << "Set world path." << endl;
cout << "\t" << "-w" << "\t" << "--worldname [PATH]" << "\t" << "Select world by name (Worlds are placed in ~/.dragonblocks/worlds/)." << endl;
cout << "\t" << "-r" << "\t" << "--worldlist" << "\t\t" << "Show a list of your worlds." << endl;
cout << "\t" << "-s" << "\t" << "--seed [NUMBER]" << "\t\t" << "Set seed." << endl;
cout << "\t" << "-l" << "\t" << "--logfile [PATH]" << "\t" << "Set logfile." << endl;
}
void Game::version(){
cout << "DRAGONBLOCKS BEDROCK EDITION" << endl;
cout << "Written in C++" << endl;
cout << "An Open Source Project by Elias Fleckenstein" << endl;
cout << "Dragonblocks " << VERSION << endl;
}
void Game::worldlist(){
log("Your worlds:");
DIR *folder;
struct dirent *entry;
int files = 0;
folder = opendir(((string)getenv("HOME")+"/.dragonblocks/worlds/").c_str());
if(!folder){
Game::log("Cant Open World Directory", ERROR);
exit(EXIT_FAILURE);
}
while(entry = readdir(folder))
{
files++;
if(files > 2)
cout << "\t" << entry->d_name;
}
if(files <= 2)
cout << "\tYou have no Worlds yet.";
cout << endl;
closedir(folder);
return;
}

43
src/game.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef _GAME_H_
#define _GAME_H_
#include <string>
#include <cstdio>
#include "map.h"
#include "inventory.h"
#define WARNING 1
#define ERROR 2
#define INFO -1
#define EASTEREGG 17
#define LOG 0
#define VERSION "3.0"
#define BLACK 0
#define RED 1
#define GREEN 2
#define ORANGE 3
#define BLUE 4
#define VIOLET 5
#define LIGHTBLUE 6
#define GREY 7
class Game{
public:
static int *argc;
static char **argv;
static int seed;
static std::string mapfile;
static std::string logfile;
static FILE *logfile_fd;
static Map *map;
static void log(std::string);
static void log(std::string, int);
static void help();
static void version();
static void worldlist();
static Inventory *inventory;
};
#endif

130
src/graphics.cpp Normal file
View File

@ -0,0 +1,130 @@
#include <GL/freeglut.h>
#include <cstring>
#include <string>
#include <iostream>
#include "graphics.h"
#include "util.h"
#include "game.h"
#include "mapgen.h"
position Graphics::pointed;
position Graphics::pos = {MAPWIDTH/2 - DISPLAYWIDTH/2, MAPHEIGHT/2 - DISPLAYHEIGHT/2};
using namespace std;
void Graphics::display(){
glClear(GL_COLOR_BUFFER_BIT);
//sky
drawRectangle(0, 0, DISPLAYWIDTH*BLOCKWIDTH, DISPLAYHEIGHT*BLOCKWIDTH, "#87CEEB");
//map
for(int x = 0; x < DISPLAYWIDTH; x++){
for(int y = 0; y < DISPLAYHEIGHT; y++){
Game::map -> getNode(x+pos.x, y+pos.y) -> texture -> draw(x*BLOCKWIDTH, y*BLOCKWIDTH, BLOCKWIDTH, BLOCKWIDTH);
}
}
//pointed block
if(pointed.x < DISPLAYWIDTH){
drawRectangle(pointed.x * BLOCKWIDTH, pointed.y * BLOCKWIDTH, BLOCKWIDTH, 1, COLOR_BLACK);
drawRectangle(pointed.x * BLOCKWIDTH + BLOCKWIDTH - 1, pointed.y * BLOCKWIDTH, 1, BLOCKWIDTH, COLOR_BLACK);
drawRectangle(pointed.x * BLOCKWIDTH, pointed.y * BLOCKWIDTH + BLOCKWIDTH - 1, BLOCKWIDTH, 1, COLOR_BLACK);
drawRectangle(pointed.x * BLOCKWIDTH, pointed.y * BLOCKWIDTH, 1, BLOCKWIDTH, COLOR_BLACK);
}
//inventory
drawRectangle(DISPLAYWIDTH*BLOCKWIDTH, 0, INVWIDTH, DISPLAYHEIGHT*BLOCKWIDTH, "#B4B4B4");
drawRectangle(DISPLAYWIDTH*BLOCKWIDTH, Game::inventory->selected * INVWIDTH, INVWIDTH, INVWIDTH, "#636363");
for(int i = 0; i < Game::inventory->count; i++)
Game::inventory -> getSlot(i) -> texture -> draw(BLOCKWIDTH*DISPLAYWIDTH + (INVWIDTH-INVBLOCKWIDTH)/2, i * INVWIDTH + (INVWIDTH-INVBLOCKWIDTH)/2, INVBLOCKWIDTH, INVBLOCKWIDTH);
//infotext
writeText(5, 5, (string)"Dragonblocks "+VERSION, GLUT_BITMAP_9_BY_15, COLOR_WHITE);
string infotext = "pos: ("+to_string(pos.x)+", "+to_string(pos.y)+"), seed: "+to_string(Game::seed);
if(pointed.x < DISPLAYWIDTH)
infotext += ", pointed: "+ Game::map->getNode(pointed.x+pos.x, pointed.y+pos.y)->name + "("+to_string(pointed.x+pos.x)+", "+to_string(pointed.y+pos.y)+")";
writeText(5, 20, infotext, GLUT_BITMAP_9_BY_15, COLOR_WHITE);
//writeText(5, 35, "world: "+Game::mapfile, GLUT_BITMAP_9_BY_15, COLOR_WHITE);
glFlush();
}
void Graphics::reshape(int width, int height){
glViewport(0, 0, width, height); /* Establish viewing area to cover entire window. */
glMatrixMode(GL_PROJECTION); /* Start modifying the projection matrix. */
glLoadIdentity(); /* Reset project matrix. */
glOrtho(0, width, 0, height, -1, 1); /* Map abstract coords directly to window coords. */
glScalef(1, -1, 1); /* Invert Y axis so increasing Y goes down. */
glTranslatef(0, -height, 0); /* Shift origin up to upper-pos.x corner. */
}
void Graphics::init(){
glutInit(Game::argc, Game::argv);
glutCreateWindow("Dragonblocks");
glutReshapeWindow(DISPLAYWIDTH*BLOCKWIDTH+INVWIDTH, DISPLAYHEIGHT*BLOCKWIDTH);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutSpecialFunc(special);
glutMouseFunc(mouse);
glutPassiveMotionFunc(motion);
glutMotionFunc(motion);
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glutMainLoop();
}
void Graphics::keyboard(unsigned char key, int x, int y){
}
void Graphics::special(int key, int x, int y){
switch(key){
case GLUT_KEY_LEFT:
if(pos.x > 0)
pos.x--;
break;
case GLUT_KEY_UP:
if(pos.y > 0)
pos.y--;
break;
case GLUT_KEY_RIGHT:
if(pos.x < MAPWIDTH-DISPLAYWIDTH)
pos.x++;
break;
case GLUT_KEY_DOWN:
if(pos.y < MAPHEIGHT-DISPLAYHEIGHT)
pos.y++;
break;
}
}
void Graphics::mouse(int key, int action, int x, int y){
if(action == 0){
if(x < BLOCKWIDTH*DISPLAYWIDTH){
switch(key){
case 0:
if(Game::map -> getNode(pointed.x+pos.x, pointed.y+pos.y)->stable)
Game::map -> setNode(pointed.x+pos.x, pointed.y+pos.y, MAPGEN_AIR);
break;
case 2:
if(! Game::map -> getNode(pointed.x+pos.x, pointed.y+pos.y)->stable)
Game::map -> setNode(pointed.x+pos.x, pointed.y+pos.y, Game::inventory->getSelectedSlot());
break;
}
}
else{
Game::inventory->select(y/INVWIDTH);
}
}
}
void Graphics::motion(int x, int y){
pointed.x = x / BLOCKWIDTH;
pointed.y = y / BLOCKWIDTH;
}
void Graphics::writeText(int x, int y, string text, void *font, color c){
glColor3f(c.red, c.green, c.blue);
glRasterPos2i(x, y+10);
char *s = strdup(text.c_str());
--s;
while(*++s)
glutBitmapCharacter(font, *s);
}
void Graphics::drawRectangle(int x, int y, int width, int height, color c){
glColor3f(c.red, c.green, c.blue);
glBegin(GL_POLYGON);
glVertex2i(x, y);
glVertex2i(x+width, y);
glVertex2i(x+width, y+height);
glVertex2i(x, y+height);
glEnd();
}

38
src/graphics.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef _GRAPHICS_H_
#define _GRAPHICS_H_
#include <string>
#include "texture.h"
#include "util.h"
#define BLOCKWIDTH 32
#define DISPLAYWIDTH 25
#define DISPLAYHEIGHT 25
#define INVBLOCKWIDTH 64
#define INVWIDTH 80
#define COLOR_WHITE {1,1,1}
#define COLOR_BLACK {0,0,0}
class Graphics{
public:
static void init();
static position pointed;
static position pos;
//handlers
static void display();
static void keyboard(unsigned char, int, int);
static void mouse(int, int, int, int);
static void special(int, int, int);
static void reshape(int, int);
static void motion(int, int);
//functions
static void drawRectangle(int, int, int, int, color);
static void writeText(int, int, std::string, void*, color);
};
#endif

24
src/inventory.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "node.h"
#include "inventory.h"
Inventory::Inventory(){
count = 0;
selected = 0;
for(int i = 0; i < Node::count; i++){
if(! Node::getNodeById(i) -> hidden){
list[count] = Node::getNodeById(i);
count++;
}
}
}
Node *Inventory::getSlot(int nr){
if(nr >= 0 && nr < count)
return list[nr];
return list[0];
}
void Inventory::select(int nr){
if(nr >= 0 && nr < count)
selected = nr;
}
Node *Inventory::getSelectedSlot(){
return list[selected];
}

17
src/inventory.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _INVENTORY_H_
#define _INVENTORY_H_
#include "node.h"
class Inventory{
public:
int count;
int selected;
Node *list[MAXNODES];
Node *getSlot(int);
void select(int);
Node *getSelectedSlot();
Inventory();
};
#endif

113
src/main.cpp Normal file
View File

@ -0,0 +1,113 @@
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <time.h>
#include <getopt.h>
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include "graphics.h"
#include "map.h"
#include "game.h"
#include "node.h"
#include "mapgen.h"
#include "mods.h"
#include "threads.h"
#include "inventory.h"
using namespace std;
Map *Game::map;
string Game::mapfile;
string Game::logfile;
int Game::seed;
char **Game::argv;
int *Game::argc;
FILE *Game::logfile_fd;
Inventory *Game::inventory;
int main(int argc, char **argv){
if((string)argv[0] != "bin/dragonblocks"){
string command = "cd ..; bin/dragonblocks -w world ";
while(*++argv)
command += *argv;
exit(system(command.c_str()));
}
create_dir_if_not_exists((string)getenv("HOME")+"/.dragonblocks");
create_dir_if_not_exists((string)getenv("HOME")+"/.dragonblocks/worlds");
Game::argc = &argc;
Game::argv = argv;
Game::seed = time(0);
Game::logfile = (string)getenv("HOME")+"/.dragonblocks/dragonblocks.log";
const char *short_options = "hrvs:l:w:p:";
const struct option long_options[] = {
{"help", 0, NULL, 'h'},
{"version", 0, NULL, 'v'},
{"worldname", 1, NULL, 'w'},
{"worldpath", 1, NULL, 'p'},
{"worldlist", 0, NULL, 'r'},
{"seed", 1, NULL, 's'},
{"logfile", 1, NULL, 'l'},
{NULL, 0, NULL, 0},
};
int next_option;
while((next_option = getopt_long(argc, argv, short_options, long_options, NULL)) != -1){
switch(next_option){
case 'h':
Game::help();
exit(EXIT_SUCCESS);
break;
case 'v':
Game::version();
exit(EXIT_SUCCESS);
break;
case 'p':
Game::mapfile = optarg;
break;
case 'w':
Game::mapfile = (string)getenv("HOME")+"/.dragonblocks/worlds/"+optarg;
break;
case 's':
Game::seed = atoi(optarg);
break;
case 'l':
Game::logfile = optarg;
break;
case 'r':
Game::worldlist();
exit(0);
break;
case '?':
Game::log("Invalid Usage", ERROR);
Game::help();
exit(EXIT_FAILURE);
break;
};
}
if(Game::logfile_fd = fopen(Game::logfile.c_str(), "a"))
fprintf(Game::logfile_fd, "\n--------------------------------------------------\n");
else
Game::log((string)"Failed to open log file " + Game::logfile, WARNING);
Game::log((string)"Welcome to Dragonblocks "+VERSION);
srand(Game::seed);
new Node("unknown_node", "textures/unknown_node.png", true, true, false);
Mods::init();
Game::inventory = new Inventory();
Game::map = new Map();
if(Game::mapfile == ""){
Game::log("No World Specified", ERROR);
exit(EXIT_FAILURE);
}
if(fopen(Game::mapfile.c_str(), "r"))
Game::map->load();
else
Mapgen();
Threads::startMapBackupThread();
Threads::startGraphicUpdateThread();
Threads::addSignalHandlers();
Graphics::init();
Game::log("Closed Window, Exiting.");
Game::map -> save();
return 0;
}

53
src/map.cpp Normal file
View File

@ -0,0 +1,53 @@
#include <string>
#include <stdlib.h>
#include <cstring>
#include <cstdio>
#include "map.h"
#include "node.h"
#include "game.h"
using namespace std;
Node *Map::getNode(int x, int y){
if(x < MAPWIDTH && y < MAPHEIGHT && x > -1 && y > -1)
return content[x][y];
return NULL;
}
void Map::setNode(int x, int y, Node *n){
if(x < MAPWIDTH && y < MAPHEIGHT && x > -1 && y > -1)
content[x][y] = n;
}
void Map::setNode(int x, int y, string n){
setNode(x, y, Node::getNodeByName(n));
}
void Map::load(){
Game::log("Loading Map from " + Game::mapfile);
FILE *mapfile = fopen(Game::mapfile.c_str(), "r");
if(mapfile){
for(int x = 0; x < MAPWIDTH; x++)
for(int y = 0; y < MAPHEIGHT; y++){
char buffer[512] = {0};
fscanf(mapfile, "%s", buffer);
setNode(x, y, buffer);
}
fclose(mapfile);
Game::log("Loaded Map");
}
else{
Game::log("Could not Load Map.", ERROR);
exit(EXIT_FAILURE);
}
}
void Map::save(){
Game::log("Saving Map to " + Game::mapfile);
FILE *mapfile = fopen(Game::mapfile.c_str(), "w");
if(mapfile){
for(int x = 0; x < MAPWIDTH; x++){
for(int y = 0; y < MAPHEIGHT; y++)
fprintf(mapfile,"%s ", getNode(x,y)->name.c_str());
fprintf(mapfile, "\n");
}
fclose(mapfile);
Game::log("Saved Map");
}
else
Game::log("Could not Save Map.", ERROR);
}

21
src/map.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef _MAP_H_
#define _MAP_H_
#include <string>
#include "node.h"
#define MAPWIDTH 500
#define MAPHEIGHT 100
class Map{
public:
Node *getNode(int, int);
void setNode(int, int, Node *);
void setNode(int, int, std::string);
void load();
void save();
private:
Node *content[MAPWIDTH][MAPHEIGHT];
};
#endif

121
src/mapgen.cpp Normal file
View File

@ -0,0 +1,121 @@
#include <string>
#include <iostream>
#include <stdlib.h>
#include <math.h>
#include "mapgen.h"
#include "map.h"
#include "node.h"
#include "util.h"
#include "game.h"
using namespace std;
void Mapgen(){
Game::log("Generating Map");
//Air
for(int x = 0; x < MAPWIDTH; x++){
for(int y = 0; y < MAPHEIGHT; y++){
Game::map->setNode(x,y,MAPGEN_AIR);
}
}
//Seed 13 Easteregg
if(Game::seed == 13){
for(int x = 0; x < MAPWIDTH; x++){
for(int y = 0; y < MAPHEIGHT; y++){
Game::map->setNode(x,y,MAPGEN_BEDROCK);
}
}
Game::log("LOL Seed 13", EASTEREGG);
return;
}
//Bottom
int bottom[MAPWIDTH];
bottom[0] = random(MAPHEIGHT/2 - MAPHEIGHT/10, MAPHEIGHT/2);
for(int x = 1; x < MAPWIDTH; x++){
bottom[x] = bottom[x-1] + random(-1,1);
}
//Smooth
for(int x = 1; x < MAPWIDTH-1; x++){
if(bottom[x] > bottom[x+1] && bottom[x] > bottom[x-1]) bottom[x]--;
else if(bottom[x] < bottom[x+1] && bottom[x] < bottom[x-1])bottom[x]++;
}
//Dirt with Grass
for(int x = 0; x < MAPWIDTH; x++){
Game::map->setNode(x,bottom[x],MAPGEN_GRASS);
}
//Dirt
for(int x = 0; x < MAPWIDTH; x++){
for(int y = bottom[x]+1; y < bottom[x]+5; y++){
Game::map->setNode(x,y,MAPGEN_DIRT);
}
}
//Stone
for(int x = 0; x < MAPWIDTH; x++){
for(int y = bottom[x]+5; y < MAPHEIGHT; y++){
Game::map->setNode(x,y,MAPGEN_STONE);
}
}
//Mese
for(int x = 0; x < MAPWIDTH; x++){
for(int y = bottom[x]+10; y < MAPHEIGHT; y++){
if((rand() % 100) == 0) Game::map->setNode(x,y,MAPGEN_MESE);
}
}
//Bedrock
for(int x = 0; x < MAPWIDTH; x++){
Game::map->setNode(x,MAPHEIGHT-1,MAPGEN_BEDROCK);
if(random(0,1) == 0){
Game::map->setNode(x,MAPHEIGHT-2,MAPGEN_BEDROCK);
if(random(0,2) == 0){
Game::map->setNode(x,MAPHEIGHT-3,MAPGEN_BEDROCK);
}
}
}
//Water
int flatcount = 0;
for(int x = 1; x < MAPWIDTH; x++){
if(bottom[x] == bottom[x-1]) flatcount++;
else if(flatcount > 7){
int leftborder = rand() % 2;
int rightborder = rand() % 2;
for(int mx = x-flatcount-3; mx < x+2; mx++){
for(int y = bottom[mx];y < bottom[mx]+5;y++){
if(Game::map->getNode(mx,y) == MAPGEN_STONE) break;
if(Game::map->getNode(mx,y) == MAPGEN_DIRT || Game::map->getNode(mx,y) == MAPGEN_GRASS) Game::map->setNode(mx,y,MAPGEN_SAND);
}
}
for(int mx = x-flatcount+leftborder;mx < x-1-rightborder;mx++) Game::map->setNode(mx,bottom[x-1],MAPGEN_WATER);
for(int mx = x-flatcount+1+leftborder;mx < x-2-rightborder;mx++) Game::map->setNode(mx,bottom[x-1]+1,MAPGEN_WATER);
for(int mx = x-flatcount+2+leftborder; mx < x-3-rightborder;mx++) Game::map->setNode(mx,bottom[x-1]+2,MAPGEN_WATER);
flatcount = 0;
}
else flatcount = 0;
}
//Tree
int treecount = rand() % MAPWIDTH/10;
int treepos[treecount];
for(int i = 0; i < treecount; i++){
while(true){
bool cont = true;
treepos[i] = rand() % MAPWIDTH;
for(int j = 0; j < i; j++){
if(abs(treepos[j]-treepos[i]) < 3) cont = false;
}
if(!(Game::map->getNode(treepos[i],bottom[treepos[i]]) == MAPGEN_GRASS)) cont = false;
if(cont) break;
}
int x = treepos[i];
int y = bottom[x] - 1;
Game::map->setNode(x,y,MAPGEN_WOOD);
Game::map->setNode(x,y-1,MAPGEN_WOOD);
Game::map->setNode(x,y-2,MAPGEN_LEAVES);
Game::map->setNode(x,y-3,MAPGEN_LEAVES);
Game::map->setNode(x,y-4,MAPGEN_LEAVES);
Game::map->setNode(x-1,y-2,MAPGEN_LEAVES);
Game::map->setNode(x-1,y-3,MAPGEN_LEAVES);
Game::map->setNode(x-1,y-4,MAPGEN_LEAVES);
Game::map->setNode(x+1,y-2,MAPGEN_LEAVES);
Game::map->setNode(x+1,y-3,MAPGEN_LEAVES);
Game::map->setNode(x+1,y-4,MAPGEN_LEAVES);
}
}

21
src/mapgen.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef _MAPGEN_H_
#define _MAPGEN_H_
#include "map.h"
#define MAPGEN_AIR Node::getNodeByName("dragonblocks:air")
#define MAPGEN_GRASS Node::getNodeByName("dragonblocks:grass")
#define MAPGEN_DIRT Node::getNodeByName("dragonblocks:dirt")
#define MAPGEN_STONE Node::getNodeByName("dragonblocks:stone")
#define MAPGEN_BEDROCK Node::getNodeByName("dragonblocks:bedrock")
#define MAPGEN_MESE Node::getNodeByName("dragonblocks:mese")
#define MAPGEN_LEAVES Node::getNodeByName("dragonblocks:leaves")
#define MAPGEN_WOOD Node::getNodeByName("dragonblocks:wood")
#define MAPGEN_WATER Node::getNodeByName("dragonblocks:water")
#define MAPGEN_SAND Node::getNodeByName("dragonblocks:sand")
void Mapgen();
#endif

87
src/mods.cpp Normal file
View File

@ -0,0 +1,87 @@
#include <cstring>
#include <cstdio>
#include <cerrno>
#include <string>
#include <iostream>
#include "node.h"
#include "mods.h"
#include "game.h"
#include "util.h"
#include "graphics.h"
using namespace std;
lua_State *Mods::lua_vm;
void Mods::init(){
Game::log("Initializing Mods");
lua_vm = luaL_newstate();
luaL_openlibs(lua_vm);
if(! check_lua(luaL_dofile(lua_vm, "builtin/init.lua"))){
Game::log("Failed to load Builtin", ERROR);
exit(EXIT_FAILURE);
return;
}
for(;;){
lua_getglobal(lua_vm, "cpp_get_next_node");
if(!lua_isfunction(lua_vm, -1)){
Game::log("Lua is sick. What's Wrong with her?", EASTEREGG);
Game::log("No, seriously, something is wrong with the lua builtin (it is missing the function cpp_get_next_node)", ERROR);
exit(EXIT_FAILURE);
}
lua_pcall(lua_vm, 0, 1, 0);
if(! lua_istable(lua_vm, -1))
break;
lua_pushstring(lua_vm, "name");
lua_gettable(lua_vm, -2);
if(!lua_isstring(lua_vm,-1))
continue;
string name = lua_tostring(lua_vm,-1);
lua_pop(lua_vm, 1);
lua_pushstring(lua_vm, "texture");
lua_gettable(lua_vm, -2);
if(!lua_isstring(lua_vm,-1))
continue;
string texture = lua_tostring(lua_vm,-1);
lua_pop(lua_vm, 1);
lua_pushstring(lua_vm, "hidden");
lua_gettable(lua_vm, -2);
if(!lua_isboolean(lua_vm,-1))
continue;
bool hidden = lua_toboolean(lua_vm,-1);
lua_pop(lua_vm, 1);
lua_pushstring(lua_vm, "stable");
lua_gettable(lua_vm, -2);
if(!lua_isboolean(lua_vm,-1))
continue;
bool stable = lua_toboolean(lua_vm,-1);
lua_pop(lua_vm, 1);
lua_pushstring(lua_vm, "translucent");
lua_gettable(lua_vm, -2);
if(!lua_isboolean(lua_vm,-1))
continue;
bool translucent = lua_toboolean(lua_vm,-1);
lua_pop(lua_vm, 1);
new Node(name, texture, hidden, stable, translucent);
Game::log("Registered Node " + name, INFO);
}
}
bool Mods::check_lua(int code){
if(code == LUA_OK)
return true;
else{
error(lua_tostring(lua_vm, -1));
return false;
}
}
void Mods::error(string text){
Game::log("\e[34mlua: \e[0m" + text, ERROR);
}

19
src/mods.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef _MODS_H_
#define _MODS_H_
#include <string>
extern "C"{
#include <lua5.3/lua.h>
#include <lua5.3/lauxlib.h>
#include <lua5.3/lualib.h>
}
class Mods{
public:
static lua_State *lua_vm;
static bool check_lua(int);
static void init();
static void error(std::string);
};
#endif

44
src/node.cpp Normal file
View File

@ -0,0 +1,44 @@
#include <string>
#include <stdlib.h>
#include <iostream>
#include "node.h"
#include "game.h"
#include "texture.h"
using namespace std;
int Node::count = 0;
Node *Node::list[MAXNODES];
Node::Node(string n, string t, bool h, bool s, bool tr){
if (Node::count >= MAXNODES)
Game::log("Too many registered Nodes", ERROR);
else{
name = n;
id = Node::count;
hidden = h;
stable = s;
Node::list[id] = this;
texture = new Texture(t,tr);
Node::count++;
}
}
Node *Node::getNodeById(int id){
if(id < count && id > -1)
return list[id];
return list[0];
}
Node *Node::getNodeByName(string name){
for(int i = 0; i < count; i++){
if(list[i]->name == name ){
return list[i];
}
}
Game::log("Node "+name+" not found", WARNING);
return list[0];
}
bool Node::operator==(Node *node){
return id == node->id;
}
bool Node::operator==(string n){
return name == n;
}

25
src/node.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef _NODE_H_
#define _NODE_H_
#include <string>
#include "texture.h"
#define MAXNODES 1024
class Node{
public:
int id;
std::string name;
static Node *getNodeById(int);
static Node *getNodeByName(std::string);
static Node *list[MAXNODES];
static int count;
bool operator==(Node *);
bool operator==(std::string);
Texture *texture;
bool hidden;
bool stable;
bool translucent;
Node(std::string, std::string, bool, bool, bool);
};
#endif

74
src/texture.cpp Normal file
View File

@ -0,0 +1,74 @@
#include <GL/freeglut.h>
#include <png.h>
#include <string>
#include <iostream>
#include <cstring>
#include <cassert>
#include <cstdio>
#include "game.h"
#include "graphics.h"
#include "texture.h"
using namespace std;
Texture::Texture(string filename, bool t){
translucent = t;
dummyimage = false;
FILE *file = fopen(filename.c_str(), "rb");
if(!file){
Game::log("Failed to Load Image " + filename + ": File not found. Using a dummy Image.", WARNING);
dummyimage = true;
return;
}
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
assert(png);
png_infop info = png_create_info_struct(png);
assert(info);
png_init_io(png, file);
png_read_info(png, info);
width = png_get_image_width(png, info);
height = png_get_image_height(png, info);
color_type = png_get_color_type(png, info);
bit_depth = png_get_bit_depth(png, info);
if(bit_depth == 16)
png_set_strip_16(png);
if(color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
#ifndef _WIN32
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png);
#endif
if(png_get_valid(png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png);
if(color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
png_read_update_info(png, info);
row_pointers = (png_bytep*)malloc(sizeof(png_bytep) *height);
for(int y = 0; y < height; y++) {
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info));
}
png_read_image(png, row_pointers);
fclose(file);
png_destroy_read_struct(&png, &info, NULL);
}
void Texture::draw(int displayX, int displayY, int displayWidth, int displayHeight){
if(dummyimage){
Graphics::drawRectangle(displayX, displayY, displayWidth, displayHeight, {0, 0, 0});
return;
}
int scaleX = (float)displayWidth/width;
int scaleY = (float)displayHeight/height;
for(int y = 0; y < height; y++) {
png_bytep row = row_pointers[y];
for(int x = 0; x < width; x++) {
png_bytep px = &(row[x * 4]);
if(!translucent || px[0] || px[1] || px[2])
Graphics::drawRectangle(x*scaleX + displayX, y*scaleY + displayY, scaleX, scaleY, {(float)px[0]/255, (float)px[1]/255, (float)px[2]/255});
}
}
}

20
src/texture.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _TEXTURE_H_
#define _TEXTURE_H_
#include <png.h>
#include <string>
class Texture{
public:
int width;
int height;
void draw(int, int, int, int);
Texture(std::string, bool);
private:
png_byte color_type;
png_byte bit_depth;
png_bytep *row_pointers;
bool dummyimage;
bool translucent;
};
#endif

57
src/threads.cpp Normal file
View File

@ -0,0 +1,57 @@
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <GL/glut.h>
#include <iostream>
#include <algorithm>
#include "threads.h"
#include "graphics.h"
#include "game.h"
using namespace std;
void Threads::startMapBackupThread(){
Game::log("Starting Map Backup Thread");
pthread_t thread_id;
pthread_create(&thread_id, NULL, &mapBackupThread, NULL);
}
void *Threads::mapBackupThread(void *unused){
while(true){
sleep(MAP_BACKUP_INTERVAL);
Game::map -> save();
}
return NULL;
}
void Threads::startGraphicUpdateThread(){
Game::log("Starting Graphic Update Thread");
pthread_t thread_id;
pthread_create(&thread_id, NULL, &graphicUpdateThread, NULL);
}
void *Threads::graphicUpdateThread(void *unused){
while(true){
usleep(1);
if(glutGetWindow())
glutPostRedisplay();
}
return NULL;
}
void Threads::addSignalHandlers(){
#ifndef _WIN32
struct sigaction sa_sigterm;
sa_sigterm.sa_handler = &signal_handler;
sigaction(SIGTERM, &sa_sigterm, NULL);
struct sigaction sa_sigint;
sa_sigint.sa_handler = &signal_handler;
sigaction(SIGINT, &sa_sigint, NULL);
#endif
}
void Threads::signal_handler(int signal_number){
#ifndef _WIN32
Game::log((string)"Got "+sys_siglist[signal_number]+" Signal, Exiting.");
Game::map -> save();
exit(0);
#endif
}

17
src/threads.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _THREADS_H_
#define _THREADS_H_
#define MAP_BACKUP_INTERVAL 15
class Threads{
public:
static void startMapBackupThread();
static void addSignalHandlers();
static void startGraphicUpdateThread();
private:
static void *mapBackupThread(void *);
static void *graphicUpdateThread(void *);
static void signal_handler(int);
};
#endif

40
src/util.cpp Normal file
View File

@ -0,0 +1,40 @@
#include <stdlib.h>
#include <cstring>
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstdio>
#include <string>
#include "util.h"
#include "game.h"
using namespace std;
int random(int min, int max){
return min + rand() % (max - min + 1);
}
color::color(const char *htmlcolor){
unsigned int r, g, b;
sscanf(htmlcolor, "#%2x%2x%2x", &r, &g, &b);
red = (float) r / 255;
green = (float) g / 255;
blue = (float) b / 255;
}
color::color(float r, float g, float b){
red = r;
green = g;
blue = b;
}
void create_dir_if_not_exists(string d){
const char *dir = d.c_str();
struct stat dir_exists_st = {0};
if(stat(dir, &dir_exists_st) == -1){
Game::log((string)dir + " doesn't exist, creating", INFO);
#ifdef _WIN32
mkdir(dir);
#else
mkdir(dir, 0700);
#endif
}
}

20
src/util.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _UTIL_H_
#define _UTIL_H_
#include <string>
class color{
public:
float red;
float green;
float blue;
color(const char *);
color(float, float, float);
};
class position{
public:
int x;
int y;
};
int random(int, int);
void create_dir_if_not_exists(std::string d);
#endif

BIN
textures/air.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

BIN
textures/bedrock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

BIN
textures/cobble.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

BIN
textures/dirt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
textures/grass.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

BIN
textures/leaves.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

BIN
textures/mese.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

BIN
textures/sand.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

BIN
textures/stone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

BIN
textures/unknown_node.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

BIN
textures/water.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

BIN
textures/wood.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B