diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..7398a69 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,31 @@ +name: Build all + +on: + push: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: docker-practice/actions-setup-docker@master + - name: Setup Docker Multiarch + run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + - name: Build ARM + run: | + docker pull arm32v7/buildpack-deps:buster + docker run -v $PWD:$PWD -w $PWD --rm arm32v7/buildpack-deps:buster bash ./ci.sh + - name: Build AArch64 + run: | + docker pull arm64v8/buildpack-deps:buster + docker run -v $PWD:$PWD -w $PWD --rm arm64v8/buildpack-deps:buster bash ./ci.sh + - name: Build x86_64 + run: | + docker pull amd64/buildpack-deps:buster + docker run -v $PWD:$PWD -w $PWD --rm amd64/buildpack-deps:buster bash ./ci.sh + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: gmcpil_debs + path: gmcpil_*.deb diff --git a/.github/workflows/build_amd64.yml b/.github/workflows/build_amd64.yml deleted file mode 100644 index 90401a4..0000000 --- a/.github/workflows/build_amd64.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Build amd64 - -on: - push: - branches: [ master ] - -jobs: - build_amd64: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - name: Install Dependencies - run: sudo apt update && sudo apt install -y git make fakeroot binutils-arm-linux-gnueabihf gcc-arm-linux-gnueabihf dpkg-dev build-essential crossbuild-essential-armhf libgtk-3-dev libjson-glib-dev - - name: Make - run: make - - name: Make DEB - run: make pack - - name: Upload artifacts - uses: actions/upload-artifact@v2 - with: - name: gmcpil_latest_amd64.deb - path: gmcpil_*.deb diff --git a/.gitignore b/.gitignore index 1cde438..14787ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # Builds build/ +*.c +*.o # Debian *.deb diff --git a/Makefile b/Makefile index 9e4f632..d28b695 100644 --- a/Makefile +++ b/Makefile @@ -1,104 +1,61 @@ -# -# Makefile -# -# Copyright 2021 Alvarito050506 -# -# 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. -# -# +VERSION:=0.13.0 +SRCS:=$(patsubst %,./src/%.vala,profile config gui play features servers) +SRCS+=./src/gmcpil.vapi -ifdef USE_CLANG -ifeq ($(origin CC),default) -CC:=clang -endif -STRIP?=llvm-strip -LDFLAGS:=-fuse-ld=lld -ARCH:=$(shell $(CC) -dumpmachine | grep -Eo "arm|aarch|86|x86_64") -else -ifeq ($(origin CC),default) -CC:=gcc -endif STRIP?=strip -LDFLAGS:= -ARCH:=$(shell $(CC) -print-multiarch | grep -Eo "arm|aarch|86|x86_64") +PKG_CONFIG?=pkg-config +ifdef CROSS_COMPILE +CC:=$(CROSS_COMPILE)-gcc +PKG_CONFIG:=$(CROSS_COMPILE)-pkg-config +STRIP:=$(CROSS_COMPILE)-strip endif -VERSION:=0.12.0 - -OBJS:=$(patsubst %,build/%.o,mcpil config features play servers) +VFLAGS:=--pkg json-glib-1.0 --pkg gio-2.0 --pkg gtk+-3.0 +VFLAGS+=--cc=$(CC) --pkg-config=$(PKG_CONFIG) -X -DGMCPIL_VERSION="\"v$(VERSION)\"" -CFLAGS+=-DGMCPIL_VERSION=\"v$(VERSION)\" -I./src/include -Wall -Wno-address-of-packed-member -Wno-pointer-to-int-cast -Wno-unused-result -CFLAGS+=$(shell pkg-config --cflags gtk+-3.0 json-glib-1.0) -LDFLAGS+=-Wl,--no-undefined $(shell pkg-config --libs gtk+-3.0 json-glib-1.0) +ARCH:=$(shell $(CC) -dumpmachine | grep -Eo "arm|aarch|86|x86_64") +ifeq ($(ARCH),86) + DEB_ARCH:=i386 +else ifeq ($(ARCH),x86_64) + DEB_ARCH:=amd64 +else ifeq ($(ARCH),aarch) + DEB_ARCH:=arm64 +else + DEB_ARCH:=armhf +endif ifdef DEBUG -CFLAGS+=-g -Wextra -Werror +VFLAGS+=-X -g --save-temps --fatal-warnings else -CFLAGS+=-O3 +VFLAGS+=-X -O3 endif -# Some GTK+/GDK-Pixbuf combinations may generate this warning -# for internal functions, so let's "ignore" it. -CFLAGS+=-Wno-error=deprecated-declarations - -.PHONY: ./build/gmcpil +ifndef NO_BUSTER_COMPAT +VFLAGS+=-D BUSTER_COMPAT +endif -./build/gmcpil: mkdir $(OBJS) - $(CC) -fPIC -fpie $(OBJS) -o $@ $(CFLAGS) $(LDFLAGS) +./build/gmcpil: ./build/ $(SRCS) + valac $(VFLAGS) $(SRCS) -o ./build/gmcpil ifndef DEBUG $(STRIP) ./build/gmcpil endif -./build/%.o: ./src/%.c ./src/include/*.h - $(CC) -fPIC -fpie -c $< -o $@ $(CFLAGS) - -mkdir: +./build/: mkdir -p ./build/ pack: ./build/gmcpil mkdir -p ./deb/DEBIAN/ mkdir -p ./deb/usr/bin/ - mkdir -p ./deb/usr/share/ cp ./build/gmcpil ./deb/usr/bin/ - cp -r ./res/. ./deb/usr/share/ + cp -r ./res/usr/share/ ./deb/usr/ chmod a+x ./deb/usr/bin/gmcpil - @echo "Package: gmcpil" > ./deb/DEBIAN/control - @echo "Version: $(VERSION)" >> ./deb/DEBIAN/control - @echo "Priority: optional" >> ./deb/DEBIAN/control -ifeq ($(ARCH),86) - @echo "Architecture: i386" >> ./deb/DEBIAN/control -else ifeq ($(ARCH),x86_64) - @echo "Architecture: amd64" >> ./deb/DEBIAN/control -else ifeq ($(ARCH),aarch) - @echo "Architecture: arm64" >> ./deb/DEBIAN/control -else - @echo "Architecture: armhf" >> ./deb/DEBIAN/control -endif - @echo "Section: contrib/misc" >> ./deb/DEBIAN/control - @echo "Depends: libc6 (>= 2.28), minecraft-pi-reborn-client (>= 2.1.0), libgtk-3-0, libjson-glib-1.0-0" >> ./deb/DEBIAN/control - @echo "Maintainer: Alvarito050506 " >> ./deb/DEBIAN/control - @echo "Homepage: https://mcpirevival.tk" >> ./deb/DEBIAN/control - @echo "Vcs-Browser: https://github.com/MCPI-Revival/gMCPIL" >> ./deb/DEBIAN/control - @echo "Vcs-Git: https://github.com/MCPI-Revival/gMCPIL.git" >> ./deb/DEBIAN/control - @echo "Description: Simple launcher for Minecraft: Pi Edition - GTK+ Edition." >> ./deb/DEBIAN/control - @echo " Simple GUI launcher for Minecraft: Pi Edition and MCPI-Reborn," >> ./deb/DEBIAN/control - @echo " rewritten in C using GTK+ 3." >> ./deb/DEBIAN/control - fakeroot dpkg-deb -b ./deb/ ./gmcpil_$(VERSION).deb + sed "s/{{ARCH}}/$(DEB_ARCH)/g; s/{{VERSION}}/$(VERSION)/g" ./res/control > ./deb/DEBIAN/control + fakeroot dpkg-deb -b ./deb/ ./gmcpil_$(VERSION)_$(DEB_ARCH).deb clean: rm -rf ./deb/ + rm -rf ./src/*.c rm -rf ./build/ + +purge: clean rm -f ./gmcpil_*.deb diff --git a/README.md b/README.md index 6ae8ca8..8049c74 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,16 @@

gMCPIL

- Simple launcher for Minecraft: Pi Edition and MCPI-Reborn - GTK+ Edition. + Simple launcher for Minecraft: Pi Edition and MCPI-Reborn - Vala/GTK+ Edition.

- GPL-2.0 + GPL-2.0 Latest release

-

screenshot

