{"id":29846,"date":"2019-10-31T21:32:19","date_gmt":"2019-10-31T18:32:19","guid":{"rendered":"https:\/\/prohoster.info\/blog\/igra-na-rust-za-24-chasa-lichnyj-opyt-razrabotki\/"},"modified":"2019-10-31T21:32:19","modified_gmt":"2019-10-31T18:32:19","slug":"igra-na-rust-za-24-chasa-lichnyj-opyt-razrabotki","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/igra-na-rust-za-24-chasa-lichnyj-opyt-razrabotki","title":{"rendered":"Developing a Game in Rust in 24 Hours: Personal Experience","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Developing a Game in Rust in 24 Hours: Personal Experience\" src=\"\/wp-content\/uploads\/2019\/03\/ea25406c43ac90ce2e33e290168d1083.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn this article, I will share my personal experience of developing a small game in Rust. It took about 24 hours to create a working version (mainly, I worked in the evenings or on weekends). The game is still far from finished, but I believe the experience will be useful. I will discuss what I learned and some observations made while building the game from scratch.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<blockquote><p><b>Skillbox recommends:<\/b> Two-Year Practical Course <noindex><a rel=\"nofollow\" href=\"https:\/\/iamwebdev.skillbox.ru\/?utm_source=skillbox.media&amp;utm_medium=habr.com&amp;utm_campaign=WEBDEVPRO&amp;utm_content=articles&amp;utm_term=rust24\">I am a PRO web developer<\/a><\/noindex>.<\/p>\n<p><b>Reminder:<\/b> <i>for all readers of 'Habr' - a discount of 10,000 rubles when enrolling in any Skillbox course with the promo code 'Habr'.<\/i><\/p><\/blockquote>\n<p><\/p>\n<h3>Why Rust?<\/h3>\n<p>\nI chose this language because I had heard a lot of good things about it and see it becoming increasingly popular in game development. Before writing the game, I had a little experience with developing simple applications in Rust. That was just enough to feel a certain freedom while creating the game.<\/p>\n<h3>Why a game and what kind of game?<\/h3>\n<p>\nCreating games is fun! I wish there were more reasons, but for 'home' projects, I choose topics that are not too closely related to my usual work. What kind of game? I wanted to create something like a tennis simulator, combining Cities Skylines, Zoo Tycoon, Prison Architect, and of course tennis. In general, it turned out to be a game about a tennis academy where people come to play.<\/p>\n<h3>Technical Preparation<\/h3>\n<p>\nI wanted to use Rust, but I wasn't sure how 'from scratch' I would need to start working. I didn\u2019t want to write pixel shaders and use drag-and-drop, so I was looking for the most flexible solutions.<\/p>\n<p>I found some helpful resources that I\u2019d like to share with you:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/arewegameyet.com\/\">Are we game yet<\/a><\/noindex> \u2014 a list of necessary Rust elements for game development;<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.reddit.com\/r\/rust_gamedev\">Rust game dev subreddit;<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/kenney.nl\">Free pixel art.<\/a><\/noindex><\/li>\n<\/ul>\n<p>\nI explored several Rust game engines, ultimately choosing Piston and ggez. I had encountered them while working on a previous project. In the end, I chose ggez because it seemed more suitable for developing a small 2D game. The modular structure of Piston is too complicated for a beginner developer (or someone new to Rust).<\/p>\n<h3>Game Structure<\/h3>\n<p>\nI spent some time thinking about the project's architecture. The first step is to create the 'land', people, and tennis courts. People should move around the courts and wait. Players should have skills that develop over time. Additionally, there should be an editor that allows adding new people and courts, but that won\u2019t be free.<\/p>\n<p>After considering everything, I got to work. <\/p>\n<h3>Creating a Game<\/h3>\n<p>\n<b>Beginning: Circles and Abstractions<\/b><\/p>\n<p>I took an example from ggez and got a circle on the screen. Amazing! Now, a bit about abstractions. I thought it would be good to abstract from the idea of a game object. Each object should be rendered and updated as specified here:<\/p>\n<pre><code class=\"rust\">\/\/ the game object trait\ntrait GameObject {\n    fn update(&amp;mut self, _ctx: &amp;mut Context) -&gt; GameResult&lt;()&gt;;\n    fn draw(&amp;mut self, ctx: &amp;mut Context) -&gt; GameResult&lt;()&gt;;\n}\n \n\/\/ a specific game object - Circle\nstruct Circle {\n    position: Point2,\n}\n \n impl Circle {\n    fn new(position: Point2) -&gt; Circle {\n        Circle { position }\n    }\n}\nimpl GameObject for Circle {\n    fn update(&amp;mut self, _ctx: &amp;mut Context) -&gt; GameResult&lt;()&gt; {\n        Ok(())\n    }\n    fn draw(&amp;mut self, ctx: &amp;mut Context) -&gt; GameResult&lt;()&gt; {\n        let circle =\n            graphics::Mesh::new_circle(ctx, graphics::DrawMode::Fill, self.position, 100.0, 2.0)?;\n \n         graphics::draw(ctx, &amp;circle, na::Point2::new(0.0, 0.0), 0.0)?;\n        Ok(())\n    }\n}<\/code><\/pre>\n<p>\nThis piece of code allowed me to get a great list of objects that I can update and render in a no less great loop.<\/p>\n<pre><code class=\"rust\">mpl event::EventHandler for MainState {\n    fn update(&amp;mut self, context: &amp;mut Context) -&gt; GameResult {\n        \/\/ Update all objects\n        for object in self.objects.iter_mut() {\n            object.update(context)?;\n        }\n\n        Ok(())\n    }\n\n    fn draw(&amp;mut self, context: &amp;mut Context) -&gt; GameResult {\n        graphics::clear(context);\n\n        \/\/ Draw all objects\n        for object in self.objects.iter_mut() {\n            object.draw(context)?;\n        }\n\n        graphics::present(context);\n\n        Ok(())\n    }\n}<\/code><\/pre>\n<p>\nmain.rs is necessary because it contains all the lines of code. I spent some time dividing files and optimizing the directory structure. Here\u2019s what it all looked like afterward:<br \/>\n<i>resources -&gt; this is where all the assets are (images)<br \/>\nsrc<br \/>\n \u2014 entities<br \/>\n \u2014 game_object.rs<br \/>\n \u2014 circle.rs<br \/>\n \u2014 main.rs -&gt; main loop<\/i><\/p>\n<p><b>People, Courts, and Images<\/b><\/p>\n<p>The next step is creating a game object Person and loading images. Everything should be built on the basis of tiles sized 32*32.<\/p>\n<p><img decoding=\"async\" alt=\"Developing a Game in Rust in 24 Hours: Personal Experience\" src=\"\/wp-content\/uploads\/2019\/03\/265ed79e6784ef0180cfdc5aa8d96a4c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\n<b>Tennis Courts<\/b><\/p>\n<p>After studying what tennis courts look like, I decided to make them from 4*2 tiles. Initially, it was possible to create an image of that size or compose it from 8 separate tiles. But then I realized that only two unique tiles were needed, and here's why.<\/p>\n<p>We have just two such tiles: 1 and 2.<\/p>\n<p>Each section of the court consists of tile 1 or tile 2. They can be placed normally or flipped 180 degrees.<\/p>\n<p><img decoding=\"async\" alt=\"Developing a Game in Rust in 24 Hours: Personal Experience\" src=\"\/wp-content\/uploads\/2019\/03\/90d07caea0dee8673ada5d44963ab347.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\n<b>Basic Building (Assembly) Mode<\/b><\/p>\n<p>After achieving rendering of courts, people, and maps, I understood that a basic assembly mode was also necessary. I implemented it so that when a button is pressed, an object is selected, and a click places it in the desired location. So, button 1 allows you to select a court, while button 2 allows you to select a player.<\/p>\n<p>But we also need to remember what 1 and 2 mean, so I added a wireframe to show which object is selected. Here\u2019s what it looks like.<\/p>\n<p><img decoding=\"async\" alt=\"Developing a Game in Rust in 24 Hours: Personal Experience\" src=\"\/wp-content\/uploads\/2019\/03\/09b92828fb9b8d4bfa5d5178ca99613c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\n<b>Questions about Architecture and Refactoring<\/b><\/p>\n<p>Now I have several game objects: people, courts, and floors. However, for the wireframes to work, each object entity needs to know whether the objects themselves are in demonstration mode or just drawn as a frame. This is not very convenient.<\/p>\n<p>I felt that it was necessary to rethink the architecture to reveal certain limitations:<\/p>\n<ul>\n<li>having an entity that displays and updates itself is a problem, since this entity will not be able to 'know' what it should render \u2014 an image or a wireframe;<\/li>\n<li>the lack of a tool for exchanging properties and behavior between discrete entities (for example, a property like is_build_mode or rendering behavior). Inheritance could be used, although there is no proper way to implement it in Rust. What I really needed was composition;<\/li>\n<li>a tool for interaction between entities was needed to assign people to courts;<\/li>\n<li>the entities themselves represented a mix of data and logic, which quickly got out of control.<\/li>\n<\/ul>\n<p><\/p>\n<blockquote><p><i>I conducted further research and discovered the architecture <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity_component_system\">ECS \u2014 Entity Component System<\/a><\/noindex>, which is commonly used in games. Here are the advantages of ECS:<\/p>\n<ul>\n<li>data is separate from logic;<\/li>\n<li>composition instead of inheritance;<\/li>\n<li>data-oriented architecture.<\/li>\n<\/ul>\n<p><\/i><\/p><\/blockquote>\n<p>\nThree basic concepts characterize ECS:<\/p>\n<ul>\n<li>entities \u2014 a type of object referenced by an identifier (this could be a player, a ball, or something else);<\/li>\n<li>components \u2014 these make up entities. For example, rendering and positioning components, among others. They are data storage;<\/li>\n<li>systems \u2014 they use both objects and components and contain behaviors and logic based on this data. For example, a rendering system that iterates through all entities with rendering components and handles rendering.<\/li>\n<\/ul>\n<p>\nAfter studying it became clear that ECS solves such problems:<\/p>\n<ul>\n<li>adopting composition instead of inheritance for the systemic organization of entities; <\/li>\n<li>elimination of code clutter through management systems; <\/li>\n<li>using methods like is_build_mode to keep the wireframe logic in one place \u2014 within the rendering system.<\/li>\n<\/ul>\n<p>\nHere's what resulted after implementing ECS.<\/p>\n<p><i>resources -&gt; this is where all the assets are (images)<br \/>\nsrc<br \/>\n \u2014 components<br \/>\n \u2014 position.rs<br \/>\n \u2014 person.rs<br \/>\n \u2014 tennis_court.rs<br \/>\n \u2014 floor.rs<br \/>\n \u2014 wireframe.rs<br \/>\n \u2014 mouse_tracked.rs<br \/>\n \u2014 resources<br \/>\n \u2014 mouse.rs<br \/>\n \u2014 systems<br \/>\n \u2014 rendering.rs<br \/>\n \u2014 constants.rs<br \/>\n \u2014 utils.rs<br \/>\n \u2014 world_factory.rs -&gt; world factory functions<br \/>\n \u2014 main.rs -&gt; main loop<\/i><\/p>\n<h3>Assigning people to the courts<\/h3>\n<p>\nECS made life easier. Now I had a systematic way to add data to entities and incorporate logic based on that data. This, in turn, allowed for the organization of people across the courts.<\/p>\n<p>What I did:<\/p>\n<ul>\n<li>added data about assigned courts to Person;<\/li>\n<li>added data about distributed people to TennisCourt;<\/li>\n<li>added CourtChoosingSystem, which allows analyzing people and venues, detecting available courts, and allocating players to them;<\/li>\n<li>added the PersonMovementSystem, which searches for people assigned to courts, and if they are not there, sends them where needed.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Developing a Game in Rust in 24 Hours: Personal Experience\" src=\"\/wp-content\/uploads\/2019\/03\/f2e4632de2cb9d1c3ec7c9d9310b8170.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <\/p>\n<h3>Summing up<\/h3>\n<p>\nI really enjoyed working on this simple game. Moreover, I\u2019m glad I used Rust to write it because:<\/p>\n<ul>\n<li>Rust gives you what you need;<\/li>\n<li>it has great documentation, Rust is quite elegant;<\/li>\n<li>immutability is awesome;<\/li>\n<li>there's no need to resort to cloning, copying, or similar actions, which I often did in C++;<\/li>\n<li>Options are very convenient to work with, and they handle errors very well;<\/li>\n<li>if the project compiles, then in 99% of cases it works exactly as it should. Compiler error messages are, I believe, the best I've seen.<\/li>\n<\/ul>\n<p>\nGame development in Rust is just getting started. But there is already a stable and fairly large community working to open Rust up for everyone. Therefore, I look at the future of the language with optimism, eagerly anticipating the results of our collective efforts.<\/p>\n<blockquote><p><b>Skillbox recommends:<\/b><\/p>\n<ul>\n<li>Online Course <noindex><a rel=\"nofollow\" href=\"https:\/\/skillbox.ru\/frontend-developer\/?utm_source=skillbox.media&amp;utm_medium=habr.com&amp;utm_campaign=FRENDEV&amp;utm_content=articles&amp;utm_term=rust24\">\"Frontend Developer Profession\"<\/a><\/noindex>.<\/li>\n<li>Practical Course <noindex><a rel=\"nofollow\" href=\"https:\/\/skillbox.ru\/agima\/?utm_source=skillbox.media&amp;utm_medium=habr.com&amp;utm_campaign=AGIMA&amp;utm_content=articles&amp;utm_term=rust24\">\"Mobile Developer PRO\"<\/a><\/noindex>.<\/li>\n<li>Practical Year Course <noindex><a rel=\"nofollow\" href=\"https:\/\/skillbox.ru\/php\/?utm_source=skillbox.media&amp;utm_medium=habr.com&amp;utm_campaign=PHPDEV&amp;utm_content=articles&amp;utm_term=rust24\">\"PHP Developer from 0 to PRO\"<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>\n<\/p><\/blockquote>\n<p>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/skillbox\/blog\/444364\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u043b\u0438\u0447\u043d\u043e\u043c \u043e\u043f\u044b\u0442\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438\u0433\u0440\u044b \u043d\u0430 Rust. \u041d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0443\u0448\u043b\u043e \u043e\u043a\u043e\u043b\u043e 24 \u0447\u0430\u0441\u043e\u0432 (\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u043f\u043e \u0432\u0435\u0447\u0435\u0440\u0430\u043c \u0438\u043b\u0438 \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0445). \u0418\u0433\u0440\u0430 \u0435\u0449\u0435 \u0434\u0430\u043b\u0435\u043a\u0430 \u043e\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f, \u043d\u043e \u044f \u0434\u0443\u043c\u0430\u044e, \u0447\u0442\u043e \u043e\u043f\u044b\u0442 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c. \u042f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u0447\u0435\u043c\u0443 \u043d\u0430\u0443\u0447\u0438\u043b\u0430\u0441\u044c, \u0438 \u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f\u0445, \u0441\u0434\u0435\u043b\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 \u0438\u0433\u0440\u044b \u0441 \u043d\u0443\u043b\u044f. [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-29846","post","type-post","status-publish","format-standard","hentry"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u043b\u0438\u0447\u043d\u043e\u043c \u043e\u043f\u044b\u0442\u0435.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/igra-na-rust-za-24-chasa-lichnyj-opyt-razrabotki\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0418\u0433\u0440\u0430 \u043d\u0430 Rust \u0437\u0430 24 \u0447\u0430\u0441\u0430: \u043b\u0438\u0447\u043d\u044b\u0439 \u043e\u043f\u044b\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u043b\u0438\u0447\u043d\u043e\u043c \u043e\u043f\u044b\u0442\u0435.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/igra-na-rust-za-24-chasa-lichnyj-opyt-razrabotki\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:32:19+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:32:19+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Game in Rust in 24 hours: personal development experience | ProHoster","description":"In this article, I will share my personal experience.","canonical_url":"https:\/\/prohoster.info\/en\/blog\/igra-na-rust-za-24-chasa-lichnyj-opyt-razrabotki","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0418\u0433\u0440\u0430 \u043d\u0430 Rust \u0437\u0430 24 \u0447\u0430\u0441\u0430: \u043b\u0438\u0447\u043d\u044b\u0439 \u043e\u043f\u044b\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 | ProHoster","og:description":"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u043b\u0438\u0447\u043d\u043e\u043c \u043e\u043f\u044b\u0442\u0435.","og:url":"https:\/\/prohoster.info\/en\/blog\/igra-na-rust-za-24-chasa-lichnyj-opyt-razrabotki","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:32:19+00:00","article:modified_time":"2019-10-31T18:32:19+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"29846","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"Article","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-20 22:43:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 03:47:36","updated":"2026-01-20 22:43:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/29846","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=29846"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/29846\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=29846"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=29846"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=29846"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}