@@ -34,36 +33,23 @@ sudo apt install gmcpil You can also download and install it from the [releases](https://github.com/MCPI-Revival/gMCPIL/releases) section. ### Compiling -To build gMCPIL, you'll need GCC or Clang for the native and `arm-linux-gnueabihf` targets, plus some additional packages. -Assuming a Debian-based distro, you can install them with the following command: -```sh -# For GCC -sudo apt install gcc build-essential gcc-arm-linux-gnueabihf crossbuild-essential-armhf - -# Libraries and other build dependencies -sudo apt install git make libjson-glib-dev libgtk-3-dev dpkg-dev fakeroot -``` +To build gMCPIL, you'll need Vala, a C compiler, and some additional packages. +Assuming a Debian-based distro, you can install them running the commands listed +[here](https://github.com/MCPI-Revival/gMCPIL/blob/master/ci.sh#L7-L13) as root. After installing the build dependencies, you can clone the repo and build gMCPIL: ```sh git clone https://github.com/MCPI-Revival/gMCPIL cd gMCPIL -make # Build gMCPIL and mods +make # Build gMCPIL make pack # Make a Debian package ``` -You can also set the `DEBUG` and `USE_CLANG` environment variables to add debug symbols to the executable -and build using Clang instead of GCC, respectively. - -## Features - + Full MCPI-Reborn integration - + Proxy-free multiplayer - + Featured servers - + Coming soon: More stuff +You can also set the `DEBUG` environment variable to add debug symbols to the executable. ## Changelog -See the [CHANGELOG.txt](https://github.com/MCPI-Revival/gMCPIL/blob/master/res/doc/gmcpil/CHANGELOG.txt) file. +See the [CHANGELOG.txt](https://github.com/MCPI-Revival/gMCPIL/blob/master/res/usr/share/doc/gmcpil/CHANGELOG.txt) file. ## Licensing All the code of this project is licensed under the [GNU General Public License version 2.0](https://github.com/Alvarito050506/MCPIL/blob/master/LICENSE) (GPL-2.0). diff --git a/ci.sh b/ci.sh new file mode 100755 index 0000000..b7d55f5 --- /dev/null +++ b/ci.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +export DEBIAN_FRONTEND="noninteractive" + +echo "deb [trusted=yes] https://deb.debian.org/debian buster-backports main contrib non-free" >> /etc/apt/sources.list + +apt update +apt upgrade -y +apt install -y git make fakeroot dpkg-dev build-essential libgtk-3-dev libjson-glib-dev +apt install -y -t buster-backports valac +apt --fix-broken install + +make pack +make clean diff --git a/res/control b/res/control new file mode 100644 index 0000000..6f6fd41 --- /dev/null +++ b/res/control @@ -0,0 +1,13 @@ +Package: gmcpil +Version: {{VERSION}} +Priority: optional +Architecture: {{ARCH}} +Section: contrib/misc +Depends: libc6 (>= 2.28), minecraft-pi-reborn-client (>= 2.1.0), libgtk-3-0, libjson-glib-1.0-0 +Maintainer: Alvarito050506 +Homepage: https://mcpirevival.tk +Vcs-Browser: https://github.com/MCPI-Revival/gMCPIL +Vcs-Git: https://github.com/MCPI-Revival/gMCPIL.git +Description: Simple launcher for Minecraft: Pi Edition - GTK+ Edition. + Simple GUI launcher for Minecraft: Pi Edition and MCPI-Reborn, + rewritten in Vala using GTK+ 3. diff --git a/res/applications/gmcpil.desktop b/res/usr/share/applications/gmcpil.desktop similarity index 100% rename from res/applications/gmcpil.desktop rename to res/usr/share/applications/gmcpil.desktop diff --git a/res/doc/gmcpil/CHANGELOG.txt b/res/usr/share/doc/gmcpil/CHANGELOG.txt similarity index 89% rename from res/doc/gmcpil/CHANGELOG.txt rename to res/usr/share/doc/gmcpil/CHANGELOG.txt index 9d08595..4eaf96e 100644 --- a/res/doc/gmcpil/CHANGELOG.txt +++ b/res/usr/share/doc/gmcpil/CHANGELOG.txt @@ -1,3 +1,8 @@ +v0.13.0: + + Rewritten in Vala. + + More refactoring. + + Fixed various bugs. + v0.12.0: + New, fancy GUI. + Lots of "refactoring". diff --git a/res/doc/gmcpil/copyright b/res/usr/share/doc/gmcpil/copyright similarity index 100% rename from res/doc/gmcpil/copyright rename to res/usr/share/doc/gmcpil/copyright diff --git a/res/icons/hicolor/128x128/apps/gmcpil.png b/res/usr/share/icons/hicolor/128x128/apps/gmcpil.png similarity index 100% rename from res/icons/hicolor/128x128/apps/gmcpil.png rename to res/usr/share/icons/hicolor/128x128/apps/gmcpil.png diff --git a/res/icons/hicolor/16x16/apps/gmcpil.png b/res/usr/share/icons/hicolor/16x16/apps/gmcpil.png similarity index 100% rename from res/icons/hicolor/16x16/apps/gmcpil.png rename to res/usr/share/icons/hicolor/16x16/apps/gmcpil.png diff --git a/res/icons/hicolor/24x24/apps/gmcpil.png b/res/usr/share/icons/hicolor/24x24/apps/gmcpil.png similarity index 100% rename from res/icons/hicolor/24x24/apps/gmcpil.png rename to res/usr/share/icons/hicolor/24x24/apps/gmcpil.png diff --git a/res/icons/hicolor/32x32/apps/gmcpil.png b/res/usr/share/icons/hicolor/32x32/apps/gmcpil.png similarity index 100% rename from res/icons/hicolor/32x32/apps/gmcpil.png rename to res/usr/share/icons/hicolor/32x32/apps/gmcpil.png diff --git a/res/icons/hicolor/48x48/apps/gmcpil.png b/res/usr/share/icons/hicolor/48x48/apps/gmcpil.png similarity index 100% rename from res/icons/hicolor/48x48/apps/gmcpil.png rename to res/usr/share/icons/hicolor/48x48/apps/gmcpil.png diff --git a/res/icons/hicolor/64x64/apps/gmcpil.png b/res/usr/share/icons/hicolor/64x64/apps/gmcpil.png similarity index 100% rename from res/icons/hicolor/64x64/apps/gmcpil.png rename to res/usr/share/icons/hicolor/64x64/apps/gmcpil.png diff --git a/screenshot.png b/screenshot.png index 2df2387..66b1506 100644 Binary files a/screenshot.png and b/screenshot.png differ diff --git a/src/config.c b/src/config.c deleted file mode 100644 index 62da6f9..0000000 --- a/src/config.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * config.c - GMCPILConfig class - * - * Copyright 2021 Alvarito050506 - * - * 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. - * - */ - -#define _GNU_SOURCE /* Required for asprintf */ - -#include -#include - -#include -#include -#include - -struct __attribute__((packed)) GMCPILConfigPrivate -{ - gchar* username; - gchar* features; - gchar* distance; - gchar* last_profile; - gchar* hud; - gchar* hide; - gchar* last_featc; - gchar* filename; -}; - -enum -{ - PROP_NULL, - PROP_USERNAME, - PROP_FEATURES, - PROP_DISTANCE, - PROP_LAST_PROFILE, - PROP_HUD, - PROP_HIDE, - PROP_LAST_FEATC, - PROP_LAST -}; - -G_DEFINE_TYPE_WITH_CODE(GMCPILConfig, gmcpil_config, G_TYPE_OBJECT, G_ADD_PRIVATE(GMCPILConfig)) - -static void gmcpil_config_finalize(GObject* obj); -static void gmcpil_config_set_property(GObject* obj, guint prop_id, const GValue* value, GParamSpec* pspec); -static void gmcpil_config_get_property(GObject* obj, guint prop_id, GValue* value, GParamSpec* pspec); - -static void gmcpil_config_class_init(GMCPILConfigClass* klass) -{ - GObjectClass* gobject_class = G_OBJECT_CLASS(klass); - GParamSpec* pspec; - - gobject_class->finalize = gmcpil_config_finalize; - - gobject_class->get_property = gmcpil_config_get_property; - gobject_class->set_property = gmcpil_config_set_property; - - GMCPIL_GLIB_PROPERTY("username", "Username", "Player name", PROP_USERNAME); - GMCPIL_GLIB_PROPERTY("features", "Features", "MCPI-Reborn features", PROP_FEATURES); - GMCPIL_GLIB_PROPERTY("distance", "Distance", "Render distance", PROP_DISTANCE); - GMCPIL_GLIB_PROPERTY("last_profile", "Last profile", "Last selected profile", PROP_LAST_PROFILE); - GMCPIL_GLIB_PROPERTY("hud", "Gallium HUD", "Gallium HUD options", PROP_HUD); - GMCPIL_GLIB_PROPERTY("hide", "Hide launcher", "Hide launcher on launch", PROP_HIDE); - GMCPIL_GLIB_PROPERTY("last_featc", "Last feature count", "Last MCPI-Reborn feature count", PROP_LAST_FEATC); - return; -} - -static void gmcpil_config_init(GMCPILConfig* self) -{ - int i = 0; - GMCPILConfigPrivate* private = GMCPIL_CONFIG_PRIVATE(self); - gchar** private_gchar = (gchar**)(private); - - while (i < PROP_LAST - 1) - { - private_gchar[i] = NULL; - i++; - } - return; -} - -static void gmcpil_config_finalize(GObject* obj) -{ - int i = 0; - GMCPILConfig* self = GMCPIL_CONFIG(obj); - GMCPILConfigPrivate* private = GMCPIL_CONFIG_PRIVATE(self); - GObjectClass* parent_class = G_OBJECT_CLASS(gmcpil_config_parent_class); - gchar** private_gchar = (gchar**)(private); - - while (i < PROP_LAST - 1) - { - if (private_gchar[i] != NULL) - { - g_free(private_gchar[i]); - } - i++; - } - (*parent_class->finalize)(obj); - return; -} - -GMCPIL_GETTER_SETTER(username); -GMCPIL_GETTER_SETTER(features); -GMCPIL_GETTER_SETTER(distance); -GMCPIL_INT_GETTER_SETTER(last_profile); -GMCPIL_GETTER_SETTER(hud); -GMCPIL_GETTER_SETTER(hide); -GMCPIL_INT_GETTER_SETTER(last_featc); - -static void gmcpil_config_set_property(GObject* obj, guint prop_id, const GValue* value, GParamSpec* pspec) -{ - GMCPILConfig* self = GMCPIL_CONFIG(obj); - GMCPILConfigPrivate* private = GMCPIL_CONFIG_PRIVATE(self); - gchar** private_gchar = (gchar**)(private); - - if (prop_id <= PROP_LAST) - { - private_gchar[prop_id - 1] = g_strdup((gchar*)g_value_get_string(value)); - } else - { - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); - } - return; -} - -static void gmcpil_config_get_property(GObject* obj, guint prop_id, GValue* value, GParamSpec* pspec) -{ - GMCPILConfig* self = GMCPIL_CONFIG(obj); - GMCPILConfigPrivate* private = GMCPIL_CONFIG_PRIVATE(self); - gchar** private_gchar = (gchar**)(private); - - if (prop_id <= PROP_LAST) - { - g_value_set_string(value, private_gchar[prop_id - 1]); - } else - { - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); - } - return; -} - -GMCPILConfig* gmcpil_config_new(gchar* filename) -{ - int sz; - char* buff; - FILE* fd; - GMCPILConfig* self; - GMCPILConfigPrivate* private; - GObject* obj; - GError* err = NULL; - - fd = fopen(filename, "a+"); - if (fd == NULL) - { - return NULL; - } - - fseek(fd, 0, SEEK_END); - sz = ftell(fd); - fseek(fd, 0, SEEK_SET); - - if (sz <= 13) /* {"ip":"a.co"} */ - { - buff = (char*)malloc(2); - buff[0] = '{'; - buff[1] = '}'; - sz = 2; - } else - { - buff = (char*)malloc(sz + 1); - fread(buff, 1, sz, fd); - } - - obj = json_gobject_from_data(GMCPIL_TYPE_CONFIG, buff, sz, &err); - if (err != NULL) - { - err = NULL; - obj = g_object_new(GMCPIL_TYPE_CONFIG, 0); - } - self = GMCPIL_CONFIG(obj); - private = GMCPIL_CONFIG_PRIVATE(self); - private->filename = g_strdup(filename); - - free(buff); - fclose(fd); - return self; -} - -int gmcpil_config_save(GMCPILConfig* self) -{ - char* buff; - FILE* fd; - GMCPILConfigPrivate* private = GMCPIL_CONFIG_PRIVATE(self); - - fd = fopen(private->filename, "w"); - if (fd == NULL) - { - return -1; - } - - buff = json_gobject_to_data(G_OBJECT(self), NULL); - fwrite(buff, 1, strlen(buff), fd); - - free(buff); - fclose(fd); - return 0; -} diff --git a/src/config.vala b/src/config.vala new file mode 100644 index 0000000..a676aa5 --- /dev/null +++ b/src/config.vala @@ -0,0 +1,159 @@ +using Gtk; + +namespace GMCPIL +{ + public enum Distance + { + TINY, + SHORT, + NORMAL, + FAR + } + + public class Config : Object, Json.Serializable + { + public bool hide { get; set; default = true; } + public string hud { get; set; default = "simple,fps"; } + public string username { get; set; default = "StevePi"; } + public Object features { get; set; } + public ProfileType profile { get; set; } + public Distance distance { get; set; default = Distance.SHORT; } + public bool modified = false; + string filename; + public TextBuffer servers; + + public static string[] distance_names = { + "Tiny", + "Short", + "Normal", + "Far" + }; + + construct + { + this.notify.connect(() => { + modified = true; + }); + } + + public static Config from_file(string filename) throws Error + { + File file; + FileInputStream stream; + Json.Parser parser; + Json.Node root; + Json.Object root_obj; + Config config; + + file = File.new_for_path(filename); + if (!file.query_exists()) + { + file.create(FileCreateFlags.NONE); + } + stream = file.read(); + + parser = new Json.Parser(); + parser.load_from_stream(stream); + + root = parser.get_root(); + if (root == null) + { + root = new Json.Node(Json.NodeType.OBJECT); + root_obj = new Json.Object(); + root.set_object(root_obj); + } + + config = Json.gobject_deserialize(typeof(Config), root) as Config; + config.filename = filename; + if (config.features == null) + { + config.features = Profile.deserialize(new Json.Object()); + } + stream.close(); + Profile.profiles[ProfileType.CUSTOM] = config.features; + return config; + } + + public void save() throws Error + { + File file; + string home; + string buff; + string servers_path; + TextIter start; + TextIter end; + DataOutputStream stream; + Json.Node root; + Json.Generator gen; + + root = Json.gobject_serialize(this); + gen = new Json.Generator(); + gen.set_root(root); + gen.to_file(filename); + + servers.get_bounds(out start, out end); + buff = servers.get_text(start, end, false); + + home = Environment.get_variable("HOME"); + servers_path = Path.build_filename(home, ".minecraft-pi", "servers.txt"); + file = File.new_for_path(servers_path); + stream = new DataOutputStream(file.replace(null, false, FileCreateFlags.NONE)); + stream.put_string(buff, null); + return; + } + + public void set_env() + { + string name; + bool enabled; + StringBuilder builder; + + if (!modified) + { + return; + } + builder = new StringBuilder(); + for (int i = 0; i < Profile.features.length; i++) + { + name = Profile.features.index(i); + enabled = Profile.profiles[profile].get_data(name); + if (enabled) + { + builder.append_printf("%s|", name); + } + } + Environment.set_variable("GALLIUM_HUD", hud, true); + Environment.set_variable("MCPI_USERNAME", username, true); + Environment.set_variable("MCPI_FEATURE_FLAGS", builder.str, true); + Environment.set_variable("MCPI_RENDER_DISTANCE", distance_names[distance], true); + modified = false; + return; + } + + public Json.Node serialize_property(string name, Value val, ParamSpec spec) + { + Json.Node node; + + if (name != "features") + { + return default_serialize_property(name, val, spec); + } + + node = new Json.Node(Json.NodeType.OBJECT); + node.set_object(Profile.serialize(val.get_object())); + return node; + } + + public bool deserialize_property(string name, out Value val, ParamSpec spec, Json.Node node) + { + if (name != "features") + { + return default_deserialize_property(name, out val, spec, node); + } + + val = Value(typeof(Object)); + val.set_object(Profile.deserialize(node.get_object())); + return true; + } + } +} diff --git a/src/features.c b/src/features.c deleted file mode 100644 index 649994a..0000000 --- a/src/features.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * features.c - gMCPIL features tab - * - * Copyright 2021 Alvarito050506 - * - * 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. - * - */ - -#include -#include -#include -#include -#include - -#include -#include - -int featc; -char* features_envs[5] = {""}; -feature_t features[32]; - -static int get_features() -{ - int i = 0; - int sz = 0; - int offset = 0; - size_t buff_sz; - char* buff; - FILE* file; - - file = fopen("/opt/minecraft-pi-reborn-client/available-feature-flags", "r"); - if (file == NULL) - { - return -1; - } - - buff_sz = 48; - buff = (char*)malloc((int)buff_sz + 1); - buff[0] = 0x00; - while ((sz = getline(&buff, &buff_sz, file)) > 0) - { - FEAT_BOOL(i) = (void*)(intptr_t)(buff[0] == 'T'); - buff[sz - 1] = 0x00; - offset = FEAT_BOOL(i) == FALSE ? 6 : 5; - FEAT_PTR(i) = strdup(buff + offset); - i++; - } - free(buff); - fclose(file); - return i; -} - -static int set_feature_envs(int feat) -{ - int i = 0; - int sz[3] = {1, 1, 1}; - int len[3] = {0, 0, 0}; - int tmp[3] = {0, 0, 0}; - - while (i < 3) - { - if (i == 0 && FEAT_CMP(feat, "Touch GUI")) - { - i++; - continue; - } - if (i == 2 && (FEAT_CMP(feat, "Fancy Graphics") - || FEAT_CMP(feat, "Smooth Lighting") - || FEAT_CMP(feat, "Animated Water") - || FEAT_CMP(feat, "Disable gui_blocks Atlas"))) - { - i++; - continue; - } - if (FEAT_INT(feat) == TRUE || (i >= 2 && i <= 3 && FEAT_CMP(feat, "Force Mob Spawning"))) - { - len[i] = strlen(FEAT_STR(feat)); - tmp[i] = sz[i] + len[i] + 1; - features_envs[i + 1] = (char*)realloc((void*)features_envs[i + 1], tmp[i]); - if (sz[i] == 1) - { - strcpy(features_envs[i + 1], FEAT_STR(feat)); - } else - { - strcat(features_envs[i + 1], FEAT_STR(feat)); - } - features_envs[i + 1][tmp[i] - 2] = '|'; - features_envs[i + 1][tmp[i] - 1] = 0x00; - sz[i] = tmp[i]; - } - i++; - } - return 0; -} - -static feature_t* get_feature(char* str) -{ - int i = 0; - - while (i < featc) - { - if (FEAT_CMP(i, str)) - { - return &(features[i]); - } - i++; - } - return NULL; -} - -static void features_cb(__attribute__((unused)) GtkWidget* button, void* udata) -{ - int i = 0; - int sz = 1; - int len = 0; - int tmp = 0; - - if (features_envs[4] != NULL) - { - free(features_envs[4]); - } - features_envs[4] = (char*)malloc(1); - - while (i < featc) - { - if (FEAT_INT(i) == TRUE) - { - len = strlen(FEAT_STR(i)); - tmp = sz + len + 1; - features_envs[4] = (char*)realloc((void*)features_envs[4], tmp); - if (sz == 1) - { - strcpy(features_envs[4], FEAT_STR(i)); - } else - { - strcat(features_envs[4], FEAT_STR(i)); - } - features_envs[4][tmp - 2] = '|'; - features_envs[4][tmp - 1] = 0x00; - sz = tmp; - } - i++; - } - - if (udata == NULL) - { - gmcpil_config_set_features(config, features_envs[4]); - gmcpil_config_save(config); - } - return; -} - -static void toggle_cb(__attribute__((unused)) GtkWidget* check, void* udata) -{ - int i = (int)udata; - - FEAT_BOOL(i) = (void*)(intptr_t)(!FEAT_INT(i)); - return; -} - -TAB(Features, features_cb, { - int i = 0; - int last_profile; - int last_featc; - char* tmp; - char* features_buff; - GtkWidget* feature_check; - GtkWidget* scroll; - GtkWidget* vbox; - feature_t* feature; - - featc = 0; - featc = get_features(); - last_featc = gmcpil_config_get_last_featc(config); - last_profile = gmcpil_config_get_last_profile(config); - - features_envs[1] = (char*)malloc(1); - features_envs[2] = (char*)malloc(1); - features_envs[3] = (char*)malloc(1); - features_envs[4] = NULL; - while (i < featc) - { - set_feature_envs(i); - i++; - } - - features_buff = gmcpil_config_get_features(config); - if (features_buff != NULL) - { - i = 0; - while (i < last_featc) - { - FEAT_BOOL(i) = FALSE; - i++; - } - - i = 0; - tmp = strtok(features_buff, "|"); - while (tmp != NULL && i < last_featc) - { - feature = get_feature(tmp); - if (feature != NULL) - { - *feature[0] = (void*)TRUE; - } - tmp = strtok(NULL, "|"); - i++; - } - } else - { - printf("Yeah, no.\n"); - } - - scroll = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_NONE); - gtk_container_set_border_width(GTK_CONTAINER(scroll), 0); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_top(vbox, 6); - - i = 0; - while (i < featc) - { - feature_check = gtk_check_button_new_with_label(FEAT_STR(i)); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(feature_check), FEAT_INT(i)); - g_signal_connect(feature_check, "toggled", G_CALLBACK(toggle_cb), (void*)(intptr_t)i); - gtk_box_pack_start(GTK_BOX(vbox), feature_check, FALSE, FALSE, 0); - i++; - } - - features_cb(NULL, (void*)TRUE); - gmcpil_config_set_last_featc(config, featc); - gmcpil_config_set_features(config, features_envs[4]); - setenv("MCPI_FEATURE_FLAGS", features_envs[last_profile], 1); - gtk_container_add(GTK_CONTAINER(scroll), vbox); - gtk_box_pack_start(GTK_BOX(tab), scroll, TRUE, TRUE, 0); -}); diff --git a/src/features.vala b/src/features.vala new file mode 100644 index 0000000..a8e96c3 --- /dev/null +++ b/src/features.vala @@ -0,0 +1,55 @@ +using Gtk; + +namespace GMCPIL +{ + public class FeatureButton : Bin + { + private string feat_name; + private Config config; + private CheckButton button; + + public FeatureButton(Config config, string feat_name, bool feat_enabled) + { + Object(); + this.feat_name = feat_name; + this.config = config; + + button = new CheckButton.with_label(feat_name); + button.set_active(feat_enabled); + button.toggled.connect(toggled_cb); + add_with_properties(button, null); + } + + private void toggled_cb() + { + config.features.set_data(feat_name, button.get_active()); + config.modified = true; + } + } + + public void features_tab(Config config, Box tab) throws Error + { + string name; + bool enabled; + Box list_vbox; + FeatureButton button; + ScrolledWindow scroll; + + list_vbox = new Box(Orientation.VERTICAL, 0); + scroll = new ScrolledWindow(null, null); + scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC); + scroll.set_shadow_type(ShadowType.NONE); + scroll.set_border_width(0); + + for (int i = 0; i < Profile.features.length; i++) + { + name = Profile.features.index(i); + enabled = config.features.get_data(name); + button = new FeatureButton(config, name, enabled); + list_vbox.pack_start(button, false, false, 0); + } + + scroll.add(list_vbox); + tab.pack_start(scroll, true, true, 4); + } +} diff --git a/src/gmcpil.vapi b/src/gmcpil.vapi new file mode 100644 index 0000000..b748aaf --- /dev/null +++ b/src/gmcpil.vapi @@ -0,0 +1,5 @@ +[CCode (cheader_filename = "")] +namespace GMCPIL +{ + public const string VERSION; +} diff --git a/src/gui.vala b/src/gui.vala new file mode 100644 index 0000000..575a09d --- /dev/null +++ b/src/gui.vala @@ -0,0 +1,218 @@ +using Gtk; + +namespace GMCPIL +{ + public weak string REPO_URL = "https://github.com/MCPI-Revival/gMCPIL"; + public weak string COPYRIGHT = "Copyright 2021 MCPI-Revival contributors"; + public weak string DESCRIPTION = "Simple launcher for MCPI-Reborn - Vala/GTK+ Edition."; + public weak string DEFAULT_SERVERS = "thebrokenrail.com\npbptanarchy.tk\n"; + public weak string SERVERS_LABEL = "Each line is an ip:port pair. If the port is omitted, 19132 is used."; + + public delegate void TabDelegate(Config config, Box tab) throws Error; + + public string? read_file(string path) throws Error + { + int64 sz; + uint8[]? buff; + File file; + FileInfo info; + DataInputStream stream; + + file = File.new_for_path(path); + if (!file.query_exists()) + { + file.create(FileCreateFlags.NONE); + } + stream = new DataInputStream(file.read()); + info = file.query_info("*", FileQueryInfoFlags.NONE); + sz = info.get_size(); + buff = null; + if (sz > 0) + { + buff = new uint8[sz + 1]; + stream.read(buff); + buff[sz] = 0x00; + return (string)buff; + } + return null; + } + + public class Gui : Window + { + Box hbox; + Box vbox; + Box switcher_box; + Stack stack; + StackSwitcher switcher; + HeaderBar header; + Button launch_button; + Button about_button; + Config config; + + public Gui(Config config) + { + Object( + title: "gMCPIL", + default_width: -1, + default_width: 360, + icon_name: "gmcpil" + ); + + this.config = config; + + vbox = new Box(Orientation.VERTICAL, 0); + + hbox = new Box(Orientation.HORIZONTAL, 2); + launch_button = new Button.with_label("Launch"); + launch_button.set_margin_end(2); + launch_button.set_margin_bottom(2); + + stack = new Stack(); + switcher_box = new Box(Orientation.HORIZONTAL, 0); + switcher = new StackSwitcher(); + switcher.set_stack(stack); + + about_button = new Button.from_icon_name("help-about-symbolic", IconSize.LARGE_TOOLBAR); + + header = new HeaderBar(); + header.set_show_close_button(true); + header.set_custom_title(switcher_box); + + switcher_box.pack_start(switcher, true, false, 0); + switcher_box.pack_end(about_button, true, false, 2); + + hbox.pack_end(launch_button, false, false, 0); + + vbox.pack_start(stack, true, true, 0); + vbox.pack_start(hbox, false, false, 0); + + about_button.clicked.connect(about_cb); + launch_button.clicked.connect(launch_cb); + destroy.connect(() => { + try + { + config.save(); + } catch (Error err) + { + stderr.printf("Error: %s.\n", err.message); + } + Gtk.main_quit(); + }); + + set_titlebar(header); + header.set_decoration_layout(":close"); + add(vbox); + } + + void about_cb() + { + AboutDialog about_dialog; + + about_dialog = new AboutDialog(); + about_dialog.set_program_name("gMCPIL"); + about_dialog.set_logo_icon_name("gmcpil"); + about_dialog.set_version(VERSION); + about_dialog.set_website(REPO_URL); + about_dialog.set_copyright(COPYRIGHT); + about_dialog.set_comments(DESCRIPTION); + about_dialog.run(); + about_dialog.destroy(); + return; + } + + void launch_cb() + { + Pid pid; + string[] argv = {"minecraft-pi-reborn-client"}; + + config.set_env(); + + try + { + Process.spawn_async( + null, argv, null, + SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD, + null, out pid + ); + } catch (Error err) + { + stderr.printf("Error: %s.\n", err.message); + return; + } + + if (this.config.hide) + { + this.hide(); + } + + ChildWatch.add(pid, (pid, status) => { + if (this.config.hide) + { + this.show_all(); + } + Process.close_pid(pid); + }); + } + + public void add_tab(string name, TabDelegate code) throws Error + { + Box tab; + tab = new Box(Orientation.VERTICAL, 0); + code(config, tab); + stack.add_titled(tab, name, name); + return; + } + } +} + +public static int main(string[] args) +{ + bool ubuntu; + string home; + string path; + string os_release; + GMCPIL.Config config; + GMCPIL.Gui gui; + CssProvider provider; +#if BUSTER_COMPAT + try + { + os_release = GMCPIL.read_file("/etc/os-release"); + ubuntu = "NAME=\"Ubuntu\"\n" in os_release; + } catch (Error err) + { + ubuntu = false; + } +#else + ubuntu = Environment.get_os_info(OsInfoKey.NAME) == "Ubuntu"; +#endif + + Gtk.init(ref args); + if (ubuntu) + { + provider = CssProvider.get_named("Yaru", "dark"); + } else + { + provider = CssProvider.get_named("Adwaita", "dark"); + } + StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), provider, STYLE_PROVIDER_PRIORITY_USER); + try + { + home = Environment.get_variable("HOME"); + path = Path.build_filename(home, ".gmcpil.json"); + + GMCPIL.Profile.init("/opt/minecraft-pi-reborn-client/available-feature-flags"); + config = GMCPIL.Config.from_file(path); + gui = new GMCPIL.Gui(config); + gui.add_tab("Play", GMCPIL.play_tab); + gui.add_tab("Features", GMCPIL.features_tab); + gui.add_tab("Servers", GMCPIL.servers_tab); + gui.show_all(); + Gtk.main(); + } catch (Error err) + { + stderr.printf("Error: %s.\n", err.message); + return -1; + } + return 0; +} diff --git a/src/include/config.h b/src/include/config.h deleted file mode 100644 index 867d02f..0000000 --- a/src/include/config.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * config.h - * - * Copyright 2021 Alvarito050506 - * - * 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. - * - */ - -#ifndef CONFIG_H -#define CONFIG_H - -#include -#include - -G_BEGIN_DECLS - -#define GMCPIL_TYPE_CONFIG gmcpil_config_get_type() -#define GMCPIL_CONFIG(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, GMCPIL_TYPE_CONFIG, GMCPILConfig) -#define GMCPIL_IS_CONFIG(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, GMCPIL_TYPE_CONFIG) -#define GMCPIL_CONFIG_PRIVATE(obj) gmcpil_config_get_instance_private(obj) - -#define VALID_JSON_ARGS(dst, name, parent) \ - (parent.node != NULL || dst != NULL || name != NULL || JSON_NODE_HOLDS_OBJECT(parent.node) || parent.obj == NULL) -#define SAFE_ATOI(str) strtol(str ? str : "", NULL, 10) - -#define GMCPIL_GETTER(name) gchar* gmcpil_config_get_ ## name (GMCPILConfig* self) \ -{ \ - GMCPILConfigPrivate* private; \ - private = GMCPIL_CONFIG_PRIVATE(self); \ - return private->name; \ -} - -#define GMCPIL_SETTER(name) void gmcpil_config_set_ ## name (GMCPILConfig* self, const gchar* name) \ -{ \ - GMCPILConfigPrivate* private; \ - private = GMCPIL_CONFIG_PRIVATE(self); \ - private->name = g_strdup((gchar*)name); \ - return; \ -} - -#define GMCPIL_INT_GETTER(name) gint gmcpil_config_get_ ## name (GMCPILConfig* self) \ -{ \ - GMCPILConfigPrivate* private; \ - private = GMCPIL_CONFIG_PRIVATE(self); \ - return SAFE_ATOI(private->name); \ -} - -#define GMCPIL_INT_SETTER(name) void gmcpil_config_set_ ## name (GMCPILConfig* self, const gint name) \ -{ \ - char* tmp; \ - GMCPILConfigPrivate* private; \ - asprintf(&tmp, "%i", name); \ - private = GMCPIL_CONFIG_PRIVATE(self); \ - private->name = g_strdup((gchar*)tmp); \ - free(tmp); \ - return; \ -} - -#define GMCPIL_GETTER_SETTER(name) GMCPIL_GETTER(name); GMCPIL_SETTER(name); -#define GMCPIL_INT_GETTER_SETTER(name) GMCPIL_INT_GETTER(name); GMCPIL_INT_SETTER(name); - -#define GMCPIL_GLIB_PROPERTY(id, name, description, prop) \ - pspec = g_param_spec_string(id, name, description, NULL, G_PARAM_READWRITE); \ - g_object_class_install_property(gobject_class, prop, pspec); - -#define GMCPIL_SET_DEFAULT(name, value) \ - default_##name = gmcpil_config_get_##name(config); \ - if (default_##name == NULL) \ - { \ - default_##name = value; \ - gmcpil_config_set_##name(config, default_##name); \ - } - -typedef struct GMCPILConfigPrivate GMCPILConfigPrivate; - -typedef struct GMCPILConfig -{ - GObject parent; -} GMCPILConfig; - -typedef struct GMCPILConfigClass -{ - GObjectClass parent_class; -} GMCPILConfigClass; - -GType gmcpil_config_get_type() G_GNUC_CONST; - -GMCPILConfig* gmcpil_config_new(gchar* filename); - -void gmcpil_config_set_username(GMCPILConfig* self, const gchar* username); -void gmcpil_config_set_features(GMCPILConfig* self, const gchar* features); -void gmcpil_config_set_distance(GMCPILConfig* self, const gchar* distance); -void gmcpil_config_set_last_profile(GMCPILConfig* self, const gint last_profile); -void gmcpil_config_set_hud(GMCPILConfig* self, const gchar* hud); -void gmcpil_config_set_hide(GMCPILConfig* self, const gchar* hide); -void gmcpil_config_set_last_featc(GMCPILConfig* self, const gint last_featc); - -gchar* gmcpil_config_get_username(GMCPILConfig* self); -gchar* gmcpil_config_get_features(GMCPILConfig* self); -gchar* gmcpil_config_get_distance(GMCPILConfig* self); -gint gmcpil_config_get_last_profile(GMCPILConfig* self); -gchar* gmcpil_config_get_hud(GMCPILConfig* self); -gchar* gmcpil_config_get_hide(GMCPILConfig* self); -gint gmcpil_config_get_last_featc(GMCPILConfig* self); - -int gmcpil_config_save(GMCPILConfig* self); - -G_END_DECLS - -#endif /* CONFIG_H */ diff --git a/src/include/mcpil.h b/src/include/mcpil.h deleted file mode 100644 index 99d855f..0000000 --- a/src/include/mcpil.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * mcpil.h - gMCPIL main header - * - * Copyright 2021 Alvarito050506 - * - * 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. - * - */ - -#ifndef GMCPIL_H -#define GMCPIL_H - -#include -#include - -#define STR(str) #str - -#define FEAT_BOOL(i) (features[i][0]) -#define FEAT_INT(i) ((int)features[i][0]) -#define FEAT_PTR(i) (features[i][1]) -#define FEAT_STR(i) ((char*)features[i][1]) -#define FEAT_CMP(i, str) (strcmp(FEAT_STR(i), str) == 0) - -#define TAB(name, button_cb, code) GtkWidget* name ## _tab(GtkWidget* stack) \ -{ \ - void* cb_udata = NULL; \ - GtkWidget* tab = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); \ - GtkWidget* button = gtk_button_new_with_label("Save"); \ - GtkWidget* button_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2); \ - code; \ - gtk_box_pack_end(GTK_BOX(button_hbox), button, FALSE, FALSE, 0); \ - gtk_box_pack_end(GTK_BOX(tab), button_hbox, FALSE, FALSE, 0); \ - gtk_stack_add_titled(GTK_STACK(stack), tab, STR(name), STR(name)); \ - g_signal_connect(button, "clicked", G_CALLBACK(button_cb), cb_udata); \ - return tab; \ -} - -#define GMCPIL_REPO_URL "https://github.com/MCPI-Revival/gMCPIL" -#define GMCPIL_COPYRIGHT "Copyright 2021 MCPI-Revival contributors" -#define GMCPIL_DESCRIPTION "Simple launcher for MCPI-Reborn - GTK+ Edition." -#define DEFAULT_SERVERS "thebrokenrail.com\npbptanarchy.tk\n" -#define SERVERS_LABEL "External multiplayer is now built-in into MCPI-Reborn,\n" \ - "this is a just simple editor for the servers.txt file.\n" \ - "Each line is an ip:port tuple. If the port is omitted,\n" \ - "the default (19132) is used.\n" - -typedef void* feature_t[2]; - -typedef struct settings_box_t -{ - GtkEntry* username_entry; - GtkEntry* hud_entry; - GtkComboBoxText* distance_combo; - GtkComboBoxText* profile_combo; - GtkCheckButton* hide_check; - char* buff; -} settings_box_t; - -/* Global variables */ -extern int featc; -extern char* servers_path; -extern char* features_envs[5]; -extern settings_box_t settings_box; -extern feature_t features[32]; -extern GMCPILConfig* config; -extern GtkWidget* window; - -/* Tabs */ -GtkWidget* Play_tab(GtkWidget* notebook); -GtkWidget* Features_tab(GtkWidget* notebook); -GtkWidget* Servers_tab(GtkWidget* notebook); -GtkWidget* Settings_tab(GtkWidget* notebook); - -#endif /* MCPIL_H */ diff --git a/src/include/splashes.h b/src/include/splashes.h deleted file mode 100644 index 3d78702..0000000 --- a/src/include/splashes.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * splashes.h - MCPIL splash texts - * - * Copyright 2021 MCPI-Revival contributors - * Copyright 2021 Alvarito050506 - * - * 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. - * - */ - -#ifndef SPLASHES_H -#define SPLASHES_H - -#include - -extern char* splashes[41]; - -#ifdef DEFINE_SPLASHES -char* splashes[41] = { - "Sexy!", - "We Fixed The Rail!", - "Who Broke The Rail?", - "The World Of Notch!", - "WDYM Discontinued?", - "Oh, ok, Pigmen...", - "Check out the non-existant Far Lands!", - "mcpirevival.tk!", - "#alvarito-come-back", - "Classic!", - "Wow! Modded MCPI!", - "Now with fly-hacks!", - "Where Is My Pie?", - "I was promised pie!", - "@Banana", - "BANANA!", - "To \"Na\" Or Not To \"Na\", that is the question!", - "Not Minecraft Java!", - "Definitely not Minecraft Console!", - "Oh yeah, that version...", - "Join The Discord!", - "Segmentation fault (core dumped)", - "It's the Segment's Fault!", - "As seen on Discord!", - "Obfuscated!", - "As not seen on TV!", - "Why must you hurt me in this way?", - "Who is StevePi?", - "(Not) Made by Notch!", - "Open-Source!", - "FREE!", - "RIP MCPIL-Legacy, 2020-2020", - "StevePi = popbob confirmed?", - "Watch out for StevePi!", - "Didn't remove Herobrine!", - "Minceraft", - "MCPI-Docker", - "MCPI-Devs", - "RIP Picraft", - "Check out PBPT Anarchy!", - "Now without Docker!" -}; -#endif /* DEFINE_SPLASHES */ - -#endif /* SPLASHES_H */ diff --git a/src/mcpil.c b/src/mcpil.c deleted file mode 100644 index 7689403..0000000 --- a/src/mcpil.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * mcpil.c - MCPIL GTK+ Edition - * - * Copyright 2021 Alvarito050506 - * - * 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. - * - */ - -#define _GNU_SOURCE /* Required for asprintf */ -#define DEFINE_SPLASHES - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* Global variables */ -settings_box_t settings_box; -GMCPILConfig* config; -GtkWidget* window; - -void about_cb(__attribute__((unused)) GtkWidget* button, __attribute__((unused)) void* udata) -{ - GdkPixbuf* logo; - GtkWidget* about_dialog; - - logo = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmcpil", 64, GTK_ICON_LOOKUP_NO_SVG, NULL); - about_dialog = gtk_about_dialog_new(); - gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about_dialog), "gMCPIL"); - gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about_dialog), GMCPIL_VERSION); - gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about_dialog), logo); - gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about_dialog), GMCPIL_COPYRIGHT); - gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about_dialog), GMCPIL_REPO_URL); - gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about_dialog), GMCPIL_DESCRIPTION); - gtk_dialog_run(GTK_DIALOG(about_dialog)); - gtk_widget_destroy(about_dialog); - return; -} - -void activate_cb(GtkApplication* app, __attribute__((unused)) void* udata) -{ - GdkPixbuf* icon; - GtkWidget* stack; - GtkWidget* switcher; - GtkWidget* header; - GtkWidget* switcher_box; - GtkWidget* about_button; - - window = gtk_application_window_new(app); - gtk_window_set_title(GTK_WINDOW(window), "gMCPIL"); - gtk_window_set_default_size(GTK_WINDOW(window), -1, 375); - - icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmcpil", 32, GTK_ICON_LOOKUP_NO_SVG, NULL); - gtk_window_set_icon(GTK_WINDOW(window), icon); - - stack = gtk_stack_new(); - - switcher_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - switcher = gtk_stack_switcher_new(); - gtk_stack_switcher_set_stack(GTK_STACK_SWITCHER(switcher), GTK_STACK(stack)); - - about_button = gtk_button_new_from_icon_name("help-about-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR); - - header = gtk_header_bar_new(); - gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(header), TRUE); - gtk_header_bar_set_custom_title(GTK_HEADER_BAR(header), switcher_box); - - Play_tab(stack); - Features_tab(stack); - Servers_tab(stack); - - gtk_box_pack_start(GTK_BOX(switcher_box), switcher, TRUE, FALSE, 0); - gtk_box_pack_end(GTK_BOX(switcher_box), about_button, TRUE, FALSE, 2); - - g_signal_connect(about_button, "clicked", G_CALLBACK(about_cb), NULL); - - gtk_window_set_titlebar(GTK_WINDOW(window), header); - gtk_container_add(GTK_CONTAINER(window), stack); - gtk_widget_show_all(window); - return; -} - -int main(int argc, char* argv[]) -{ - int i = 0; - int rt = 0; - char* config_path; - GtkApplication* app; - - /* Initialize */ - srand(time(NULL)); - /* This is cursed, but it works:tm: */ - setenv("GTK_THEME", "Adwaita:dark", 1); - - asprintf(&config_path, "%s/.gmcpil.json", getenv("HOME")); - config = gmcpil_config_new(config_path); - free(config_path); - - gtk_init(&argc, &argv); - - app = gtk_application_new("tk.mcpirevival.gmcpil", G_APPLICATION_FLAGS_NONE); - - /* Signals */ - g_signal_connect(app, "activate", G_CALLBACK(activate_cb), NULL); - - rt = g_application_run(G_APPLICATION(app), argc, argv); - - /* Free memory and resources */ - g_object_unref(app); - free(features_envs[1]); - free(features_envs[2]); - free(features_envs[3]); - free(features_envs[4]); - while (i < featc) - { - free(FEAT_PTR(i)); - i++; - } - if (settings_box.buff != NULL) - { - free(settings_box.buff); - } - free(servers_path); - - gmcpil_config_save(config); - g_object_unref(config); - return rt; -} diff --git a/src/play.c b/src/play.c deleted file mode 100644 index 4a11d15..0000000 --- a/src/play.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * settings.c - gMCPIL settings tab - * - * Copyright 2021 Alvarito050506 - * - * 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. - * - */ - -#define _GNU_SOURCE /* Required for asprintf */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -char* distances[4] = {"Far", "Normal", "Short", "Tiny"}; -char* profile_names[5] = {"Classic MCPI", "Modded MCPI", "Modded MCPE", "Optimized MCPE", "Custom Profile"}; -char* profile_descriptions[5] = { - "Classic Minecraft Pi Edition (Not Recommended):\nAll optional features disabled.", - "Modded Minecraft Pi Edition:\nDefault MCPI-Reborn optional features without Touch GUI.", - "Modded Minecraft Pocket Edition (Recommended):\nDefault MCPI-Reborn optional features.", - "Optimized Minecraft Pocket Edition:\nDefault MCPI-Reborn features with lower quality graphics.", - "Custom Profile: Modify its settings in the Features tab." -}; - -static char* get_splash_text() -{ - return splashes[rand() % sizeof(splashes) / sizeof(char*)]; -} - -static int get_distance(char* str) -{ - switch (str[0]) - { - case 'F': - return 0; - break; - case 'N': - return 1; - break; - case 'S': - return 2; - break; - case 'T': - return 3; - break; - } - return -1; -} - -static void settings_cb(__attribute__((unused)) GtkWidget* button, __attribute__((unused)) void* udata) -{ - int profile; - const char* username; - const char* distance; - const char* hud; - gboolean hide; - GtkEntryBuffer* username_buff; - GtkEntryBuffer* hud_buff; - - username_buff = gtk_entry_get_buffer(GTK_ENTRY(settings_box.username_entry)); - hud_buff = gtk_entry_get_buffer(GTK_ENTRY(settings_box.hud_entry)); - - username = gtk_entry_buffer_get_text(username_buff); - hud = gtk_entry_buffer_get_text(hud_buff); - distance = gtk_combo_box_text_get_active_text(settings_box.distance_combo); - hide = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(settings_box.hide_check)); - - setenv("MCPI_USERNAME", username, 1); - setenv("MCPI_RENDER_DISTANCE", distance, 1); - setenv("GALLIUM_HUD", hud, 1); - - gmcpil_config_set_username(config, username); - gmcpil_config_set_hud(config, hud); - gmcpil_config_set_distance(config, distance); - if (hide) - { - gmcpil_config_set_hide(config, "TRUE"); - } else - { - gmcpil_config_set_hide(config, "FALSE"); - } - - profile = gtk_combo_box_get_active(GTK_COMBO_BOX(settings_box.profile_combo)); - setenv("MCPI_FEATURE_FLAGS", features_envs[profile], 1); - - gmcpil_config_set_last_profile(config, profile); - gmcpil_config_save(config); - return; -} - -static void watch_cb(GPid pid, __attribute__((unused)) int status, __attribute__((unused)) void* udata) -{ - gtk_widget_show_all(window); - g_spawn_close_pid(pid); - return; -} - -static void launch_cb(__attribute__((unused)) GtkWidget* button, __attribute__((unused)) void* udata) -{ - char* argv[] = {"minecraft-pi-reborn-client", NULL}; - GPid pid; - GError* err = NULL; - - settings_cb(NULL, NULL); - g_spawn_async(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &pid, &err); - - if (err != NULL) - { - g_error("Spawning child failed: %s", err->message); - return; - } - if (gmcpil_config_get_hide(config)[0] == 'T') - { - gtk_widget_hide(window); - } - g_child_watch_add(pid, watch_cb, NULL); - return; -} - -static void select_cb(GtkComboBox* combo, void* udata) -{ - int profile; - GtkLabel* description; - - description = GTK_LABEL(udata); - profile = gtk_combo_box_get_active(combo); - gtk_label_set_text(description, profile_descriptions[profile]); - return; -} - -TAB(Play, settings_cb, { - int i = 0; - int distance_int; - int last_profile; - char* default_username; - char* default_distance; - char* default_hud; - char* default_hide; - char* splash_text; - GtkWidget* username_hbox; - GtkWidget* username_label; - GtkWidget* username_entry; - GtkWidget* distance_hbox; - GtkWidget* distance_label; - GtkWidget* distance_combo; - GtkWidget* profile_hbox; - GtkWidget* profile_label; - GtkWidget* profile_combo; - GtkWidget* hud_hbox; - GtkWidget* hud_label; - GtkWidget* hud_entry; - GtkWidget* hide_hbox; - GtkWidget* hide_check; - GtkWidget* launch_button; - GtkWidget* splash; - GtkWidget* title; - GtkWidget* title_hbox; - GtkWidget* description; - - title_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - - title = gtk_label_new(NULL); - gtk_label_set_markup(GTK_LABEL(title), "Minecraft Pi Launcher"); - - splash = gtk_label_new(NULL); - asprintf(&splash_text, "%s\n", get_splash_text()); - gtk_label_set_markup(GTK_LABEL(splash), splash_text); - - GMCPIL_SET_DEFAULT(distance, "Short"); - GMCPIL_SET_DEFAULT(username, "StevePi"); - GMCPIL_SET_DEFAULT(hud, "simple,fps"); - GMCPIL_SET_DEFAULT(hide, "TRUE"); - - distance_int = get_distance(default_distance); - - username_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - username_label = gtk_label_new("Username"); - username_entry = gtk_entry_new_with_buffer(gtk_entry_buffer_new(default_username, strlen(default_username))); - gtk_widget_set_size_request(username_entry, 25 * 10, -1); - - hud_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - hud_label = gtk_label_new("Gallium HUD options"); - hud_entry = gtk_entry_new_with_buffer(gtk_entry_buffer_new(default_hud, strlen(default_hud))); - gtk_widget_set_size_request(hud_entry, 25 * 10, -1); - - distance_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - distance_label = gtk_label_new("Rendering distance"); - distance_combo = gtk_combo_box_text_new(); - while (i < 4) - { - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(distance_combo), distances[i]); - i++; - } - gtk_combo_box_set_active(GTK_COMBO_BOX(distance_combo), distance_int); - gtk_widget_set_size_request(distance_combo, 25 * 10, -1); - - i = 0; - profile_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - profile_label = gtk_label_new("Profile"); - profile_combo = gtk_combo_box_text_new(); - last_profile = gmcpil_config_get_last_profile(config); - while (i < 5) - { - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(profile_combo), profile_names[i]); - i++; - } - gtk_combo_box_set_active(GTK_COMBO_BOX(profile_combo), last_profile); - gtk_widget_set_size_request(profile_combo, 25 * 10, -1); - - hide_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - hide_check = gtk_check_button_new_with_label("Hide launcher"); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hide_check), default_hide[0] == 'T'); - gtk_widget_set_size_request(hide_check, -1, 32); // To match rest of input widgets - - description = gtk_label_new(profile_descriptions[last_profile]); - gtk_label_set_justify(GTK_LABEL(description), GTK_JUSTIFY_CENTER); - gtk_label_set_line_wrap(GTK_LABEL(description), TRUE); - - launch_button = gtk_button_new_with_label("Launch"); - - gtk_box_pack_start(GTK_BOX(title_hbox), title, TRUE, FALSE, 0); - - gtk_box_pack_start(GTK_BOX(tab), title_hbox, FALSE, FALSE, 4); - gtk_box_pack_start(GTK_BOX(tab), splash, FALSE, FALSE, 0); - - gtk_box_pack_start(GTK_BOX(username_hbox), username_label, FALSE, FALSE, 10); - gtk_box_pack_end(GTK_BOX(username_hbox), username_entry, FALSE, FALSE, 10); - - gtk_box_pack_start(GTK_BOX(hud_hbox), hud_label, FALSE, FALSE, 10); - gtk_box_pack_end(GTK_BOX(hud_hbox), hud_entry, FALSE, FALSE, 10); - - gtk_box_pack_start(GTK_BOX(distance_hbox), distance_label, FALSE, FALSE, 10); - gtk_box_pack_end(GTK_BOX(distance_hbox), distance_combo, FALSE, FALSE, 10); - - gtk_box_pack_start(GTK_BOX(profile_hbox), profile_label, FALSE, FALSE, 10); - gtk_box_pack_end(GTK_BOX(profile_hbox), profile_combo, FALSE, FALSE, 10); - - gtk_box_pack_end(GTK_BOX(hide_hbox), hide_check, FALSE, FALSE, 10); - - gtk_box_pack_start(GTK_BOX(tab), username_hbox, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(tab), hud_hbox, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(tab), distance_hbox, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(tab), profile_hbox, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(tab), hide_hbox, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(tab), description, FALSE, FALSE, 2); - - gtk_box_pack_end(GTK_BOX(button_hbox), launch_button, FALSE, FALSE, 0); - - settings_box.username_entry = GTK_ENTRY(username_entry); - settings_box.hud_entry = GTK_ENTRY(hud_entry); - settings_box.distance_combo = GTK_COMBO_BOX_TEXT(distance_combo); - settings_box.profile_combo = GTK_COMBO_BOX_TEXT(profile_combo); - settings_box.hide_check = GTK_CHECK_BUTTON(hide_check); - - g_signal_connect(launch_button, "clicked", G_CALLBACK(launch_cb), NULL); - g_signal_connect(profile_combo, "changed", G_CALLBACK(select_cb), (void*)description); - - setenv("MCPI_USERNAME", default_username, 1); - setenv("MCPI_RENDER_DISTANCE", distances[distance_int], 1); - setenv("GALLIUM_HUD", default_hud, 1); - free(splash_text); -}); diff --git a/src/play.vala b/src/play.vala new file mode 100644 index 0000000..88ef218 --- /dev/null +++ b/src/play.vala @@ -0,0 +1,167 @@ +using Gtk; + +namespace GMCPIL +{ + class SettingBox : Box + { + public SettingBox(string name, Widget widget) + { + Object(orientation: Orientation.HORIZONTAL, spacing: 0); + pack_start(new Label(name), false, false, 10); + pack_end(widget, false, false, 10); + } + } + + public string get_splash_text() + { + string[] splashes = { + "Sexy!", + "We Fixed The Rail!", + "Who Broke The Rail?", + "The World Of Notch!", + "WDYM Discontinued?", + "Oh, ok, Pigmen...", + "Check out the non-existant Far Lands!", + "mcpirevival.tk!", + "#alvarito-come-back", + "Classic!", + "Wow! Modded MCPI!", + "Now with fly-hacks!", + "Where Is My Pie?", + "I was promised pie!", + "@Banana", + "BANANA!", + "To \"Na\" Or Not To \"Na\", that is the question!", + "Not Minecraft Java!", + "Definitely not Minecraft Console!", + "Oh yeah, that version...", + "Join The Discord!", + "Segmentation fault (core dumped)", + "It's the Segment's Fault!", + "As seen on Discord!", + "Obfuscated!", + "As not seen on TV!", + "Why must you hurt me in this way?", + "Who is StevePi?", + "(Not) Made by Notch!", + "Open-Source!", + "FREE!", + "RIP MCPIL-Legacy, 2020-2020", + "StevePi = popbob confirmed?", + "Watch out for StevePi!", + "Didn't remove Herobrine!", + "Minceraft", + "MCPI-Docker", + "MCPI-Devs", + "RIP Picraft", + "Check out PBPT Anarchy!", + "Now without Docker!", + "Banana!", + "Fancy Vala" + }; + return splashes[Random.int_range(0, splashes.length - 1)]; + } + + public void play_tab(Config config, Box tab) throws Error + { + Box hide_hbox; + Box title_hbox; + Label title; + Label splash; + Label description; + Entry hud; + Entry username; + ComboBoxText profile; + ComboBoxText distance; + CheckButton hide; + string splash_text; + string[] profile_names = { + "Classic MCPI", + "Modded MCPI", + "Modded MCPE", + "Optimized MCPE", + "Custom Profile" + }; + string[] profile_descriptions = { + "Classic Minecraft Pi Edition (Not Recommended):\nAll optional features disabled.", + "Modded Minecraft Pi Edition:\nDefault MCPI-Reborn optional features without Touch GUI.", + "Modded Minecraft Pocket Edition (Recommended):\nDefault MCPI-Reborn optional features.", + "Optimized Minecraft Pocket Edition:\nDefault MCPI-Reborn features with lower quality graphics.", + "Custom Profile: Modify its settings in the Features tab." + }; + + splash_text = @"$(get_splash_text())\n"; + + title_hbox = new Box(Orientation.HORIZONTAL, 0); + + title = new Label(null); + title.set_markup("Minecraft Pi Launcher"); + + splash = new Label(null); + splash.set_markup(splash_text); + + username = new Entry(); + username.set_text(config.username); + username.set_size_request(25 * 10, -1); + + hud = new Entry(); + hud.set_text(config.hud); + hud.set_size_request(25 * 10, -1); + + distance = new ComboBoxText(); + for (Distance i = 0; i <= Distance.FAR; i += 1) + { + distance.append_text(Config.distance_names[i]); + } + distance.set_active(config.distance); + distance.set_size_request(25 * 10, -1); + + profile = new ComboBoxText(); + for (ProfileType i = 0; i <= ProfileType.CUSTOM; i += 1) + { + profile.append_text(profile_names[i]); + } + profile.set_active(config.profile); + profile.set_size_request(25 * 10, -1); + + hide_hbox = new Box(Orientation.HORIZONTAL, 0); + hide = new CheckButton.with_label("Hide launcher"); + hide.set_active(config.hide); + hide.set_size_request(-1, 32); /* To match other input widgets */ + + description = new Label(profile_descriptions[config.profile]); + description.set_justify(Justification.CENTER); + description.set_line_wrap(true); + + title_hbox.pack_start(title, true, false, 0); + + tab.pack_start(title_hbox, false, false, 4); + tab.pack_start(splash, false, false, 0); + + hide_hbox.pack_end(hide, false, false, 10); + + tab.pack_start(new SettingBox("Username", username), false, false, 2); + tab.pack_start(new SettingBox("Gallium HUD options", hud), false, false, 2); + tab.pack_start(new SettingBox("Distance", distance), false, false, 2); + tab.pack_start(new SettingBox("Profile", profile), false, false, 2); + tab.pack_start(hide_hbox, false, false, 2); + tab.pack_start(description, false, false, 2); + + username.changed.connect(() => { + config.username = username.get_text(); + }); + hud.changed.connect(() => { + config.hud = hud.get_text(); + }); + distance.changed.connect(() => { + config.distance = (Distance)distance.get_active(); + }); + profile.changed.connect(() => { + config.profile = (ProfileType)profile.get_active(); + description.set_text(profile_descriptions[config.profile]); + }); + hide.toggled.connect(() => { + config.hide = hide.get_active(); + }); + } +} diff --git a/src/profile.vala b/src/profile.vala new file mode 100644 index 0000000..fd906ae --- /dev/null +++ b/src/profile.vala @@ -0,0 +1,115 @@ +namespace GMCPIL +{ + public enum ProfileType + { + VANILLA, + MODDED, + MCPE, + OPTIMIZED, + CUSTOM + } + + public class Profile + { + public static Array features; + public static Object[] profiles; + static string[] optimized_disable = { + "Fancy Graphics", + "Smooth Lighting", + "Animated Water", + "Disable \"gui_blocks\" Atlas" + }; + + public static void init(string path) throws Error + { + File file; + bool enabled; + string line; + string[] tuple; + FileInputStream file_stream; + DataInputStream data_stream; + + features = new Array(); + profiles = new Object[5]; + + for (ProfileType i = 0; i < ProfileType.CUSTOM; i += 1) + { + profiles[i] = new Object(); + } + + file = File.new_for_path(path); + file_stream = file.read(); + data_stream = new DataInputStream(file_stream); + line = data_stream.read_line(); + while (line != null) + { + tuple = line.split(" ", 2); + enabled = tuple[0][0] == 'T'; + features.append_val(tuple[1]); + for (ProfileType i = 0; i < ProfileType.CUSTOM; i += 1) + { + switch (i) + { + case ProfileType.VANILLA: + continue; + case ProfileType.MODDED: + if (tuple[1] == "Touch GUI") + { + continue; + } + break; + case ProfileType.OPTIMIZED: + if (tuple[1] in optimized_disable) + { + continue; + } + break; + default: + break; + } + profiles[i].set_data(tuple[1], enabled); + } + line = data_stream.read_line(); + } + return; + } + + public static Json.Object serialize(Object obj) + { + string name; + bool enabled; + Json.Object tmp; + + tmp = new Json.Object(); + for (int i = 0; i < features.length; i++) + { + name = features.index(i); + enabled = obj.get_data(name); + tmp.set_boolean_member(name, enabled); + } + return tmp; + } + + public static Object deserialize(Json.Object obj) + { + string name; + bool enabled; + Object tmp; + + tmp = new Object(); + for (int i = 0; i < features.length; i++) + { + name = features.index(i); + if (obj.has_member(name)) + { + enabled = obj.get_boolean_member(name); + } else + { + enabled = profiles[ProfileType.MCPE].get_data(name); + } + tmp.set_data(name, enabled); + } + return tmp; + } + } +} diff --git a/src/servers.c b/src/servers.c deleted file mode 100644 index 958d6ec..0000000 --- a/src/servers.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * servers.c - gMCPIL servers tab - * - * Copyright 2021 Alvarito050506 - * - * 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. - * - */ - -#define _GNU_SOURCE /* Required for asprintf */ - -#include -#include -#include -#include -#include - -#include -#include - -char* servers_path; - -static void servers_cb(__attribute__((unused)) GtkWidget* button, void* udata) -{ - char* buff; - FILE* fd; - GtkTextView* view; - GtkTextBuffer* gtk_buff; - GtkTextIter start; - GtkTextIter end; - - fd = fopen(servers_path, "w+"); - if (fd == NULL) - { - fprintf(stderr, "Could not save servers file: %s.", strerror(errno)); - return; - } - view = (GtkTextView*)udata; - - gtk_buff = gtk_text_view_get_buffer(view); - gtk_text_buffer_get_start_iter(gtk_buff, &start); - gtk_text_buffer_get_end_iter(gtk_buff, &end); - buff = gtk_text_buffer_get_text(gtk_buff, &start, &end, FALSE); - - fwrite(buff, 1, strlen(buff), fd); - fclose(fd); - return; -} - -TAB(Servers, servers_cb, { - int sz = 0; - char* buff; - FILE* fd; - GtkWidget* label; - GtkWidget* scroll; - GtkWidget* view; - GtkTextBuffer* gtk_buff; - - buff = NULL; - asprintf(&servers_path, "%s/.minecraft-pi/servers.txt", getenv("HOME")); - - fd = fopen(servers_path, "r+"); - if (fd != NULL) - { - fseek(fd, 0, SEEK_END); - sz = ftell(fd); - fseek(fd, 0, SEEK_SET); - buff = (char*)malloc(sz + 1); - fread((void*)buff, 1, sz, fd); - buff[sz] = 0x00; - fclose(fd); - } - - label = gtk_label_new(SERVERS_LABEL); - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); - gtk_widget_set_margin_top(label, 6); - - scroll = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_ETCHED_IN); - gtk_container_set_border_width(GTK_CONTAINER(scroll), 5); - - gtk_buff = gtk_text_buffer_new(NULL); - - if (buff != NULL) - { - gtk_text_buffer_set_text(gtk_buff, buff, -1); - } else - { - gtk_text_buffer_set_text(gtk_buff, DEFAULT_SERVERS, -1); - } - - view = gtk_text_view_new_with_buffer(gtk_buff); - gtk_text_view_set_editable(GTK_TEXT_VIEW(view), TRUE); - gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(view), TRUE); - gtk_container_add(GTK_CONTAINER(scroll), view); - - gtk_box_pack_start(GTK_BOX(tab), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(tab), scroll, TRUE, TRUE, 0); - cb_udata = (void*)view; - free(buff); -}); diff --git a/src/servers.vala b/src/servers.vala new file mode 100644 index 0000000..ac60460 --- /dev/null +++ b/src/servers.vala @@ -0,0 +1,49 @@ +using Gtk; + +namespace GMCPIL +{ + public void servers_tab(Config config, Box tab) throws Error + { + string? buff; + string home; + string filename; + string dirname; + File dir; + Label label; + TextView view; + ScrolledWindow scroll; + + home = Environment.get_variable("HOME"); + dirname = Path.build_filename(home, ".minecraft-pi"); + filename = Path.build_filename(dirname, "servers.txt"); + + label = new Label(SERVERS_LABEL); + label.set_line_wrap(true); + label.set_justify(Justification.CENTER); + label.set_margin_top(6); + + scroll = new ScrolledWindow(null, null); + scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC); + scroll.set_shadow_type(ShadowType.NONE); + scroll.set_border_width(5); + + dir = File.new_for_path(dirname); + if (!dir.query_exists()) + { + dir.make_directory(null); + } + + buff = read_file(filename); + + config.servers = new TextBuffer(null); + config.servers.set_text(buff != null ? buff : DEFAULT_SERVERS); + + view = new TextView.with_buffer(config.servers); + view.set_editable(true); + view.set_cursor_visible(true); + + scroll.add(view); + tab.pack_start(label, false, false, 0); + tab.pack_start(scroll, true, true, 0); + } +}