-
Notifications
You must be signed in to change notification settings - Fork 0
/
feed.json
391 lines (391 loc) · 191 KB
/
feed.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
{
"version": "https://jsonfeed.org/version/1",
"title": "Csharp and Game Development Notes",
"description": "",
"home_page_url": "https://pilvimaa.fi",
"feed_url": "https://pilvimaa.fi/feed.json",
"user_comment": "",
"icon": "https://pilvimaa.fi/media/website/Hedgehog.png",
"author": {
"name": "Pilvinen"
},
"items": [
{
"id": "https://pilvimaa.fi/localizing-godots-default-splash-screen/",
"url": "https://pilvimaa.fi/localizing-godots-default-splash-screen/",
"title": "Localizing Godot's default Splash Screen",
"summary": "Getting Godot’s default static splash screen localized is a nightmare. One might assume it’s as easy as 1, 2, ,3, just set a remap for it and you’re done, but…",
"content_html": "<p>Getting Godot’s default static splash screen localized is a nightmare. One might assume it’s as easy as 1, 2, ,3, just set a remap for it and you’re done, but oh no, of course it isn’t supported.</p><p>Furthermore, because all the user space code loads only after the splash screen has already been shown, it complicates things.</p><p>And to make the matters even worse, of course any runtime changes to <code>ProjectSettings</code> are not persistent, so you can’t just set a new path for the boot splash when the locale changes.</p><p>However, there is a way.</p><h2 id=\"project-settings\">Project Settings</h2>\n<p>In the Godot Editor under <code>Project Settings > General > Application > Boot Splash</code></p><ol>\n<li>Set <code>Show Image</code> to <code>true</code>.</li>\n<li>Set <code>Image</code> to your default image.</li>\n</ol>\n<p>Under <code>Project Settings > General > Application > Config</code> set <code>Project Settings Override</code> to <code>override.cfg</code>.</p><h2 id=\"writing-to-overridecfg\">Writing to override.cfg</h2>\n<p>When your locale changes, call:</p><pre><code class=\"language-cs\">// Set the splash image to graphics localized to Finnish.\nProjectSettings.SetSetting("application/boot_splash/image", "user://path/to/my/localized/splash_fi.png");\n\n// Save the changed setting to override.cfg.\nProjectSettings.SaveCustom("override.cfg");\n</code></pre>\n<p>This special <code>override.cfg</code> file will be created in the folder where your game’s executable resides. It will be loaded via the project settings as defined above.</p><h2 id=\"setting-the--splashes-in-user\">Setting the splashes in user://</h2>\n<p>Trying to use the splashes from <code>res://</code> resulted in an utter failure for me. The solution was copying the images to <code>user://</code>. Of course you can’t just copy them, that would be too simple. But we can write the image files.</p><p>You can do this how ever you like, here’s what I did:</p><pre><code class=\"language-cs\">private static void TryToCopySplashImagesToUserFolder() { \n \n // Copy the splash screen images to the user folder if they don't exist there. \n string splashScreenFolderPath = Paths.GetSplashScreenFolderPath(); \n string splashScreenFolderFullPathFi = Path.Combine(splashScreenFolderPath, "ProphetOfTheLonelyStar_fi.png"); \n string splashScreenFolderFullPathEn = Path.Combine(splashScreenFolderPath, "ProphetOfTheLonelyStar_en.png"); \n \n // Check if the folder exists. \n if (!Directory.Exists(splashScreenFolderPath)) { \n Directory.CreateDirectory(splashScreenFolderPath); \n } \n \n // Write splash screens to user folder. \n \n // English splash screen. if (!File.Exists(splashScreenFolderFullPathEn)) { \n string fileNameEn = "ProphetOfTheLonelyStar_en.png"; \n string imageFilePathEn = $"res://Textures/SplashScreen/{fileNameEn}"; \n string writeFilePathEn = Path.Combine(Paths.GetSplashScreenFolderPath(), fileNameEn); \n Texture2D imageEn = GD.Load<Texture2D>(imageFilePathEn); \n if (!File.Exists(writeFilePathEn)) { \n // Write the imageEn to the destination file. \n try { \n imageEn.GetImage().SavePng(writeFilePathEn); \n } catch (Exception e) { \n Console.WriteLine($"Splash screen image file could not be written: {writeFilePathEn}"); \n Console.WriteLine(e); \n } \n } \n } \n \n // Finnish splash screen. \n if (!File.Exists(splashScreenFolderFullPathFi)) { \n string fileNameFi = "ProphetOfTheLonelyStar_fi.png"; \n string imageFilePathFi = $"res://Textures/SplashScreen/{fileNameFi}"; \n string writeFilePathFi = Path.Combine(Paths.GetSplashScreenFolderPath(), fileNameFi); \n Texture2D imageFi = GD.Load<Texture2D>(imageFilePathFi); \n if (!File.Exists(writeFilePathFi)) { \n // Write the imageFi to the destination file. \n try { \n imageFi.GetImage().SavePng(writeFilePathFi); \n } catch (Exception e) { \n Console.WriteLine($"Splash screen image file could not be written: {writeFilePathFi}"); \n Console.WriteLine(e); \n } \n } \n } \n}\n</code></pre>\n<p>These were the main points. Fill in the blanks for your own project and you should be good to go.</p>",
"image": "https://pilvimaa.fi/media/posts/21/ProphetOfTheLonelyStar_fi.png",
"author": {
"name": "Pilvinen"
},
"tags": [
],
"date_published": "2024-09-29T15:51:50+03:00",
"date_modified": "2024-09-29T15:51:50+03:00"
},
{
"id": "https://pilvimaa.fi/game-structure-and-software-architecture/",
"url": "https://pilvimaa.fi/game-structure-and-software-architecture/",
"title": "Game Structure and Software Architecture",
"summary": "This is a straightforward simple memo on what all game structure should be like, in the most general sense. It’s for me. It’s not for you. It hasn’t been checked…",
"content_html": "<p>This is a straightforward simple memo on what all game structure should be like, in the most general sense. It’s for me. It’s not for you. It hasn’t been checked very thoroughly and might contain errors, even big ones, especially the parts generated with the help of generative AI.</p><h2 id=\"project-structure\">Project Structure</h2>\n<h3 id=\"parent-to-child-dependencies\">Parent-to-Child Dependencies</h3>\n<p>All the dependencies should be designed to be accessed from parent to child.\nBy ensuring that parents handle dependencies, you avoid issues where children or siblings aren’t fully initialized.\nThis also keeps objects modular, so each is only responsible for its own scope.\nDo not depend from child to parent. The parent isn’t loaded yet when the child is ready.\nDo not depend on siblings. They might or might not be there. Let the parent handle it.\nThings should be self contained. Objects should be responsible for simple things which the parent manages.</p><h3 id=\"separation-of-logic-and-data\">Separation of Logic and Data</h3>\n<p>Separate logic from data.\nIt is always a good idea to split behavior from data models, ensuring a clean and maintainable codebase.</p><h2 id=\"saving-state\">Saving State</h2>\n<p>EF Core with SQLite should be used for object relational mapping. All state saving and loading should be handled by EF Core. Standard practices should be used for organizing the state objects.</p><p>EF Core (Entity Framework Core) is an Object-Relational Mapper (ORM), which means it translates between your C# classes and database tables. It handles CRUD (Create, Read, Update, Delete) operations for you, but requires a few key elements:</p><ul>\n<li><strong>DbContext:</strong> The class responsible for managing database connections and mapping entities (your C# objects) to tables in your database.</li>\n<li><strong>Entities:</strong> The C# classes that represent your database tables.</li>\n<li><strong>Migrations:</strong> EF Core’s way of managing changes to your database schema.</li>\n</ul>\n<h3 id=\"defining-your-dbcontext\">Defining Your DbContext</h3>\n<p>The <code>DbContext</code> class is where you configure your connection to the database and define which entities will be tracked.</p><p>Here’s a minimal example of a <code>DbContext</code>:</p><pre><code class=\"language-cs\">public class GameDbContext : DbContext {\n\n // Define DbSet properties for each entity (table) in your database\n public DbSet<Player> Players { get; set; }\n public DbSet<InventoryItem> InventoryItems { get; set; }\n\n protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {\n // Configure EF Core to use SQLite\n optionsBuilder.UseSqlite("Data Source=game.db");\n }\n}\n</code></pre>\n<p>This <code>GameDbContext</code> class will automatically map your <code>Player</code> and <code>InventoryItem</code> entities to tables in an SQLite database (<code>game.db</code>).</p><h3 id=\"defining-entities\">Defining Entities</h3>\n<p>Entities are C# classes that represent rows in your database tables. Each property corresponds to a column in the table.</p><p>For example, here’s a <code>Player</code> entity:</p><pre><code class=\"language-cs\">public class Player {\n public int Id { get; set; } // Primary key\n public string Name { get; set; }\n public int Level { get; set; }\n public List<InventoryItem> Inventory { get; set; } // Navigation property\n}\n</code></pre>\n<p>And the <code>InventoryItem</code>:</p><pre><code class=\"language-cs\">public class InventoryItem {\n public int Id { get; set; } // Primary key\n public string ItemName { get; set; }\n public int Quantity { get; set; }\n public int PlayerId { get; set; } // Foreign key to Player\n public Player Player { get; set; } // Navigation property\n}\n</code></pre>\n<p>In this example:</p><ul>\n<li>Each <code>Player</code> has a collection of <code>InventoryItems</code>.</li>\n<li>The <code>InventoryItem</code> table will have a foreign key (<code>PlayerId</code>) to the <code>Player</code> table.</li>\n</ul>\n<h3 id=\"basic-crud-operations\">Basic CRUD Operations</h3>\n<p>Create</p><pre><code class=\"language-cs\">using (var context = new GameDbContext()) {\n var player = new Player {\n Name = "Jack",\n Level = 5\n };\n\n context.Players.Add(player);\n context.SaveChanges(); // Persist changes to the database\n}\n</code></pre>\n<p>Read</p><pre><code class=\"language-cs\">using (var context = new GameDbContext()) {\n var player = context.Players\n .Include(p => p.Inventory) // Load related inventory items\n .FirstOrDefault(p => p.Name == "Jack");\n\n Console.WriteLine(player.Name + " has " + player.Inventory.Count + " items.");\n}\n</code></pre>\n<p>Update</p><pre><code class=\"language-cs\">using (var context = new GameDbContext()) {\n var player = context.Players.FirstOrDefault(p => p.Name == "Jack");\n if (player != null) {\n player.Level += 1;\n context.SaveChanges(); // Save the updated data\n }\n}\n</code></pre>\n<p>Delete</p><pre><code class=\"language-cs\">using (var context = new GameDbContext()) {\n var player = context.Players.FirstOrDefault(p => p.Name == "Jack");\n if (player != null) {\n context.Players.Remove(player);\n context.SaveChanges();\n }\n}\n</code></pre>\n<h3 id=\"tips-for-effective-use\">Tips for Effective Use</h3>\n<p><strong>Avoid Querying the DbContext Multiple Times:</strong> When you need related data, use <strong>eager loading</strong> (<code>.Include()</code>) or <strong>lazy loading</strong> so you don’t make multiple database round trips.</p><p>Example of eager loading:</p><pre><code class=\"language-cs\">var playerWithInventory = context.Players.Include(p => p.Inventory).FirstOrDefault();\n</code></pre>\n<p><strong>Use Transactions for Batch Operations:</strong> If you are performing multiple updates, wrap them in a transaction for better performance and consistency.</p><pre><code class=\"language-cs\">using (var transaction = context.Database.BeginTransaction()) {\n // Multiple operations here\n transaction.Commit();\n}\n</code></pre>\n<p><strong>Split Read and Write Contexts:</strong> If your game has a lot of read-heavy operations, you can create separate contexts for reading and writing. This can reduce lock contention in some cases.</p><h3 id=\"relationships-between--the-database-and-c-objects\">Relationships Between the Database and C# Objects</h3>\n<h4 id=\"key-parts\">Key Parts:</h4>\n<ol>\n<li><p><strong><code>List<InventoryItem></code> in the <code>Player</code> class</strong><br> This is a collection (or list) of items that a player owns. It’s purely a C# list inside the <code>Player</code> object. It represents all the items that the player has in their inventory.</p></li>\n<li><p><strong><code>DbSet<InventoryItem></code> in the <code>GameDbContext</code> class</strong><br> This is a way for Entity Framework (EF Core) to track all the inventory items in your game. It knows how to load items from the database, save them back to the database, and query them.</p></li>\n</ol>\n<h4 id=\"relationship-between-them\">Relationship Between Them:</h4>\n<ul>\n<li>The <strong><code>DbSet<InventoryItem></code></strong> in <code>GameDbContext</code> manages <em>all</em> the <code>InventoryItem</code> objects stored in your database. Think of it like a “big box” where every inventory item in the entire game is kept.</li>\n<li>The <strong><code>List<InventoryItem></code></strong> inside the <code>Player</code> class is more specific. It only holds the items that belong to that particular player. When you retrieve a player from the database, EF Core also helps fill in the <code>List<InventoryItem></code> with just the items that belong to that player.</li>\n</ul>\n<h4 id=\"how-an-item-is-created-and-added\">How an Item is Created and Added</h4>\n<ol>\n<li><strong>Creating a New Item:</strong> When you create an <code>InventoryItem</code>, you are making a new C# object in memory. For example:</li>\n</ol>\n<pre><code class=\"language-cs\">var newItem = new InventoryItem {\n ItemName = "Sword",\n Quantity = 1,\n PlayerId = player.Id // Foreign key linking to the player\n};\n</code></pre>\n<ul>\n<li><p>This creates an object in memory but <strong>it’s not yet part of the database</strong>.</p></li>\n<li><p><strong>Adding it to the Player’s Inventory:</strong> Next, you add it to the player’s inventory list:</p></li>\n</ul>\n<pre><code class=\"language-cs\">player.Inventory.Add(newItem);\n</code></pre>\n<ul>\n<li><p>Now the new <code>InventoryItem</code> is in the <code>Player</code>‘s list (<code>player.Inventory</code>), but it still <strong>doesn’t exist in the database</strong> yet.</p></li>\n<li><p><strong>Adding the Item to the Database (Making it Permanent):</strong> To save the new item to the database, you have to tell EF Core to track it and save it. Here’s how:</p></li>\n</ul>\n<pre><code class=\"language-cs\">context.InventoryItems.Add(newItem); // Add the item to the DbSet\ncontext.SaveChanges(); // Save changes to the database\n</code></pre>\n<ul>\n<li><code>context.InventoryItems.Add(newItem)</code> tells EF Core to prepare this new item for being stored in the database.</li>\n<li><code>context.SaveChanges()</code> takes everything EF Core is tracking (including this new item) and writes it into the database.</li>\n</ul>\n<p>Now the item exists both in <strong>memory</strong> (in <code>player.Inventory</code>) and in the <strong>database</strong> (inside the <code>InventoryItems</code> table).</p><h3 id=\"who-or-what-is-responsible-for-the-objects\">Who or What is Responsible for the Objects?</h3>\n<ul>\n<li><strong>You (the Developer)</strong> create and manage the actual objects (<code>InventoryItem</code>, <code>Player</code>, etc.) in C# code.</li>\n<li><strong>EF Core</strong> manages the communication between your code (in memory) and the database (on disk). It knows how to save and load these objects.</li>\n</ul>\n<h4 id=\"what-is-the-real-object\">What is the Real Object?</h4>\n<ul>\n<li>The <strong>real object</strong> is the one in memory. For example, <code>newItem</code> is the actual object you create.</li>\n<li>When you save it to the database, it becomes a row in the database, but when you load it back later, EF Core re-creates the object in memory.</li>\n</ul>\n<h4 id=\"are-there-temporary-objects\">Are There Temporary Objects?</h4>\n<ul>\n<li>Yes, the <code>InventoryItem</code> you create in memory is a “temporary object” until you save it to the database using <code>context.SaveChanges()</code>.</li>\n<li>After saving, it becomes permanent in the database. EF Core keeps a reference to this same object in memory, so it doesn’t create multiple copies unnecessarily.</li>\n</ul>\n<h4 id=\"are-they-the-same-object-with-multiple-references\">Are They the Same Object with Multiple References?</h4>\n<ul>\n<li>Yes. Once you add an item to both <code>player.Inventory</code> and <code>context.InventoryItems</code>, these are two references to the <strong>same object</strong>.<ul>\n<li><code>player.Inventory</code> holds a reference to the <code>InventoryItem</code> in the context of the player.</li>\n<li><code>context.InventoryItems</code> manages that same object but in the context of the database.</li>\n</ul>\n</li>\n</ul>\n<h4 id=\"how-do-you-use-all-of-this\">How Do You Use All of This?</h4>\n<ol>\n<li><strong>Create the item:</strong><br> Create a new item in memory like this:</li>\n</ol>\n<pre><code class=\"language-cs\">var newItem = new InventoryItem {\n ItemName = "Shield",\n Quantity = 1,\n PlayerId = player.Id\n};\n</code></pre>\n<p><strong>Add the item to the player:</strong><br>Add it to the player’s <code>Inventory</code> list:</p><pre><code class=\"language-cs\">player.Inventory.Add(newItem);\n</code></pre>\n<p><strong>Track the item in EF Core:</strong><br>Tell EF Core about this item by adding it to the <code>DbSet</code>:</p><pre><code class=\"language-cs\">context.SaveChanges();\n</code></pre>\n<p>Now, the item is:</p><ul>\n<li>In the player’s inventory (<code>player.Inventory</code>).</li>\n<li>In the database, managed by EF Core (<code>context.InventoryItems</code>).</li>\n</ul>\n<h3 id=\"quick-summary\">Quick Summary:</h3>\n<ul>\n<li><strong><code>List<InventoryItem></code> in <code>Player</code>:</strong> Holds items only for that player in memory.</li>\n<li><strong><code>DbSet<InventoryItem></code> in <code>GameDbContext</code>:</strong> Manages all inventory items in the game and connects them to the database.</li>\n<li><strong>Creating an item:</strong> You create the item in memory, add it to the player’s list, and then save it to the database with EF Core.</li>\n<li><strong>Real object:</strong> The item is real in memory, and EF Core makes sure the object gets saved and retrieved from the database properly. Multiple references to the same object point to the same instance.</li>\n</ul>\n<p>This approach helps ensure that your game objects exist in both memory and the database in a well-structured, efficient manner.</p><h3 id=\"who-should-initialize-player-with-inventory-items\">Who Should Initialize <code>Player</code> with Inventory Items?</h3>\n<p>Classes should not be responsible for initializing themselves with its data. That would violate the Single Responsibility Principle, where a class should only have one reason to change. The Player class, for example, should focus on modeling the player and its properties, not managing data access.</p><p>The better option is to have a controller or manager responsible for fetching the <code>Player</code> and its associated data from the database. This manager could be something like a <code>PlayerService</code> or <code>GameDataLoader</code> and it would query the database, populate the <code>Player</code> object with the data, and return the fully initialized <code>Player</code> object.</p><p>It might look something like:</p><pre><code class=\"language-cs\">public class PlayerService {\n private readonly GameDbContext _context;\n\n public PlayerService(GameDbContext context) {\n _context = context;\n }\n\n public Player GetPlayerWithInventory(int playerId) {\n return _context.Players\n .Include(p => p.Inventory) // Eager load inventory items\n .FirstOrDefault(p => p.Id == playerId);\n }\n}\n</code></pre>\n<p>This way the <code>Player</code> class stays clean and doesn’t know anything about the database.</p><h3 id=\"multiple-operations-on-the-same-object\">Multiple Operations on the Same Object</h3>\n<p>It can feel like there are two separate operations:</p><ol>\n<li>Adding items to the <code>player.Inventory</code> list.</li>\n<li>Adding items to the <code>DbSet<InventoryItem></code>.</li>\n</ol>\n<p>It can feel like you’re duplicating the same work by managing both the list and the database. Let’s clarify what’s going on and how to approach it.</p><h3 id=\"are-there-really-two-sets-of-objects\">Are There Really Two Sets of Objects?</h3>\n<p>Not exactly. When you create an <code>InventoryItem</code>, it exists as a single object in memory. When you add it to <code>player.Inventory</code> and later to <code>context.InventoryItems</code>, you’re just creating <strong>two references to the same object</strong>. EF Core tracks changes to the object via <code>context.InventoryItems</code>, but you’re free to access that object through <code>player.Inventory</code>.</p><h3 id=\"is-it-normal\">Is It Normal?</h3>\n<p>Yes, this pattern of managing both the collection (like <code>player.Inventory</code>) and saving to the database separately is pretty common in EF Core and ORMs in general. However, the redundancy you’re feeling can be reduced.</p><h3 id=\"how-to-simplify\">How to Simplify</h3>\n<p>Instead of managing both the player’s inventory list and the database context separately, let’s clean it up so that you only interact with the <code>Player</code> object and let EF Core handle saving both <code>Player</code> and <code>InventoryItem</code> in one go.</p><ul>\n<li><strong>One Object Graph</strong>: You should treat the <code>Player</code> and its <code>Inventory</code> as a single “object graph.” When you save the <code>Player</code>, EF Core will automatically save all related <code>InventoryItem</code> objects.</li>\n</ul>\n<p>Here’s how you might do that:</p><pre><code class=\"language-cs\">using (var context = new GameDbContext()) {\n // Create the player and the item\n var player = new Player { Name = "Jack", Level = 5 };\n var newItem = new InventoryItem { ItemName = "Sword", Quantity = 1 };\n\n // Add the item to the player's inventory\n player.Inventory.Add(newItem);\n\n // Add the player (with inventory) to the context\n context.Players.Add(player);\n\n // Save everything at once\n context.SaveChanges(); // Saves both Player and InventoryItem in one go\n}\n</code></pre>\n<p>In this example:</p><ul>\n<li>You’re only managing the <code>Player</code> object.</li>\n<li>By adding the <code>InventoryItem</code> to the <code>player.Inventory</code>, EF Core will automatically track that item because it’s part of the <code>Player</code>’s “object graph.”</li>\n<li>When you call <code>context.SaveChanges()</code>, EF Core will save the <code>Player</code> and all related <code>InventoryItem</code> objects in one transaction.</li>\n</ul>\n<h3 id=\"is-it-code-smell\">Is It Code Smell?</h3>\n<p>The approach where you’re managing <code>player.Inventory</code> and <code>context.InventoryItems</code> separately can feel like a code smell if you’re not leveraging EF Core’s ability to track relationships between entities. If you’re manually handling both, it feels like duplication and is error-prone.</p><p>However, when you treat the <code>Player</code> and <code>InventoryItems</code> as part of a single object graph (as shown above), it becomes simpler and more natural. EF Core can track everything with just one call to <code>SaveChanges()</code>.</p><h3 id=\"summary\">Summary</h3>\n<ul>\n<li><strong>Who initializes the <code>Player</code>?</strong> A <code>PlayerService</code> (or similar) should be responsible for loading <code>Player</code> objects with their <code>InventoryItems</code> from the database.</li>\n<li><strong>Are two object sets necessary?</strong> No, ideally you treat <code>Player</code> and <code>InventoryItem</code> as a single object graph. Add items to <code>player.Inventory</code> and let EF Core handle the persistence for both in one operation.</li>\n<li><strong>Cleaner approach:</strong> Use EF Core’s relationship tracking to save both <code>Player</code> and <code>InventoryItem</code> with one <code>SaveChanges()</code> call, minimizing manual duplication of work.</li>\n</ul>\n<p>This approach should streamline your code and make it feel less “janky.”</p><h3 id=\"performing-logic-without-becoming-tied-to-database-operations\">Performing Logic Without Becoming Tied to Database Operations</h3>\n<p>Let’s explore how the <code>Receive(IItem givenItem, IItemGiver giver)</code> method would fit into this scheme.</p><p>The <code>Receive</code> method allows the player to receive an item from another entity like an NPC. Here’s how we can integrate this with our previously discussed EF Core setup without causing duplication or breaking cohesion.</p><h3 id=\"1-what-would-receive-do\">1. <strong>What Would <code>Receive</code> Do?</strong></h3>\n<p>The <code>Receive</code> method in <code>Player</code> is responsible for:</p><ul>\n<li>Adding the received item (<code>givenItem</code>) to the player’s inventory.</li>\n<li>Optionally tracking who gave the item (if needed for gameplay logic).</li>\n<li>Ensuring the item is properly saved to the database.</li>\n</ul>\n<p>The key here is that the method should manage the player’s inventory but let EF Core handle the database part. <code>Receive</code> can operate on the object graph (the player and its items) without worrying about how EF Core persists those changes.</p><h3 id=\"2-adjusting-the-receive-method-to-work-with-ef-core\">2. <strong>Adjusting the <code>Receive</code> Method to Work with EF Core</strong></h3>\n<p>Let’s start by looking at a potential implementation of the <code>Receive</code> method:</p><pre><code class=\"language-cs\">public class Player {\n\n public List<InventoryItem> Inventory { get; private set; }\n\n public void Receive(IItem givenItem, IItemGiver giver) {\n // Assume givenItem is a valid InventoryItem object\n InventoryItem item = (InventoryItem)givenItem;\n\n // Add the item to the player's inventory\n Inventory.Add(item);\n\n // Optionally log the giver or update some logic based on the giver\n Console.WriteLine($"{giver.Name} gave you {item.ItemName}.");\n\n // The item now exists in the player's inventory list\n // Saving to the database happens outside of this method\n }\n}\n</code></pre>\n<p>In this method:</p><ul>\n<li><code>givenItem</code> is cast to <code>InventoryItem</code> and added to the player’s <code>Inventory</code> list.</li>\n<li>The method handles adding the item to the player’s memory representation of inventory but <strong>doesn’t directly deal with the database</strong>.</li>\n<li>Database operations (saving the item) happen outside this method.</li>\n</ul>\n<h3 id=\"3-who-manages-database-saving\">3. <strong>Who Manages Database Saving?</strong></h3>\n<p>You want the <code>Receive</code> method to be simple and focus on the game logic, not database handling. Database saving should be handled at a higher level, probably by the <strong>game logic controller</strong> or <strong>service</strong>.</p><p>For example, an NPC gives the player an item, and after the game logic is complete, the system saves the changes to the database.</p><p>Here’s how that might look at the controller/service level:</p><pre><code class=\"language-cs\">public class GameController {\n private readonly GameDbContext _context;\n\n public GameController(GameDbContext context) {\n _context = context;\n }\n\n public void GiveItemToPlayer(Player player, IItem givenItem, IItemGiver giver) {\n // Player receives the item from the NPC\n player.Receive(givenItem, giver);\n\n // Track changes to the player's inventory in the database\n _context.Players.Update(player);\n \n // Since the InventoryItem is part of the Player's object graph, EF Core will\n // automatically track the new item and save it\n _context.SaveChanges();\n }\n}\n</code></pre>\n<p>Here:</p><ul>\n<li><strong>The <code>Player</code> handles the game logic</strong>: The player gets the item from the NPC via <code>Receive(givenItem, giver)</code>.</li>\n<li><strong>The <code>GameController</code> handles the database logic</strong>: After the player has received the item, the controller updates the player’s state in the database by calling <code>Update(player)</code> and <code>SaveChanges()</code>.</li>\n</ul>\n<h3 id=\"4-why-does-this-make-sense\">4. <strong>Why Does This Make Sense?</strong></h3>\n<ul>\n<li><strong>Separation of Concerns</strong>: The <code>Player</code> class focuses only on game logic (receiving items, managing its own state). It doesn’t deal with saving or database operations, which are handled at a higher level (in this case, the <code>GameController</code>).</li>\n<li><strong>Single Object Graph</strong>: The <code>Player</code> and its <code>InventoryItem</code> are part of a single object graph. When the <code>GameController</code> saves the <code>Player</code>, EF Core will automatically detect that a new <code>InventoryItem</code> was added to the player’s <code>Inventory</code> and will save both the <code>Player</code> and the new item in one operation.</li>\n<li><strong>No Duplication of Objects</strong>: You’re still only working with one set of objects in memory. There’s no separate management of the database objects and in-memory objects.</li>\n</ul>\n<h3 id=\"5-handling-the-giver-npc\">5. <strong>Handling the Giver (NPC)</strong></h3>\n<p>If the giver (NPC) needs to be tracked (for example, if it’s important to know which NPC gave the item), you can log or store that information in the <code>Receive</code> method or another part of the <code>Player</code> class. Here’s an example:</p><pre><code class=\"language-cs\">public class Player {\n\n public List<InventoryItem> Inventory { get; private set; }\n\n public void Receive(IItem givenItem, IItemGiver giver) {\n InventoryItem item = (InventoryItem)givenItem;\n\n // Add to the player's inventory\n Inventory.Add(item);\n\n // Log or track the giver if needed\n Console.WriteLine($"{giver.Name} gave {item.ItemName}");\n\n // Example: Track giver info in the item\n item.GivenBy = giver.Name;\n\n // Database saving is handled externally\n }\n}\n</code></pre>\n<p>In this case, you might store the giver’s information inside the <code>InventoryItem</code> or just log it. This depends on your game’s needs.</p><h3 id=\"does-this-fit-the-pattern\"><strong>Does This Fit the Pattern?</strong></h3>\n<p>Absolutely. This design adheres to the principles we’ve discussed:</p><ul>\n<li><strong>Parent-to-Child Dependency</strong>: The <code>Player</code> manages its own inventory (<code>InventoryItem</code> is part of the <code>Player</code> object graph).</li>\n<li><strong>Single Responsibility</strong>: The <code>Player</code> class focuses only on its own game logic (receiving items), while the <code>GameController</code> is responsible for coordinating between game logic and the database.</li>\n<li><strong>No Object Duplication</strong>: You only manage one set of objects in memory. EF Core tracks the changes and handles persistence in the background.</li>\n</ul>\n<h4 id=\"example-flow\">Example Flow:</h4>\n<ol>\n<li>The NPC (giver) wants to give an item.</li>\n<li>The <code>GameController</code> calls <code>player.Receive(givenItem, giver)</code>.</li>\n<li>The <code>Player</code> receives the item and adds it to its <code>Inventory</code>.</li>\n<li>The <code>GameController</code> calls <code>SaveChanges()</code> to persist both the <code>Player</code> and the new <code>InventoryItem</code> to the database.</li>\n</ol>\n<h4 id=\"summary-1\">Summary</h4>\n<ul>\n<li><strong><code>Player.Receive()</code></strong> manages the logic of receiving the item, while <strong>database operations</strong> are handled at a higher level (like a controller or manager).</li>\n<li><strong>EF Core automatically tracks</strong> changes to the <code>InventoryItem</code> through the <code>Player</code>’s object graph.</li>\n<li>You avoid duplication by keeping everything in one object graph and only persisting the whole player state when needed.</li>\n</ul>\n<p>This approach is clean, avoids code smells, and keeps your game logic and data access responsibilities well-separated.</p><h2 id=\"managing-dependencies\">Managing dependencies</h2>\n<p><code>[Export]</code> is the Godot way of doing dependency injection. Ideally the exported node would be a child node mapped to a parent controller, as explained in [[#Parent-to-Child Dependencies]] above.</p><p>When a clear parent-child relationship cannot be used, like, for example in a situation where UI needs data to display different strategies can be applied.</p><h3 id=\"where-should-requests-originate\">Where Should Requests Originate?</h3>\n<p>The request to give an item should indeed originate from the <strong>NPC</strong> (or more precisely, from an interaction between the NPC and the Player). However, the <strong>NPC</strong> itself doesn’t need to manage the whole process—its role can remain simple, while the higher-level game logic (likely in the <strong>GameController</strong>) handles the actual mechanics.</p><h3 id=\"2-the-npc-as-a-dumb-object\">2. <strong>The NPC as a “Dumb” Object</strong></h3>\n<p>The NPC can be more of a “dumb” object. The NPC just holds some data and methods to initiate an action (like giving an item), but the <strong>NPC should not be responsible for complex game logic</strong> like inventory management or interacting directly with the database. This keeps the NPC clean and focused on what it represents in the game world.</p><p>In other words, the NPC initiates the process by signaling its intent to give an item, but the <strong>GameController</strong> or some other game system handles the heavy lifting.</p><p>Here’s a possible structure:</p><h3 id=\"3-how-the-hierarchy-and-interaction-would-work\">3. <strong>How the Hierarchy and Interaction Would Work</strong></h3>\n<ol>\n<li><strong>NPC</strong>: The NPC triggers the action, such as giving an item, when it interacts with the player.</li>\n<li><strong>GameController</strong>: The <code>GameController</code> (or a similar system) manages what actually happens when the NPC gives the item to the player, including updating the game state, calling the player’s <code>Receive()</code> method, and saving the changes.</li>\n<li><strong>Player</strong>: The player receives the item, and the player’s inventory is updated. The player doesn’t handle persistence or interaction logic—that’s handled by the <code>GameController</code>.</li>\n</ol>\n<h3 id=\"4-example-flow-of-giving-an-item\">4. <strong>Example Flow of Giving an Item</strong></h3>\n<h4 id=\"npc-class\">NPC Class</h4>\n<p>The NPC is a simple entity. It has an item to give and can trigger the <code>GiveItemToPlayer()</code> method in the <code>GameController</code>.</p><pre><code class=\"language-cs\">public class NPC : IItemGiver {\n public string Name { get; set; }\n public InventoryItem ItemToGive { get; set; }\n\n public void InteractWithPlayer(Player player, GameController controller) {\n // The NPC asks the GameController to give the player an item\n controller.GiveItemToPlayer(player, ItemToGive, this);\n }\n}\n</code></pre>\n<p>In this case:</p><ul>\n<li>The <strong>NPC</strong> has an <code>ItemToGive</code>, but it doesn’t handle the details of giving the item.</li>\n<li>When the player interacts with the NPC, the <strong>NPC triggers</strong> the interaction by calling the <code>GameController</code>.</li>\n</ul>\n<h4 id=\"gamecontroller-class\">GameController Class</h4>\n<p>The <strong>GameController</strong> handles the actual transaction, manages the logic of giving the item, and persists the changes to the database.</p><pre><code class=\"language-cs\">public class GameController {\n private readonly GameDbContext _context;\n\n public GameController(GameDbContext context) {\n _context = context;\n }\n\n public void GiveItemToPlayer(Player player, IItem givenItem, IItemGiver giver) {\n // The player receives the item\n player.Receive(givenItem, giver);\n\n // Update the database to reflect the new item in the player's inventory\n _context.Players.Update(player);\n _context.SaveChanges();\n }\n}\n</code></pre>\n<p>Here:</p><ul>\n<li>The <strong>GameController</strong> coordinates the interaction between the <strong>NPC</strong> and the <strong>Player</strong>.</li>\n<li>It ensures that the item is added to the player’s inventory and saved in the database.</li>\n</ul>\n<h4 id=\"player-class\">Player Class</h4>\n<p>The <strong>Player</strong> is responsible for adding the item to its inventory but doesn’t deal with persistence or interaction logic.</p><pre><code class=\"language-cs\">public class Player {\n public List<InventoryItem> Inventory { get; private set; }\n\n public void Receive(IItem givenItem, IItemGiver giver) {\n InventoryItem item = (InventoryItem)givenItem;\n Inventory.Add(item);\n Console.WriteLine($"{giver.Name} gave you a {item.ItemName}.");\n }\n}\n</code></pre>\n<h3 id=\"hierarchy-and-parent-to-child-dependency\"><strong>Hierarchy and Parent-to-Child Dependency</strong></h3>\n<p>To maintain the <strong>parent-to-child dependency</strong>, the <strong>NPC</strong> doesn’t need to directly know about the <strong>GameController</strong> or even the <strong>Player</strong> in a deep sense. It just triggers an action (like <code>InteractWithPlayer</code>) and passes in the necessary data.</p><p>The <strong>GameController</strong> acts as the “parent” managing the flow between the NPC and the Player. It orchestrates the logic from a higher level, ensuring that the NPC, Player, and database all interact correctly without causing any child-to-parent dependencies or complex cross-object interactions.</p><p>In this setup:</p><ul>\n<li><strong>NPC → GameController → Player</strong> is the flow of control.</li>\n<li>The <strong>NPC</strong> triggers the event, but it’s the <strong>GameController</strong> that manages the relationship between NPCs, Players, and the database.</li>\n</ul>\n<p>This avoids any circular dependencies, keeps the NPC simple (it doesn’t manage the database or game state directly), and maintains a clear, hierarchical flow of control.</p><h3 id=\"6-why-this-structure-makes-sense\">6. <strong>Why This Structure Makes Sense</strong></h3>\n<ul>\n<li><strong>Separation of Concerns</strong>: The <strong>NPC</strong> only knows about the fact that it wants to give an item. It doesn’t care about how the item is added to the player’s inventory or saved to the database.</li>\n<li><strong>Centralized Game Logic</strong>: The <strong>GameController</strong> coordinates the overall interaction and handles the persistence. This prevents messy dependencies between unrelated objects and keeps the architecture clean.</li>\n<li><strong>Single Source of Truth</strong>: There’s no risk of having multiple versions of the same data floating around. The <strong>Player</strong> manages the inventory, and EF Core handles the persistence as one unified object graph.</li>\n</ul>\n<h3 id=\"summary-2\">Summary</h3>\n<ul>\n<li><strong>The NPC</strong> initiates the action to give an item but doesn’t handle the complex logic. It triggers the interaction by calling the <code>GameController</code>.</li>\n<li><strong>The GameController</strong> orchestrates the interaction, calling the player’s <code>Receive()</code> method and saving the changes to the database.</li>\n<li><strong>The Player</strong> receives the item, but doesn’t manage the persistence or higher-level game logic.</li>\n<li>This structure avoids child-to-parent dependencies and keeps the <strong>NPC</strong> and <strong>Player</strong> focused on their respective responsibilities, while the <strong>GameController</strong> handles game logic and database interaction.</li>\n</ul>\n<p>This way, everything stays clean, focused, and manageable, adhering to solid architectural principles.</p><h3 id=\"what-about-returning-state\">What About Returning State?</h3>\n<p>you sometimes need to get state back from child objects. However, how you handle that state depends on how tightly you want to couple your objects and what kind of architecture you’re following. There are two key approaches you can consider:</p><ol>\n<li><strong>Fetching State When Necessary</strong>: This is the classic way where you allow some controlled flow of information back up the hierarchy.</li>\n<li><strong>Designing Around the Principle of Always Valid State</strong>: This approach reduces the need to query state and focuses on ensuring that the system is always in a valid state by design.</li>\n</ol>\n<p>Let’s explore both.</p><h4 id=\"fetching-state-back-from-child-objects\"><strong>Fetching State Back from Child Objects</strong></h4>\n<p>In many cases, it’s reasonable for a parent (like the <code>GameController</code>) to query child objects (like the <code>Player</code> or <code>NPC</code>) for their state. This is especially true when decisions need to be made based on real-time data (e.g., checking the player’s health, inventory capacity, etc.).</p><h4 id=\"example-checking-the-players-health\">Example: Checking the Player’s Health</h4>\n<p>Imagine you need to check the player’s health to decide if they can continue in combat or if they need healing:</p><pre><code class=\"language-cs\">public class GameController {\n\n public void CheckPlayerHealth(Player player) {\n if (player.Health < 20) {\n Console.WriteLine("Player needs healing!");\n } else {\n Console.WriteLine("Player is healthy.");\n }\n }\n}\n\npublic class Player {\n public int Health { get; private set; }\n\n public Player(int health) {\n Health = health;\n }\n}\n</code></pre>\n<p>Here:</p><ul>\n<li>The <strong>GameController</strong> is querying the <strong>Player</strong> for its current health.</li>\n<li>The flow remains parent-to-child (the <code>GameController</code> calls methods on <code>Player</code>), but it’s getting information back for decision-making.</li>\n</ul>\n<p><strong>This approach is sensible when:</strong></p><ul>\n<li>You need real-time, up-to-date information from child objects.</li>\n<li>The parent object (e.g., <code>GameController</code>) needs to make decisions based on child state.</li>\n</ul>\n<h3 id=\"2-designing-for-always-valid-state\">2. <strong>Designing for Always Valid State</strong></h3>\n<p>Another approach is to minimize or eliminate the need for fetching state by designing your objects to always maintain a valid state. In this approach, each object is responsible for managing its state and ensuring that it is always “correct” from the perspective of the game logic. This aligns with the <strong>tell, don’t ask</strong> principle, where instead of querying state, you tell the object to act and trust that it will maintain its own state properly.</p><h4 id=\"example-players-health-in-an-always-valid-system\">Example: Player’s Health in an “Always Valid” System</h4>\n<p>Instead of checking the player’s health manually, you could have the <strong>Player</strong> class manage its own health logic:</p><pre><code class=\"language-cs\">public class Player {\n public int Health { get; private set; }\n\n public Player(int health) {\n Health = health;\n }\n\n public void TakeDamage(int damage) {\n Health -= damage;\n\n // Automatically handle death\n if (Health <= 0) {\n HandleDeath();\n }\n }\n\n private void HandleDeath() {\n Console.WriteLine("Player has died.");\n // Additional logic for death could go here\n }\n}\n</code></pre>\n<p>In this example:</p><ul>\n<li>The <strong>Player</strong> object itself manages its state (health), and you don’t need to query it in the <code>GameController</code> to check if it needs healing or if it’s dead.</li>\n<li>The <strong>Player</strong> ensures that its own health logic is valid at all times. If health reaches 0, it automatically handles death internally.</li>\n</ul>\n<p><strong>This approach is sensible when:</strong></p><ul>\n<li>You want to decentralize state management and avoid state queries.</li>\n<li>You prefer each object to be self-sufficient in managing its own state, reducing external checks.</li>\n</ul>\n<h3 id=\"when-to-fetch-state-vs-when-to-rely-on-always-valid-state\">When to Fetch State vs. When to Rely on “Always Valid State”</h3>\n<h4 id=\"fetching-state\"><strong>Fetching State</strong></h4>\n<p>This approach works best when you have:</p><ul>\n<li>Complex decision-making that requires real-time information from child objects.</li>\n<li>Systems where the parent (controller) needs to make decisions based on child state.</li>\n</ul>\n<p>You should use this approach if:</p><ul>\n<li>You need to query conditions like the player’s inventory, health, or quest status to make game-wide decisions.</li>\n<li>The flow of data needs to be flexible and responsive.</li>\n</ul>\n<h4 id=\"designing-for-always-valid-state\"><strong>Designing for Always Valid State</strong></h4>\n<p>This approach reduces complexity by making each object responsible for its own state, making the system less dependent on constant state checks.</p><p>You should use this approach if:</p><ul>\n<li>You want to reduce the need for querying state and want each object to maintain itself.</li>\n<li>You prefer objects that react to commands and automatically handle their own logic, ensuring that no external checks are needed.</li>\n</ul>\n<h3 id=\"hybrid-approach-valid-state--occasional-queries\">Hybrid Approach: Valid State + Occasional Queries</h3>\n<p>In practice, most games use a combination of both approaches.</p><ul>\n<li><strong>“Always Valid State”</strong>: For simpler systems like inventory management, health, or abilities, where the player and other entities handle their own state and transitions.</li>\n<li><strong>Fetching State</strong>: For higher-level game systems or controllers that need to coordinate multiple entities or query complex data (like checking for quest completion or making decisions based on several objects’ states).</li>\n</ul>\n<p>For example, the <code>GameController</code> might periodically <strong>query</strong> the player’s health and inventory, but <strong>rely</strong> on the player itself to always keep its inventory and health in a valid state.</p><h3 id=\"example-of-combining-both-approaches\">Example of Combining Both Approaches</h3>\n<pre><code class=\"language-cs\">public class GameController {\n\n public void UpdateGameState(Player player) {\n // Query player state when needed\n if (player.Health < 20) {\n Console.WriteLine("Warning: Player health is low.");\n }\n\n // Assume player always maintains a valid inventory\n player.ReceiveNewItem(new InventoryItem("Health Potion"));\n }\n}\n\npublic class Player {\n public int Health { get; private set; }\n public List<InventoryItem> Inventory { get; private set; }\n\n public Player(int health) {\n Health = health;\n Inventory = new List<InventoryItem>();\n }\n\n // Player manages its own health and reacts accordingly\n public void TakeDamage(int damage) {\n Health -= damage;\n if (Health <= 0) HandleDeath();\n }\n\n // Always valid inventory management\n public void ReceiveNewItem(InventoryItem item) {\n Inventory.Add(item);\n Console.WriteLine($"Received {item.ItemName}.");\n }\n\n private void HandleDeath() {\n Console.WriteLine("Player has died.");\n }\n}\n</code></pre>\n<p>In this hybrid example:</p><ul>\n<li>The <strong>GameController</strong> queries the player’s health when needed.</li>\n<li>The <strong>Player</strong> manages its inventory and health internally, always ensuring valid state without needing to be micromanaged by the <code>GameController</code>.</li>\n</ul>\n<h3 id=\"conclusion\">Conclusion</h3>\n<ul>\n<li><strong>Fetching state</strong> is necessary when the controller needs real-time information to make decisions, and it’s totally acceptable in many cases.</li>\n<li><strong>Always valid state</strong> design reduces the need for querying and ensures objects maintain themselves in a valid state, which simplifies logic and reduces dependencies.</li>\n<li><strong>Hybrid approaches</strong> are often best in games, where certain systems (like health, inventory, or quests) manage themselves, while others (like high-level game logic) still require state checks.</li>\n</ul>\n<p>In short, aim for valid state whenever possible, but don’t be afraid to query state when needed for complex game logic. Both patterns can work together effectively depending on the situation.</p><h2 id=\"c-events-and-signals-for-decoupling\">C# Events and Signals for Decoupling</h2>\n<p>Use the event system to create loosely coupled communication mechanism between nodes. This allows nodes that don’t have a direct relationship to communicate without being tightly bound.\nThe UI can emit an event when it needs data, and any node (or manager) can listen to those signals and provide the needed data.</p><h2 id=\"using-godot-resources-to-share-data\">Using Godot Resources to Share Data</h2>\n<p>Godot <code>Resource</code> can be used to share data between various objects as long as you are aware of the limitations - only one party should ever be responsible for changing the data, while several can read it at the same time. A shared <code>Resource</code> gives instantaneous access to the data across multiple objects. You will also have to be careful and deploy a default strategy in case the data is not available at any given time.</p><h2 id=\"service-locator--manager-pattern\">Service Locator / Manager Pattern</h2>\n<p>Can be used to create a centralized manager or service locator to handle instances of shared dependencies like data required by UI. This pattern helps when the relationships is not clear or direct.\nFor example, you can have a <code>GameManager</code> or <code>DataManager</code> node responsible for holding game state, UI data, or other global information.\nYou’d reference this node using Godot’s <code>GetTree().Root</code> or a singleton (Autoload) which would allow child nodes, such as your UI elements, to fetch the necessary data without needing a direct parent-child relationship.</p><h2 id=\"godot-singleton-autoload\">Godot Singleton Autoload</h2>\n<p>For truly global data (such as player stats, global settings, etc.) consider using an <code>Autoload</code>. This allows any node to access global state without needing a direct reference. This should be used sparingly to avoid overloading the global namespace with too many dependencies.</p>",
"image": "https://pilvimaa.fi/media/posts/20/SoftwareArchitecture.png",
"author": {
"name": "Pilvinen"
},
"tags": [
"structure",
"design",
"architecture"
],
"date_published": "2024-09-20T10:56:56+03:00",
"date_modified": "2024-09-20T11:28:02+03:00"
},
{
"id": "https://pilvimaa.fi/how-to-setup-sqlite-database-with-ef-core-and-godot/",
"url": "https://pilvimaa.fi/how-to-setup-sqlite-database-with-ef-core-and-godot/",
"title": "How to setup SQLite database with EF Core and Godot",
"summary": "EF Core is a popular high level object relational mapper (ORM) which can have various databases at the backend. As a database noobie, I recently had a bit of a…",
"content_html": "<p>EF Core is a popular high level object relational mapper (ORM) which can have various databases at the backend.</p><p>As a database noobie, I recently had a bit of a trouble setting it up with Godot and SQLite. There was very little practical information available from a beginner’s perspective for setting it up successfully with Godot.</p><p>I hit a dead end several times trying to follow the official MS docs and bunch of tutorials, but eventually with a help from a friend got it working.</p><p>So I thought I might as well write a quick article about it - from my own unique database noob perspective. In case someone else is having the same challenges.</p><p>If you’re looking for educated, accurate, precise and scientific description of how this piece of… technology… works, avert your eyes and never return!</p><p>At the time of writing this, Godot 4.2.2 has been out for a while and Godot 4.3 hasn’t yet been released. I’m running on .NET 8 and using C# 12. These instructions have been written for that in mind and specifically for Rider IDE. If you’re dealing with another IDE or the command line, you will have to figure those parts out for yourself.</p><h1 id=\"setting-up-a-class-library\">Setting up a class library</h1>\n<p>Since we’re going to use the Migrations feature of EF Core, to get things working properly with Godot’s SDK, you’re going to need to create your database as a separate project, as a <strong>class library</strong>.</p><p>To do that, right click your solution in Rider’s solution explorer and select <strong>Add > New Project</strong> and make it a <strong>Class Library</strong>. It will be created directly under your main project for easy access. You can call it “Database”, or what ever you like.</p><h1 id=\"linking\">Linking</h1>\n<p>To be able to do anything with the Database project it needs to be linked with your main project. So right click in Rider’s solution explorer your main project and select <strong>Add > Reference</strong>, select the box for Database and click the <strong>Add</strong> button. Done.</p><h1 id=\"dealing-with-assemblyinfo-duplicate-attributes\">Dealing with AssemblyInfo duplicate attributes</h1>\n<p>You might have noticed that there’s now a funny new folder in your main project, which is from the Database project. You might be tempted to exclude it, and if you do, you’re on your own dealing with potential issues that might arise from that.</p><p>In this tutorial we’re going to edit the your main project’s <code>.csproj</code> file and add inside the <code><PropertyGroup></PropertyGroup></code> tags near the top the following mystical tags:</p><pre><code class=\"language-xml\"><GenerateAssemblyInfo>false</GenerateAssemblyInfo>\n</code></pre>\n<p>And its good buddy:</p><pre><code class=\"language-xml\"><GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>\n</code></pre>\n<p>And by doing this magical ritual you will get rid of <strong>compilation errors</strong> caused by not excluding the aforementioned folders from your Database project - by doing which you will avoid <em>another set of problems</em>.</p><p>Just do it. You can change your setup later on your own if you’re not happy with it. Let’s first get things working.</p><h1 id=\"dealing-with-nuget\">Dealing with NuGet</h1>\n<p>The three packages you need to install from NuGet are:</p><ul>\n<li><p><code>Microsoft.EntityFrameworkCore.Sqlite</code></p></li>\n<li><p><code>Microsoft.EntityFrameworkCore.Design</code></p></li>\n<li><p><code>Microsoft.EntityFrameworkCore.Tools</code></p></li>\n</ul>\n<p>You will need to add these to your <strong>Database</strong> project. You will likely not need them in your main project.</p><h1 id=\"lets-add-some-classes\">Let’s add some classes</h1>\n<p>We’re going to need some code to be able to do anything with the database.</p><h3 id=\"savegamemanifestcs\">SaveGameManifest.cs</h3>\n<p>You can arrange your projects how ever you like, but I recommend you create in the <strong>Database</strong> project a folder named <code>DatabaseSets</code>. This folder will hold your C# classes which essentially represent your database tables.</p><p>For fun let’s add <code>SaveGameManifest.cs</code> file in that folder which will represent the data in your table. It’s basically a schema or “entity”. It’s the stuff you want to store in the database.</p><pre><code class=\"language-cs\">using System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Database;\n\n[Table("SaveGameManifest")] // Name of the table in the database for this class.\n[PrimaryKey(nameof(DatabaseId))] // They key you can directly fetch the data with.\npublic sealed class SaveGameManifest {\n\n // The primary Guid based key to access this save game manifest.\n [Column(nameof(DatabaseId))] // The database column name.\n public Guid DatabaseId { get; set; } \n\n // The name of the save game as inputted by user.\n [Column(nameof(SaveName)), MaxLength(128),] // EF Core doesn't like strings of unrestricted length.\n public string SaveName { get; set; } = string.Empty;\n\n // The date when the save game was last saved.\n [Column(nameof(LastSaved))]\n public DateTime LastSaved { get; set; } = DateTime.Now;\n\n // Required for database. Do not remove.\n public SaveGameManifest() {}\n\n public SaveGameManifest(Guid databaseId, string saveName) {\n DatabaseId = databaseId;\n SaveName = saveName;\n }\n}\n</code></pre>\n<p>And that’s it. We decorated our class and properties with attributes which instruct EF Core what everything is, ie. how it should be saved in the database. SQLite database is basically just a fancy a big Excel sheet. <strong>Tables</strong> tell you what type of stuff is in there in general (they are kind like file system folders), and <strong>Columns</strong> tell you what should go in here, and <strong>rows</strong> of the columns contain the actual data, data, data and more data.</p><h3 id=\"databaseconnectioncs\">DatabaseConnection.cs</h3>\n<p>I like to name the <code>DbContext</code> class <code>DatabaseConnection</code>, it makes it easier for me to comprehend what is going on.</p><p>There are lots of ways you could set up this file, so don’t be mistaken that this is the only way or even necessarily a good way. This is the database noob way that I came up with, the way which made sense to me personally.</p><p>This class essentially represents your database / gives you access to everything.</p><p>So in my setup you would call <code>DatabaseConnection.Instance.SaveGameManifests</code>, for example, to gain access to the <code>SaveGameManifest</code> tables via the <code>DbSet</code>. And you might call <code>DatabaseConnection.Instance.SaveChanges()</code> to save the database after making changes, etc.</p><pre><code class=\"language-cs\">using Database;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace YourMainProjectNameSpace;\n\n// We need to inherit DbContext. This allows us to connect to the database.\npublic sealed class DatabaseConnection : DbContext {\n\n // I set this up as a singleton. But you can do what ever you like.\n private static DatabaseConnection _instance;\n\n /*\n To be able to pass the user folder path to our database (where our database\n is saved) I created a Configure method which must be called before using\n the database for the first time. This is all about that.\n */\n private static bool _isConfigured = false;\n\n public static void Configure(string userFolder) {\n if (_instance == null) {\n _instance = new DatabaseConnection(userFolder);\n _isConfigured = true;\n }\n }\n\n public static DatabaseConnection Instance {\n get {\n if (!_isConfigured) throw new InvalidOperationException("DatabaseHandler is not configured. Call Configure() before accessing Instance.");\n return _instance;\n }\n }\n\n // These are used in setting up the paths.\n private string _userFolder;\n private string _databaseFolder = "database";\n private string _databasePath = "database.db";\n private string _fullDatabaseFilePath;\n\n /*\n DbSets contain essentially the tables of the database.\n You should probably have all your tables defined here in this class,\n Instead of trying to spread them around or anything like that. I hear it's\n a common practice, so it should be good enough for you too.\n So below here, in production code, would be a big list of DbSet<T>s.\n */ \n public DbSet<SaveGameManifest> SaveGameManifests { get; set; }\n\n // Again, empty constructor is needed or everything fails to work.\n public DatabaseConnection() {}\n\n /*\n And here is the constructor that we use to build things up.\n Notice that we take in the user:// folder path here. But if you prefer\n an alternate method, do what ever you like.\n */\n public DatabaseConnection(string userFolder) {\n _userFolder = userFolder;\n\n // Console.WriteLine("Initializing DatabaseHandler.");\n\n // Generate the file paths.\n GeneratePaths();\n\n // Console.WriteLine("Database file paths generated.");\n\n // Attempt to create the database file if it doesn't exist yet.\n TryCreateDatabaseFile(_fullDatabaseFilePath);\n }\n\n /*\n This bit of code is needed to configure that we're using SQLite and set the path.\n Feel free to throw in more config options if you need them.\n */\n protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {\n optionsBuilder.UseSqlite($"Data Source={_fullDatabaseFilePath}");\n }\n\n\n private void GeneratePaths() {\n\n //Console.WriteLine("Generating database file paths.");\n\n // Get the full path to the database file.\n _fullDatabaseFilePath = Path.Combine(_userFolder, _databaseFolder, _databasePath);\n }\n\n /// <summary>\n /// If the database file does not exist, create it.\n /// </summary>\n private static void TryCreateDatabaseFile(string fullDatabaseFilePath) {\n\n //Console.WriteLine("Trying to create the database file.");\n\n // If the database exists already, we don't need to create it.\n bool databaseExists = File.Exists(fullDatabaseFilePath);\n if (databaseExists) return;\n\n //Console.WriteLine("Database does not exist. Trying to create a new SQLite database file.");\n\n // Try to create the database folder first and then the database file.\n try {\n string fullFolderPath = Path.GetDirectoryName(fullDatabaseFilePath);\n Directory.CreateDirectory(fullFolderPath ?? throw new InvalidOperationException());\n File.Create(fullDatabaseFilePath).Close();\n } catch (Exception e) {\n Console.WriteLine(e);\n throw;\n }\n\n // Check if the database file exists. It should.\n if (!File.Exists(fullDatabaseFilePath)) {\n throw new Exception("Failed to create the database file.");\n }\n\n //Console.WriteLine("SQLite database file created successfully.");\n }\n}\n</code></pre>\n<h3 id=\"maincs\">Main.cs</h3>\n<p>In our test this file resides in your main project - or where ever, but what I’m trying to say, it’s <em><strong>not</strong></em> in the <strong>Database</strong> project in this example.</p><p>The <code>Main.cs</code> represents some kind of controller or other class which does something practical with the database.</p><p>For our purposes we simply want to output something to see that everything works.</p><pre><code class=\"language-cs\">\nusing Database;\nusing Godot;\nusing Microsoft.EntityFrameworkCore;\nusing YourMainProjectNamespace.Database; // (Unless you excluded the database folder)\n\nnamespace YourMainProjectNamespace;\n\n// Oh yes, we're likely in Godot now doing something fun with the database.\npublic partial class Main : Node3D {\n\n /*\n In this example we store a reference to the connection, but normally you might\n just use a using block for the duration of the database operation you want\n to perform. You can do it both ways depending on the requirements.\n */\n private DatabaseConnection _databaseConnection;\n\n public override async void _Ready() {\n\n /*\n Configure the database connection. We need to run configure\n and pass the user data directory from Godot to the database\n class library before we can access the instance.\n (Simply because we happened to code it that way in this example.\n You do what you like. It doesn't matter.)\n */\n DatabaseConnection.Configure(OS.GetUserDataDir());\n _databaseConnection = DatabaseConnection.Instance;\n\n try {\n // Run migrate to create/update the database and tables if they don't exist/aren't up-to-date.\n await _databaseConnection.Database.MigrateAsync();\n \n // Now we can use the database after we've run Migrate. Not before.\n\n // Add test data to the database so we have something to show.\n await AddTestDataEntriesAsync();\n\n // Do something for fun.\n await RunDatabaseTests();\n\n } catch (Exception e) {\n GD.PrintErr(e);\n throw;\n }\n }\n\n /// <summary>\n /// Add test data to the database.\n /// </summary>\n private async Task AddTestDataEntriesAsync() {\n\n // Instantiate test data.\n SaveGameManifest saveGameManifest = new (Guid.NewGuid(), "Test Save Game");\n\n // Add test data to database.\n await DatabaseConnection.Instance.AddAsync(saveGameManifest);\n\n // Save changes to database to disc.\n await DatabaseConnection.Instance.SaveChangesAsync();\n }\n\n /// <summary>\n /// Run database tests to see if it's working.\n /// </summary>\n private async Task RunDatabaseTests() {\n\n // Get data from database and output it.\n Console.WriteLine("Fetching SaveGameManifests from database...");\n\n // Fetch all SaveGameManifest entries from the database table.\n DbSet<SaveGameManifest> results = DatabaseConnection.Instance.SaveGameManifests;\n\n // Output the results.\n\n Console.WriteLine("Results:");\n\n await foreach (SaveGameManifest manifest in results.AsAsyncEnumerable()) {\n Console.WriteLine($"DatabaseId: {manifest.DatabaseId}, SaveName: {manifest.SaveName}, LastSaved: {manifest.LastSaved}");\n }\n\n Console.WriteLine($"Results count: {results.Count()}");\n }\n}\n</code></pre>\n<h1 id=\"database-tab\">Database tab</h1>\n<p>At this point you might like to, or need to, connect the database in the database tab in Rider. Among other things this will allow you to inspect the contents of the SQLite database, which can be very helpful in debugging.</p><h1 id=\"migrations\">Migrations</h1>\n<p>Now that we’re done with all of that, create a <code>Migrations</code> folder in the <strong>Database</strong> project.</p><p>Right click on the <code>Database</code> project in the Solution Explorer and there should be entry for <strong>Entity Framework Core</strong> near the top of the context menu that pops open.</p><p>Click <strong>Add Migration</strong>.</p><p>The name can be anything you like which helps you understand what the migration is.</p><p>Migration project and Startup project should be <code>Database</code>.</p><p>DbContext class should be <code>DatabaseConnection</code>.</p><p>The <code>Migrations</code> folder has to point to the <code>Migrations</code> folder you created.</p><p><code>Target Framework</code> should probably be set to the .NET version you’re using.</p><p>Everything else can be at defaults. Hit OK.</p><p>If all goes well you should see <code>DatabaseConnectionModelSnapshot.cs</code> file being generated and also a file called something like <code>20240702182449_Initial.Designer.cs</code>.</p><p>You should now have a fully functional setup ready for running.</p><h1 id=\"how-to-use-migrations\">How to use migrations?</h1>\n<p>Every time you’ve changed the schema, ie. your tables, columns, added new types, removed columns, tables, changed types, changed names, etc. In other words every time your data definitions change and your database types don’t anymore reflect your types in code, you should run <code>Entity Framework Core > Add Migration</code>.</p><p>This will update the migration path of your data and tell your database how it should update and change between different versions.</p><h1 id=\"problems\">Problems</h1>\n<p>The database will be created in Godot’s <code>user://</code> folder. If you have trouble finding it you can open Godot and go to <code>Editor > Open Editor Data Folder</code> and look it up from there.</p><p>You can always just delete the database file and delete the Migrations files when testing things. Don’t do that in production when you’ve released something. You should only add new migrations then, and never remove them, if they have already been released out to the wild.</p><p>Unless I forgot something or you’ve got a different kind of setup, these instructions should more or less work. I did not, however, specifically go out of my way to test these instructions step by step to insure that they work on a clean system. I wrote the instructions from memory. So there may be factual errors. If that’s the case, you can contact me on Star and Serpent’s Discord. The link is on Star and Serpent’s home page.</p>",
"image": "https://pilvimaa.fi/media/posts/19/Database.png",
"author": {
"name": "Pilvinen"
},
"tags": [
"tutorial",
"sqlite",
"ef core",
"database",
"Godot",
"Csharp"
],
"date_published": "2024-07-03T01:24:09+03:00",
"date_modified": "2024-07-03T01:26:23+03:00"
},
{
"id": "https://pilvimaa.fi/bullet-parenting-trick/",
"url": "https://pilvimaa.fi/bullet-parenting-trick/",
"title": "Bullet parenting trick",
"summary": "In Godot if you have a bullet parented to your player, obviously the bullets will move when the player moves. So you need a node outside of your player hierarchy…",
"content_html": "<p>In Godot if you have a bullet parented to your player, obviously the bullets will move when the player moves.</p><p>So you need a node outside of your player hierarchy to parent them to, eg. something like:</p><pre><code>- World\n - Bullets \n - Player\n - EnemyA\n - EnemyB\n</code></pre>\n<p>This works fine, but can make controlling the bullets a chore due to required boiler plate code.</p><p>But… what if you don’t need to do that?</p><p>If you put a node of type <code>Node</code> inside your Player scene it will break the inheritance hierarchy because Node is such a simple type.</p><p>In that case you can have:</p><pre><code>- Player (Node2D)\n - Bullets (Node)\n - Bullet (Node2D)\n - Bullet (Node2D)\n - Bullet (Node2D)\n - Bullet (Node2D)\n</code></pre>\n<p>And with this the movement of <code>Player</code> won’t affect position of <code>Bullets</code> because the inheritance hierarchy doesn’t work between them.</p>",
"image": "https://pilvimaa.fi/media/posts/18/bullet_hell.png",
"author": {
"name": "Pilvinen"
},
"tags": [
"Inheritance",
"Godot"
],
"date_published": "2024-02-09T11:06:05+02:00",
"date_modified": "2024-02-09T11:06:05+02:00"
},
{
"id": "https://pilvimaa.fi/what-to-return-when-you-dont-have-anything-to-return/",
"url": "https://pilvimaa.fi/what-to-return-when-you-dont-have-anything-to-return/",
"title": "What to return when you don't have anything to return?",
"summary": "Not finding your data that you are trying to fetch via Guid Id can be handled elegantly either as a case of domain error or just as a regular case…",
"content_html": "<p>Not finding your data that you are trying to fetch via <code>Guid</code> <strong>Id</strong> can be handled elegantly either as a case of <strong>domain error</strong> or just as a <strong>regular case</strong> that you’re expecting to happen. We will only go in-depth with domain error in this article and do a quick overview on regular cases.</p><h2 id=\"domain-error\">Domain error</h2>\n<p>When fetching data we can handle domain errors with our own custom <code>Result</code> type which also includes an <strong>error</strong>.</p><p>But what is a “domain error”?</p><p>In software development, a “domain error” happens when there’s a mistake or issue because the rules or limitations of a particular area, or situation, that the software is designed for are not followed properly. For example, if the software is made to handle banking transactions but does something against banking rules, that’s a domain error.</p><p>If you’re working with a system where each entity is uniquely identified by a GUID (Globally Unique Identifier), not finding an entity by its GUID could indicate a more serious issue. This might be because the data doesn’t exist, it’s not accessible for some reason, or there’s an inconsistency in the data integrity.</p><p>In such scenarios, using a <code>Result</code> type that includes an <strong>error</strong> is beneficial. The Result type, commonly found in functional programming - and increasingly in other paradigms - is a way to encapsulate either a successful outcome (with the expected data) or an error (with details about what went wrong). This approach is more informative than simply returning <code>null</code> or an <strong>optional</strong> object because it provides explicit information about the nature of the error, which is critical for debugging and handling exceptional cases properly.</p><p>Handling a returned <code>Result</code> type without resorting to branching logic (like if or switch statements) often involves leveraging higher-order functions or patterns such as monadic binding. In C#, this can be achieved through extension methods that abstract away the branching logic. It’s still there, but hidden away for the most part. You don’t get the branching logic vomited all over your classes which should be focused on other things.</p><p>Let’s consider a hypothetical <code>Result<T, E></code> type, where <code>T</code> is the type of the value in case of success, and <code>E</code> is the type of the error. We will define extension methods like <code>OnSuccess</code> and <code>OnError</code> to handle each case.</p><p>Here’s an example implementation:</p><pre><code class=\"language-csharp\">public class Result<T, E> { \n public T Value { get; private set; } \n public E Error { get; private set; } \n public bool HasValue { get; private set; } \n \n // Constructors \n public Result(T value) { \n Error = default!; // Replace with what you want to do here\n Value = value; \n HasValue = true; \n } \n \n public Result(E error) { \n Error = error; \n Value = default!; // Replace with what you want to do here \n HasValue = false; \n } \n}\n\npublic static class ResultExtensions { \n \n // Extension method for success case. \n public static Result<T, E> OnSuccess<T, E>(this Result<T, E> result, Action<T> action) { \n if (result.HasValue) { \n action(result.Value); \n } \n return result; \n } \n \n // Extension method for error case. \n public static void OnError<T, E>(this Result<T, E> result, Action<E> action) { \n bool errorHasOccurredHasNoValue = !result.HasValue; \n if (errorHasOccurredHasNoValue) { \n action(result.Error); \n } \n } \n \n} \n\npublic sealed class ResultTypeTest { \n \n private readonly Guid _correctId = Guid.NewGuid(); \n private readonly Guid _wrongId = Guid.NewGuid(); \n \n private readonly Database _database; \n \n public ResultTypeTest() { \n _database = new (_correctId); \n } \n \n public void Test() { \n \n // Database has been set up with data that we should be able to fetch with _correctId, \n // whereas _wrongId should return an error because data by that id does not exist. Result<SomeData, DomainError> correctResult = GetData(_correctId); \n Result<SomeData, DomainError> wrongResult = GetData(_wrongId); \n \n correctResult.OnSuccess(data => { \n // Do something with data \n Console.WriteLine($"DEBUG: correctResult: Data fetched successfully, data.Id: {data.Id}"); \n }).OnError(error => { \n // Do something with error \n Console.WriteLine($"DEBUG: correctResult: Error fetching data, error message: {error.Message}"); \n }); \n \n wrongResult.OnSuccess(data => { \n // Do something with data \n Console.WriteLine($"DEBUG: wrongResult: Data fetched successfully, data.Id: {data.Id}"); \n }).OnError(error => { \n // Print error \n Console.WriteLine($"DEBUG: wrongResult: Error fetching data, error message: {error.Message}"); \n }); \n \n } \n \n private Result<SomeData, DomainError> GetData(Guid id) { \n bool dataExists = _database.CheckDataExists(id); \n \n if (dataExists) { \n return new Result<SomeData, DomainError>(_database.data); \n } \n \n return new Result<SomeData, DomainError>(new DomainError("Domain error: Data not found.")); \n } \n \n} \n \n \npublic class Database { \n public SomeData data { get; set; } \n public Database(Guid id) { \n data = new SomeData(id); \n } \n \n public bool CheckDataExists(Guid id) { \n return id == data.Id; \n } \n} \n \npublic class SomeData { \n public Guid Id { get; } \n public SomeData(Guid id) { \n Id = id; \n } \n} \n\npublic class DomainError { \n public string Message { get; } \n public DomainError(string message) { \n Message = message; \n } \n}\n</code></pre>\n<p>In this example, <code>GetData</code> returns a <code>Result<SomeData, DomainError></code>. Depending on whether <code>GetData</code> succeeds or fails, either <code>HandleData</code> or <code>LogError</code> will be executed. The key here is that the <code>OnSuccess</code> and <code>OnError</code> methods encapsulate the branching logic, allowing for a more fluent and declarative style of programming.</p><p>The <code>data => HandleData(data)</code> is a lambda expression that represents an <code>Action<T></code>. It’s a method taking <code>data</code> as a parameter and then calling <code>HandleData</code> with it. Similarly, <code>error => LogError(error)</code> is an <code>Action<E></code>, handling the error case.</p><p>This approach is quite powerful as it separates the concerns of error handling from the main business logic, leading to cleaner and more maintainable code. You can further refine this pattern by adding more methods for chaining, like Map for transforming the result, Bind for monadic operations, etc. This makes the Result type a very flexible tool for robust error handling without resorting to traditional branching logic.</p><p>The provided code snippet demonstrated several programming techniques and concepts:</p><ol>\n<li><p><strong>Encapsulation and Monadic Design Pattern</strong>: The <code>Result<T, E></code> class demonstrates encapsulation by containing both success and error states along with their values. This approach, akin to a monadic design pattern, organizes state handling within a structured object, avoiding dispersed code management. While not a full monad, <code>Result</code> mimics monadic aspects by providing methods to process values or errors without manual state checks.</p></li>\n<li><p><strong>Fluent Interface and Method Chaining</strong>: The <code>Result</code> class employs a fluent interface through method chaining. The methods <code>OnSuccess</code> and <code>OnError</code> return the <code>Result</code> object itself, allowing for chaining multiple methods in a single statement. This design enhances code readability and conciseness, characteristic of fluent interfaces.</p></li>\n<li><p><strong>Delegation and Higher-Order Functions</strong>: <code>OnSuccess</code> and <code>OnError</code> serve as higher-order functions, taking <code>Action<T></code> and <code>Action<E></code> delegates as parameters. They exemplify delegation by passing execution based on the <code>Result</code> object’s state to these provided action functions. This pattern allows for flexible and dynamic handling of different execution scenarios.</p></li>\n<li><p><strong>Lambda Expressions and Conditional Execution</strong>: Lambda expressions like <code>data => HandleData(data)</code> and <code>error => LogError(error)</code> in C# provide concise representations of anonymous methods. The implementation of <code>OnSuccess</code> and <code>OnError</code> involves conditional execution, determining action invocation based on the <code>Result</code> object’s success state, often utilizing these lambda expressions for inline logic definition.</p></li>\n</ol>\n<h2 id=\"regular-case\">Regular case</h2>\n<p>Default value such as Optional object can help to recover from not finding the Guid Id.</p><p>If the absence of data corresponding to a GUID is a regular occurrence and not indicative of a deeper issue, then using an optional object like <code>Option<T></code> is a more appropriate approach. <code>Option<T></code> is a container that either holds a value of type <code>T</code> (representing the presence of data) or is empty (representing the absence of data).</p><p>This approach is particularly useful in cases where the absence of data is a normal - an expected part of the application’s flow. For example if a user is searching for a record that doesn’t exist, it isn’t necessarily an error. It could also mean that the record hasn’t been created yet. By using <code>Option<T></code>, you can handle these scenarios without resorting to <code>null</code> checks or throwing exceptions. It allows the calling code to handle the case of missing data, perhaps by taking alternative actions or providing a default value.</p><p>I won’t go into details about this. But <code>Option<T></code> is available, for example, from the popular function library <code>LanguageExt</code>.</p>",
"image": "https://pilvimaa.fi/media/posts/17/nothing_to_return-2.png",
"author": {
"name": "Pilvinen"
},
"tags": [
],
"date_published": "2023-11-23T18:33:04+02:00",
"date_modified": "2023-11-23T20:10:24+02:00"
},
{
"id": "https://pilvimaa.fi/godot-control-node-mouse-input-handling-order/",
"url": "https://pilvimaa.fi/godot-control-node-mouse-input-handling-order/",
"title": "Godot Control node mouse input handling order",
"summary": "Godot mouse input handling is a source of lot of confusion. The basic idea is that Mouse Filter set to Ignore ignores the element. Stop processes the received event and…",
"content_html": "<p>Godot mouse input handling is a source of lot of confusion.</p><p>The basic idea is that <strong>Mouse Filter</strong> set to <code>Ignore</code> ignores the element. <code>Stop</code> processes the received event and doesn’t pass it along. It stops there. While <code>Pass</code> handles the event but then passes it along so other nodes can process it.</p><p>Where most of the confusion happens is trying to figure out in what order the mouse input events get processed.</p><p>Godot handles the input in nodes in reverse depth-first order.</p><p>In other words the order is:</p><ol>\n<li>Bottom to top (ie. reverse)</li>\n<li>Children first (ie. depth).</li>\n</ol>\n<h1 id=\"tree-order-example\">Tree order example</h1>\n<pre><code>- Last\n - Sixth\n - Fifth\n - Fourth\n - Third\n - Second\n - First\n</code></pre>\n<p>One of the more important things to understand is that <em><strong>sibling nodes DO NOT react to Mouse Filter being set to <code>Pass</code>!!!</strong></em></p><p>When a node is <code>Pass</code>ing event forward it <strong>ONLY</strong> passes it to its direct parent.</p><p>And of course only elements affected by the mouse clicking - or other mouse input events - are processed in the first place. You can’t <code>Pass</code> event forward to something that wouldn’t receive an event to begin with!</p><h1 id=\"using-pass-an-example\">Using Pass, an example</h1>\n<p>Let’s assume a situation where we have a button that we want to press, and we also want to detect when the mouse enters and leaves the window - we use the <code>MouseEntered</code> and <code>MouseExited</code> events set up for that and the detection element covers the whole screen. OK, so.</p><p>This doesn’t work:</p><pre><code>- SceneRoot (Control)\n - Button (Texturebutton)\n - MouseDetectionElement (Control)\n</code></pre>\n<p>Why? </p><p>Because in this case <code>MouseDetectionElement</code> will block clicks to <code>Button</code> if it has its <code>MouseFilter</code> set to <code>Stop</code> and <code>Pass</code>. And if it’s set to <code>Ignore</code> then it’s just inactive and doesn’t perform the function we would like it to do.</p><p>This won’t improve the situation:</p><pre><code>- SceneRoot (Control)\n - MouseDetectionElement (Control)\n - Button (Texturebutton)\n</code></pre>\n<p>Now we can click the <code>Button</code>, but <code>MouseDetectionElement</code> will generate erroneous mouse entered and mouse exited events whether it’s set to <code>Pass</code> or <code>Stop</code> because when the mouse moves over the <code>Button</code>, it is counted as exiting/entering the <code>MouseDetectionElement</code>. It’s not what we want here.</p><p>The correct solution is to make the <code>MouseDetectionElement</code> part of the hierarchy so that the <code>Button</code> can <code>Pass</code> the events forward to its parent, the <code>MouseDetectionElement</code>:</p><pre><code>- SceneRoot (Control)\n - MouseDetectionElement (Control)\n - Button (Texturebutton)\n</code></pre>\n<p>Here <code>Button</code> is processed first and with its <strong>Mouse Filter</strong> is set to <code>Pass</code> it will both:</p><ol>\n<li>Process the mouse events </li>\n<li>and pass them along to its parent, the <code>MouseDetectionElement</code>.</li>\n</ol>\n<p>The <code>MouseDetectionElement</code> can then on its turn handle all the events correctly.</p>",
"image": "https://pilvimaa.fi/media/posts/16/GodotMouseInput.jpeg",
"author": {
"name": "Pilvinen"
},
"tags": [
"MouseFilter",
"Mouse",
"InputEvent",
"Godot"
],
"date_published": "2023-11-01T21:09:44+02:00",
"date_modified": "2023-11-01T21:12:20+02:00"
},
{
"id": "https://pilvimaa.fi/gdscript-vs-c-in-godot-which-language-should-you-use/",
"url": "https://pilvimaa.fi/gdscript-vs-c-in-godot-which-language-should-you-use/",
"title": "GDScript vs. C# in Godot: Which language should you use?",
"summary": "Godot is a powerful and versatile game engine that supports two scripting languages: GDScript and C#. Both languages have their own advantages and disadvantages, so it’s important to choose the…",
"content_html": "<p>Godot is a powerful and versatile game engine that supports two scripting languages: GDScript and C#. Both languages have their own advantages and disadvantages, so it’s important to choose the one that’s right for you.</p><h1 id=\"official-support\">Official support</h1>\n<p>Both GDScript and C# are officially supported by the Godot team. This means that both languages have equal access to the Godot API and documentation.</p><h1 id=\"popularity\">Popularity</h1>\n<p>GDScript is by far the more popular language in Godot. It’s supported by a large community of developers. C#, on the other hand, is a newer addition to Godot, but it’s quickly gaining popularity, especially among developers who are already familiar with the language.</p><h1 id=\"tutorials-and-resources\">Tutorials and resources</h1>\n<p>There are more tutorials and resources available for GDScript than for C#. This is because GDScript has been around for longer, and it’s the default language for Godot. However, the C# community is growing rapidly, and more tutorials and resources are becoming available all the time.</p><h1 id=\"your-existing-skills-matter\">Your existing skills matter</h1>\n<p>Your existing skill set and personal preferences are the most important factors to consider when choosing between GDScript and C#. </p><p>If you’re already familiar with C#, or if you have experience with other statically typed languages, then C# will be a more natural choice for you. You’ll be able to get started quickly, and you’ll be able to leverage your existing knowledge and skills.</p><p>On the other hand, if you’re new to programming, or if you have experience with dynamically typed languages like Python, then GDScript may be a better choice for you. GDScript is easier to learn, and it has a more forgiving syntax.</p><h1 id=\"ease-of-prototyping\">Ease of prototyping</h1>\n<p>GDScript is generally considered to be easier to prototype with than C#. This is because GDScript has a more relaxed syntax, and it doesn’t require as much boilerplate code. C#, on the other hand, is a more statically typed language, which can make it more difficult to prototype quickly.</p><h1 id=\"applicability-beyond-godot\">Applicability beyond Godot</h1>\n<p>C# is a more widely applicable language than GDScript. C# is the primary language used in the Unity game engine, and it’s also used in a variety of other game development tools and libraries. GDScript, on the other hand, is specific to the Godot game engine.</p><h1 id=\"syntax-and-style\">Syntax and style</h1>\n<p>GDScript is a Python-like language, with a simple and easy-to-read syntax. C#, on the other hand, is a more verbose language with a more traditional C-style syntax.</p><h1 id=\"type-safety\">Type safety</h1>\n<p>GDScript has a level of optional type safety. This means that you can choose to use type hints to make your code more type-safe, but it’s not required. C#, on the other hand, is a statically typed language, which means that all variables and expressions must have explicitly defined types.</p><h1 id=\"static-vs-dynamic-typing\">Static vs. dynamic typing</h1>\n<p>Static typing can help to prevent errors and make your code more maintainable. However, it can also make your code more verbose and difficult to prototype with. Dynamic typing, on the other hand, can make your code more concise and easier to prototype with, but it can also lead to more errors.</p><h1 id=\"ides\">IDEs</h1>\n<p>C# has several professional IDEs available, such as Rider, Visual Studio and Visual Studio Code. GDScript, on the other hand, doesn’t have any dedicated IDEs. However, GDScript can be used with any text editor, and there are several plugins available that provide IDE-like features, such as syntax highlighting, code completion, and debugging.</p><h1 id=\"ecosystem\">Ecosystem</h1>\n<p>The .NET ecosystem is massive in comparison to the GDScript ecosystem. This means that there are a lot more libraries and tools available for C# developers.</p><h1 id=\"debugging\">Debugging</h1>\n<p>It’s generally easier to get hard to fix runtime bugs in GDScript than in C#. This is because GDScript is dynamically typed, so you can inspect and modify variables at runtime. C#, on the other hand, is statically typed, so it can be more difficult to debug runtime errors.</p><h1 id=\"using-both-gdscript-and-csharp\">Using both GDScript and Csharp</h1>\n<p>It is possible to use both C# and GDScript in the same Godot project (but definitely not required). This can be useful for a variety of reasons, such as:</p><p>You could leverage the strengths of both languages. For example, you could use C# (or even C++) for performance-critical code, and GDScript for prototyping and scripting simple game mechanics.</p><p>However, there are also some potential drawbacks to using both C# and GDScript in the same project:</p><p>It can be more difficult to maintain a project that uses multiple languages. This is because you need to be aware of the differences between the two languages, and you need to make sure that your code is compatible with both languages.</p><p>It can be more difficult to debug a project that uses multiple languages. This is because you need to be able to debug code written in both languages.</p><h2 id=\"language-interoperability\">Language interoperability</h2>\n<p>C# code within a Godot project can be difficult to remove once it is introduced. This is because GDscript calling into C# is good, idiomatic GDscript. However, C# calling into GDscript is bad C#, as it requires referencing functions by string. This can make your code more difficult to maintain and debug.</p><p>In other words, once you start using C# code in your Godot project, it can be difficult to go back. This is because GDscript is designed to make it easy to call C# code, but C# is not designed to make it easy to call GDscript code.</p><p>If you are considering using multiple languages in your Godot project, I recommend that you think carefully about whether or not you need to use C#. If you do need to use C#, try to limit the amount of code that you call.</p><h1 id=\"performance\">Performance</h1>\n<p>A lot of new developers coming to Godot often worry about performance, so let’s talk about that for a bit.</p><h2 id=\"gdscript-vs-csharp-speed\">GDScript vs. Csharp speed</h2>\n<p>C# is generally faster than GDScript, but this is not true in all circumstances and all situations.</p><p>Marshalling can add overhead to C# code, especially when calling native Godot functions.</p><p>Marshalling is the process of converting data between different programming languages. Godot is written in C++. When you call a native Godot function from C#, the .NET runtime needs to marshal the data between the two languages. This can add overhead to your code, especially if you’re calling native functions frequently.</p><p>GDScript, on the other hand, doesn’t need to marshal data when calling native Godot functions. This is because GDScript is built on top of the Godot engine, and it has direct access to the Godot API.</p><p>As a result, GDScript code can sometimes be faster than C# code, especially when calling native Godot functions frequently.</p><h2 id=\"does-it-really-matter\">Does it really matter</h2>\n<p>If you’re developing a performance-critical game, then C# may be a better choice. </p><p>But for most games, the difference in performance between GDScript and C# will be negligible.</p><p>You can always write performance critical parts of your game in C++ if you find it necessary. It’s always an option whether you choose GDScript or C#.</p><p>About marshalling specifically, you can avoid any major problems simply by being mindful of the fact that marshalling happens and avoiding excessive and unnecessary back and forth between C# and Godot.</p><p>Marshalling overhead is typically only significant in performance-critical applications, and you’re likely to hit other more critical bottle necks way before that happens. </p><p>Know the scale of your game, know your skillset, know your personal preferences. There are a lot of things to consider when choosing a language and performance is only one of those.</p><h1 id=\"final-words\">Final words</h1>\n<p>If you’re new to game development, or if you’re looking for a language that is easy to prototype with, or you’re already familiar with Python then GDScript is a good choice.</p><p>If you’re already familiar with C#, or if you need a language with better performance or a wider ecosystem, then C# is a good choice.</p><p>Ultimately it comes down to personal preference.</p>",
"image": "https://pilvimaa.fi/media/posts/15/csharp_vs_gdscript_godot.png",
"author": {
"name": "Pilvinen"
},
"tags": [
"gdscript",
"Godot",
"C#"
],
"date_published": "2023-10-16T18:47:16+03:00",
"date_modified": "2023-10-16T19:18:04+03:00"
},
{
"id": "https://pilvimaa.fi/node2d-double-click-detection-in-godot/",
"url": "https://pilvimaa.fi/node2d-double-click-detection-in-godot/",
"title": "Node2D double click detection in Godot",
"summary": "Clicks for Node2D based nodes can easily be detected by using CollisionObject2D‘s input_event signal. To capture the mouse clicks we can add an Area2D node and a CollisionShape2D or CollisionPolygon2D…",
"content_html": "<p>Clicks for <code>Node2D</code> based nodes can easily be detected by using <code>CollisionObject2D</code>‘s <code>input_event</code> signal.</p><p>To capture the mouse clicks we can add an <code>Area2D</code> node and a <code>CollisionShape2D</code> or <code>CollisionPolygon2D</code> as its child node. </p><p>Since we are using <code>CollisionObject2D</code>‘s <code>input_event</code> signal directly the <code>Area2D</code>‘s <code>Monitoring</code> and <code>Monitorable</code> won’t be used and we can disable those.</p><p><code>Area2D</code>‘s ‘<code>Collision > Layer</code> needs to be set to some value or the clicks won’t be detected.</p><p>The <code>Area2D</code> node also needs to have <code>Input > Pickable</code> set to <code>True</code>.</p><p>Give the <code>CollisionShape2D</code> a <code>Shape</code>, eg. <code>RectangleShape2D</code>, <code>CircleShape2D</code>, <code>CapsuleShape2D</code>, etc. and set its <code>Size</code> to the dimensions you want. This defines the area’s size and shape that can be clicked with the mouse. </p><p>Finally set the <code>CollisionShape2D</code>‘s <code>Transform > Position</code> to the location where you want it.</p><p>Now we can add a script to the <code>Area2D</code> node and in <code>Area2D</code>‘s <code>Node > Signals</code> connect the <code>input_event</code> to the script.</p><p>See example below.</p><pre><code class=\"language-cs\">public void OnContainerBeingClicked(Node viewport, InputEvent @event, int shapeIdx) { \n \n // Return if not mouse left button double click. \n if (@event is not InputEventMouseButton mouseButtonEvent) return; \n if (!mouseButtonEvent.Pressed) return; \n if (mouseButtonEvent.ButtonIndex != MouseButton.Left) return; \n if (!mouseButtonEvent.DoubleClick) return; \n \n ToggleContainer(); \n}\n</code></pre>\n<p>The code is pretty self-explanatory, but let’s break it down.</p><p>In the method signature we need to return <code>void</code>, and accept <code>Node</code>, <code>InputEvent</code>, and <code>int</code> as parameters - even if we don’t use them all. It’s simply required to connect the signal.</p><p>Since <code>event</code> is a reserved keyword we are required to place <code>@</code> in front of it if we want to use that particular name in our parameters, ie. <code>@event</code> instead of <code>event</code>. But we might as well use any other name such as <code>inputEvent</code> if it strikes your fancy - it really doesn’t matter. The parameter names can be what ever you want as long as the types match <code>Node</code>, <code>InputEvent</code> and <code>int</code>. The signal will still work.</p><p>We cannot directly handle <code>InputEventMouseButton</code>, so we need to use <code>InputEvent</code> instead and cast it to <code>InputEventMouseButton</code>:</p><pre><code class=\"language-cs\">if (@event is not InputEventMouseButton mouseButtonEvent) return; \n</code></pre>\n<p>Here we check whether <code>@event</code> is or isn’t <code>InputEventMouseButton</code>. If it’s not we simply return and do nothing further with that particular input event - someone else can handle that one, what ever it is.</p><p>If the <code>@event</code> is <code>InputEventMouseButton</code> we cast it as <code>InputEventMouseButton</code> and expose the cast as a local variable called <code>mouseButtonEvent</code> and continue executing our code. We can now access the <code>InputEventMouseButton</code> mouse button event via <code>mouseButtonEvent</code> and do further things.</p><pre><code class=\"language-cs\">if (!mouseButtonEvent.Pressed) return;\n</code></pre>\n<p>Here we immediately put it to use and check if the mouse button is not being pressed (ie. it’s likely being released instead), we will simply return and call it quits there - it’s not our concern.</p><pre><code class=\"language-cs\">if (mouseButtonEvent.ButtonIndex != MouseButton.Left) return;\n</code></pre>\n<p>We still don’t know what kind of mouse button press this was, so we can check by using the <code>ButtonIndex</code> whether it was something else than a <strong>left</strong> mouse button press - in which case we simply return and call it quits again. It’s not our concern, since in this example we want to handle left mouse buttons clicks only.</p><pre><code class=\"language-csharp\">if (!mouseButtonEvent.DoubleClick) return;\n</code></pre>\n<p>Finally we have a very handy way of checking whether a double click happened without having to deal with timers and special logic each time - we can simply check the <code>DoubleClick</code> property. Godot will expose to us automatically the information whether it was a double click or not. If it’s not a double click, again, we return and call it quits there.</p><p>Now we’ve determined:</p><ol>\n<li>It is a mouse button event.</li>\n<li>It is a mouse button being pressed down event.</li>\n<li>It is a left mouse button event.</li>\n<li>It is a double click</li>\n</ol>\n<p>So we know the user did a left mouse button double click, so we can now do what ever we want with that information.</p><pre><code class=\"language-csharp\">ToggleContainer();\n</code></pre>\n<p>In the above example what we do is we call our own custom <code>ToggleContainer()</code> method which opens - or closes - an inventory container window for us.</p><p>But you can call your own methods or do what ever you want once you’ve ruled out all the cases you don’t want to react to like we did above one step at a time.</p><p>You can also combine the if-statements if you like. We have kept them separate in the example for additional clarity and readability.</p><p>But you might also do this:</p><pre><code class=\"language-csharp\">if (@event is not InputEventMouseButton mouseButtonEvent \n || !mouseButtonEvent.Pressed \n || mouseButtonEvent.ButtonIndex != MouseButton.Left \n || !mouseButtonEvent.DoubleClick) { \n return; \n}\n</code></pre>\n<p>The IL code produced by either of these examples is slightly different, but not meaningfully so.</p><p>It’s also worth noting that when using <code>return</code>s, like in the first example, the stack traces can be more meaningful when tracking down problems.</p><p>But generally the second example would execute faster. But this would be in the realm of nano optimizations and might be made a moot point anyway by future updates to the runtime.</p><p>It’s also worth noting that in Godot 4 you can implicitly cast the <code>Node</code> by accepting <code>Viewport</code> instead of <code>Node</code> in the signal’s method signature as a parameter - and it will still work because <code>Viewport</code> is a child of <code>Node</code>.</p><p>So if you want to handle the input, for example, so it doesn’t propagate any further - and you don’t want to cast the <code>Node</code> in your code explicitly to <code>Viewport</code> which you need to access the <code>SetInputAsHandled()</code> method, you can accept a <code>Viewport</code> directly instead of <code>Node</code> which is declared in the <code>input_event</code> signal’s signature.</p><p>Eg.</p><pre><code class=\"language-csharp\">public void OnContainerBeingClicked(Viewport viewport, InputEvent @event, int shapeIdx) { \n \n // Return if not mouse left button double click. \n if (@event is not InputEventMouseButton mouseButtonEvent) return; \n if (!mouseButtonEvent.Pressed) return; \n if (mouseButtonEvent.ButtonIndex != MouseButton.Left) return; \n if (!mouseButtonEvent.DoubleClick) return; \n \n viewport.SetInputAsHandled(); \n ToggleContainer(); \n}\n</code></pre>\n<p>This will also work. Otherwise we would have to:</p><pre><code class=\"language-csharp\">public void OnContainerBeingClicked(Node viewport, InputEvent @event, int shapeIdx) { \n \n // Return if not mouse left button double click. \n if (@event is not InputEventMouseButton mouseButtonEvent) return; \n if (!mouseButtonEvent.Pressed) return; \n if (mouseButtonEvent.ButtonIndex != MouseButton.Left) return; \n if (!mouseButtonEvent.DoubleClick) return; \n \n ((Viewport)viewport).SetInputAsHandled(); \n ToggleContainer(); \n}\n</code></pre>\n<p>That’s mostly it for handling mouse double clicks in Node2D nodes.</p>",
"image": "https://pilvimaa.fi/media/posts/14/computer_mice_double_click.png",
"author": {
"name": "Pilvinen"
},
"tags": [
"InputEvent",
"Input",
"Godot",
"Csharp",
"C#"
],
"date_published": "2023-06-14T02:08:31+03:00",
"date_modified": "2023-06-14T02:08:31+03:00"
},
{
"id": "https://pilvimaa.fi/implicit-and-explicit-conversion-operators/",
"url": "https://pilvimaa.fi/implicit-and-explicit-conversion-operators/",
"title": "Implicit and explicit conversion operators",
"summary": "Implicit and explicit conversion operators allow you to ingegrate your custom types seamlessly with other types by doing implicit or explicit conversions from one type to another. public void SetPositionFromVector3(Vector3…",
"content_html": "<p>Implicit and explicit conversion operators allow you to ingegrate your custom types seamlessly with other types by doing implicit or explicit conversions from one type to another.</p><pre><code class=\"language-cs\"> public void SetPositionFromVector3(Vector3 vector) {\n // Do stuff.\n }\n\n MyType myType = new MyType(0,0,0);\n SetPositionFromVector3(myType); // Argument type 'MyType' is not assignable to parameter type 'Vector3'\n</code></pre>\n<p>If you’ve ever experienced one of those situations where you have your awesome custom type <code>MyType</code> which is essentially a <code>Vector3</code>, or what ever, with some extra spices that you really need … but now you can’t pass it to anything that really wants a <code>Vector3</code>. And you end up doing all kinds of weird things like exposing a special property or using inheritance and polymorphism to get it working… </p><p>Do not fret! We’ll have none of those shenanigans. <code>implicit</code> and <code>explicit</code> conversion operators to the rescue!</p><p>Let’s look at a simplification of how <code>implicit</code> operator is used.</p><pre><code class=\"language-cs\">class MyType {\n private Vector3 _myValue;\n public float x => _myValue.x;\n public float y => _myValue.x;\n public float z => _myValue.x;\n public static implicit operator Vector3(MyType myType) => _myvalue;\n // ^ ^ ^ ^ ^ ^-- Input type ^-- Return value\n // | | | | `-- Output type\n // `----`-------`--------`-- Magical keywords\n}\n</code></pre>\n<p>That’s how you get it working. But lets examine this declaration word by word and break it apart.</p><p>All the operators have to be declared <code>public</code> and they also have to be <code>static</code>. Next we declare the <code>implicit</code> or <code>explicit</code> keyword. What <code>implicit</code> means is basically “Don’t ask stupid questions, just do the conversion for me - <em>implicitly</em>, automatically, ie. it is <em>implied</em>.” (The <code>explicit</code> keyword will be explained further down below). Next up we have to use the <code>operator</code> keyword which allows overloading existing C# operators. Then we have <code>Vector3</code> as the type which we overload, ie. essentially our “return type” if you allow such a simplification. In the parameters we have the type we are converting from. In our function body we define how the correct value gets returned. In this example we simply return the value from the private field <code>_myValue</code>.</p><p>The <code>explicit</code> keyword works in pretty much the same way as the <code>implicit</code> keyword, except you have to do the casting yourself, <em>explicitly</em>, when you use it, eg.</p><pre><code class=\"language-cs\"> MyType myType = new MyType(0,0,0);\n SetPositionFromVector3((Vector3) myType); // explicit casting is required with explicit keyword.\n</code></pre>\n<p>Instead of implicitly as shown below.</p><pre><code class=\"language-cs\"> MyType myType = new MyType(0,0,0);\n SetPositionFromVector3(myType); // with implicit keyword casting is done automatically.\n</code></pre>\n<p>NOTE: If you decide to use the <code>implicit</code> keyword, you have to be careful because it will be less obvious what is going on in the code.</p><p>To do the conversion the other way around, ie. in our example from <code>Vector3</code> to <code>MyType</code>, we can simply switch the places of the types and make sure somehow that the correct type and values are returned.</p><pre><code class=\"language-cs\">class MyType {\n private Vector3 _myValue;\n // This is what we did before.\n public static implicit operator Vector3(MyType myType) => _myvalue;\n // Here we switched things around.\n public static implicit operator MyType(Vector3 myType) => new Vector3(myType.x, myType.z, myType.z);\n}\n</code></pre>\n",
"image": "https://pilvimaa.fi/media/posts/13/Spaghetti.jpg",
"author": {
"name": "Pilvinen"
},
"tags": [
"Implicit",
"Explicit",
"Conversion",
"C#"
],
"date_published": "2022-07-29T16:15:52+03:00",
"date_modified": "2022-07-30T10:25:33+03:00"
},
{
"id": "https://pilvimaa.fi/unit-testing-private-methods-through-extraction/",
"url": "https://pilvimaa.fi/unit-testing-private-methods-through-extraction/",
"title": "Unit testing private methods through extraction",
"summary": "When you use unit tests you have to intentionally write code that is testable. What about private methods? How do you test those? And no, you should NOT change the…",
"content_html": "<p>When you use unit tests you have to <em><strong>intentionally</strong></em> write code that is testable.</p><p>What about <code>private</code> methods? How do you test those?</p><p>And no, you <em><strong>should NOT</strong></em> change the accessibility of your methods (eg. <code>internal</code>, <code>public</code>, etc.) to make your code testable as you would lose your code’s correctness - there’s a reason why those <code>private</code> methods have been made <code>private</code>!</p><p>There are several ways to approach this problem. For example you could use the <code>PrivateObject</code> class. Or you could use <strong>reflection</strong>. </p><p>In this article, however, we are going to take a look at using <strong>extraction</strong> and good coding practices to make our <code>private</code> methods more accessible while also retaining our code’s correctness.</p><p>Let’s assume a situation where</p><pre><code class=\"language-cs\">public class Player {\n \n private void Attack() {\n System.Console.WriteLine("Enemy takes damage!");\n }\n \n private void Move() {\n System.Console.WriteLine("You moved!");\n }\n \n public override void _PhysicsProcess(float delta) {\n Attack();\n Move();\n }\n \n}\n</code></pre>\n<p>You can’t test the above methods, <code>Attack()</code> and <code>Move()</code>, because they are <code>private</code> and not exposed to the outside world. But you also want to keep it that way, it’s an important requirement.</p><p>Making the methods <code>public</code> would be bad. Using reflection to test the methods would work, but it’s not fun nor a good approach in general.</p><p>Let’s use <strong>method extraction</strong> instead and turn those methods into <strong>abstractions</strong>.</p><pre><code class=\"language-cs\">public class RefactoredPlayer {\n private Attacker attacker;\n private Mover mover;\n\n public override void _PhysicsProcess(float delta) {\n attacker.Attack();\n mover.Move();\n }\n}\n</code></pre>\n<p>What we’ve done here is we’ve refactored the <code>Player</code> class and extracted the <code>Attack()</code> and <code>Move()</code> methods into their own classes, <code>Attacker</code> and <code>Mover</code>. Now the <code>RefactoredPlayer</code> describes only the <em>flow of the code</em> and not it’s <em>implementation</em>, thus allowing us to keep the composed <code>attacker</code> and <code>mover</code> objects in the <code>RefactoredPlayer</code> class <code>private</code> while exposing the abstractions as <code>public</code> (see below).</p><pre><code class=\"language-cs\">public abstract class Attacker {\n public abstract void Attack();\n}\n\npublic abstract class Mover {\n public abstract void Move();\n}\n</code></pre>\n<p><strong>IMPORTANT:</strong> We don’t have to test the <code>RefactoredPlayer</code> class anymore, we can now test the <em><strong>actual implementations</strong></em> of <code>Attacker</code> and <code>Mover</code> or the <em><strong>abstract classes</strong></em> themselves (for that you need to make an anonymous class implementation of your abstract class as you can’t instantiate an abstract class). Which one you want to do depends mostly on whether your actual implementations have extra features beyond the promises made in the <code>abstract</code> classes or not.</p><p>As a bonus you can now have several implementations of <code>Attacker</code> and <code>Mover</code> and depend upon <strong>abstractions</strong> instead of concrete implementations giving your <code>RefactoredPlayer</code> class less reasons to change and your code becomes more flexible.</p><pre><code class=\"language-cs\">public class SwordAttack : Attacker {\n public override void Attack() {\n System.Console.WriteLine("You skewer the enemy with your sword!");\n }\n}\n</code></pre>\n<p>Here we have an example of an actual implementation of one of our abstract classes. We would still want to depend upon the abstraction <code>Attacker</code> rather than the implementation <code>SwordAttack</code> - to make our code more fluid and easier to change. This way we don’t have to change our <code>RefactoredPlayer</code> class if our implementation changes or gets swapped out to something else that is also implementing the <code>abstract</code> class <code>Attacker</code>.</p>",
"image": "https://pilvimaa.fi/media/posts/12/Bugs.jpg",
"author": {
"name": "Pilvinen"
},
"tags": [
"Unit Testing",
"C#"
],
"date_published": "2022-07-24T14:32:10+03:00",
"date_modified": "2022-07-24T14:43:32+03:00"
},
{
"id": "https://pilvimaa.fi/getting-godotxunit-up-and-running-with-rider/",
"url": "https://pilvimaa.fi/getting-godotxunit-up-and-running-with-rider/",
"title": "Getting GodotXUnit up and Running with Rider",
"summary": "Installation from Github These instructions will explain how to get GodotXUnit integrated to your project and working with Rider. [XunitTestCaseDiscoverer("GodotXUnitApi.Internal.GodotFactDiscoverer", "GodotXUnitApi")] And replace the GodotXUnitApi with your project’s assembly name,…",
"content_html": "<h2 id=\"installation-from-github\">Installation from Github</h2>\n<p>These instructions will explain how to get GodotXUnit integrated to your project and working with Rider.</p><ol>\n<li>Clone the <code>Master</code> branch of the GodotXUnit project in some temporary folder:\n<code>git clone https://github.com/fledware/GodotXUnit.git</code></li>\n<li>From the freshly cloned project, copy the contents of the <code>addons</code> folder into your project’s <code>addons</code> folder - or if that doesn’t exist yet then simply copy the whole <code>addons</code> folder itself to your Godot project’s root. After doing this you can delete the rest of the files from the cloned project, you don’t need them.</li>\n<li>Delete any <code>.csproj</code> files you can find under <code>addons/GodotXUnit</code> and its sub-folders. At the time of writing this there should be only one <code>.csproj</code> located at <code>addons/GodotXUnit/GodotXUnitApi/GodotXUnitApi.csproj</code>. Delete it. With this installation method the GodotXUnit will become a part of your own project, so there’s no need to have any other <code>.csproj</code> files lying around.</li>\n<li>In the file <code>addons/GodotXUnit/GodotXUnitApi/GodotFactAttribute.cs</code> find a line that says:</li>\n</ol>\n<pre><code class=\"language-xml\">[XunitTestCaseDiscoverer("GodotXUnitApi.Internal.GodotFactDiscoverer", "GodotXUnitApi")]\n</code></pre>\n<p>And replace the <code>GodotXUnitApi</code> with your project’s assembly name, eg.</p><pre><code class=\"language-xml\">[XunitTestCaseDiscoverer("GodotXUnitApi.Internal.GodotFactDiscoverer", "MyAwesomeGodotProject")]\n</code></pre>\n<p>You have to do this because GodotXUnit will scan your project for test cases and it needs to know the assembly to scan. If you <em><strong>don’t</strong></em> do this GodotXUnit will not find your test cases. </p><ol start=\"6\">\n<li>Add these dependencies to your project’s <code>.csproj</code></li>\n</ol>\n<pre><code class=\"language-xml\"><ItemGroup>\n <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />\n <PackageReference Include="xunit" Version="2.4.1" />\n <PackageReference Include="xunit.runner.utility" Version="2.4.1" />\n</ItemGroup>\n</code></pre>\n<p>Now you should be good to go.</p><h2 id=\"running-the-tests\">Running the tests</h2>\n<p>Annotate your tests with <code>[GodotFact]</code> and they should work directly from Rider.</p><p>If you want to write anything that uses the <strong>Godot Engine</strong>, make sure you make a <strong>base class</strong> for these tests and annotate it with a <strong>Collection attribute</strong>, as shown in the example below.</p><pre><code class=\"language-cs\">// super important - this prevents the tests from running in parallel.\n// if they would run in parallel, they would interfere with each other.\n[Collection("Integration Tests")] public abstract class BaseTest : IAsyncLifetime\n</code></pre>\n<p>And when <strong>waiting</strong> for things:</p><pre><code class=\"language-cs\">\n// Then within 5 seconds the player should be dead because\n// the monster will attack the player.\n await GetTree().WithinSeconds(5, () => {\n // This assertion will be repeatedly run every frame\n // until it either succeeds or the 5 seconds have elapsed.\n Assert.True(arena.Player.IsDead);\n });\n</code></pre>\n<p>Generally you can follow any instructions you can find for <strong>XUnit</strong>. The only real difference aside from the cases above is that you use <code>[GodotFact]</code> instead of <code>[Fact]</code>.</p><h2 id=\"more-information\">More information</h2>\n<p>Check out the GodotXUnit Github page: \n<a href=\"https://github.com/fledware/GodotXUnit\">https://github.com/fledware/GodotXUnit</a></p>",
"image": "https://pilvimaa.fi/media/posts/11/Test.jpg",
"author": {
"name": "Pilvinen"
},
"tags": [
"XUnit",
"Unit Testing",
"GodotXUnit",
"Godot",
"C#"
],
"date_published": "2022-07-18T17:54:14+03:00",
"date_modified": "2022-07-18T17:54:14+03:00"
},
{
"id": "https://pilvimaa.fi/axis-aligned-bounding-boxes-and-intersections/",
"url": "https://pilvimaa.fi/axis-aligned-bounding-boxes-and-intersections/",
"title": "Axis Aligned Bounding Boxes and Intersections",
"summary": "Let’s do a quick overview of AABBs and intersections. Axis Aligned Bounding Box is a set of three segments (or 6 numbers). AABBs can be used for fast overlapping tests.",
"content_html": "<p>Let’s do a quick overview of AABBs and intersections.</p><p>Axis Aligned Bounding Box is a set of three segments (or 6 numbers). AABBs can be used for fast overlapping tests.</p><p>In one dimension it is a <code>Segment</code> or <code>AxisAlignedBounds1D</code>:</p><pre><code class=\"language-cs\">struct Segment {\n public float min;\n public float max;\n}\n</code></pre>\n<p>Let’s calculate an intersection for two segments.</p><pre><code class=\"language-cs\">Segment Intersect(Segment a, Segment b) =>\n new Segment {\n Min = Math.Max(a.Min, b.Min),\n Max = Math.Min(a.Max, b.Max)\n };\n</code></pre>\n<p>In two dimensions it is a <code>Rectangle</code> or <code>AxisAlignedBounds2D</code>:</p><pre><code class=\"language-cs\">struct Rectangle {\n Segment boundsX;\n Segment boundsY;\n}\n</code></pre>\n<p>Let’s calculate an intersection for two rectangles.</p><pre><code class=\"language-cs\">Rectangle Intersect(Rectangle a, Rectangle b) =>\n new Rectangle {\n X = Segment.Intersect(a.X, b.X),\n Y = Segment.Intersect(a.Y, b.Y)\n };\n</code></pre>\n<p>In three dimensions it is <code>AABB</code> (Axis Aligned Bounding Box) or <code>AxisAlignedBounds3D</code>:</p><pre><code class=\"language-cs\">struct AABB {\n public Segment boundsX;\n public Segment boundsY;\n public Segment boundsZ;\n}\n</code></pre>\n<p>Let’s calculate an intersection for two AABBs.</p><pre><code class=\"language-cs\">AABB Intersect(AABB a, AABB b) =>\n new AABB {\n X = Segment.Intersect(a.X, b.X),\n Y = Segment.Intersect(a.Y, b.Y),\n Z = Segment.Intersect(a.Z, b.Z),\n };\n</code></pre>\n<p>Let’s do it slightly differently for fun.</p><p>Testing intersection via bounds in 1D:</p><pre><code class=\"language-cs\">struct Bounds{\n public float Min;\n public float Max;\n \n public Bounds Intersection(Bounds other) =>\n new Bounds {\n Min = Math.Max(this.Min, other.Min),\n Max = Math.Min(this.Max, other.Max)\n };\n \n public bool Intersects(Bounds other) {\n var i = this.Intersection(other);\n return i.Min < i.Max;\n }\n}\n</code></pre>\n<p>Testing intersections via bounds in 2D:</p><pre><code class=\"language-cs\">struct Bounds2D {\n public Bounds BoundsX;\n public Bounds BoundsY;\n public Bounds2D Intersection(Bounds2D other) =>\n new Bounds2D {\n BoundsX = this.XBounds.Intersection(other.BoundsX),\n BoundsY = this.YBounds.Intersection(other.BoundsY);\n };\n public bool IsValid => BoundsX.IsValid && BoundsY.IsValid;\n public bool Intersects(Bounds2D other) =>\n this.Intersection(other).IsValid;\n}\n</code></pre>\n<p>Testing intersections via bounds in 3D:</p><pre><code class=\"language-cs\">struct Bounds3D {\n public Bounds BoundsX;\n public Bounds BoundsY;\n public Bounds BoundsZ;\n public Bounds3D Intersection(Bounds3D other) =>\n new Bounds3D {\n BoundsX = this.BoundsX.Intersection(other.BoundsX),\n BoundsY = this.BoundsY.Intersection(other.BoundsY);\n BoundsZ = this.BoundsZ.Intersection(other.BoundsZ);\n };\n public bool IsValid => BoundsX.IsValid && BoundsY.IsValid && BoundsZ.IsValid;\n public bool Intersects(Bounds3D other) =>\n this.Intersection(other).IsValid;\n}\n</code></pre>\n",
"image": "https://pilvimaa.fi/media/posts/10/AABB.jpg",
"author": {
"name": "Pilvinen"
},
"tags": [
"Math",
"C#",
"AABB"
],
"date_published": "2022-07-16T01:15:43+03:00",
"date_modified": "2022-07-16T01:47:10+03:00"
},
{
"id": "https://pilvimaa.fi/seeded-random-numbers/",
"url": "https://pilvimaa.fi/seeded-random-numbers/",
"title": "Seeded Random Numbers",
"summary": "Sometimes you need pseudo-random numbers which are not dependent on time and which are always reliably identical and given in the same order when ever you re-start the application or…",
"content_html": "<p>Sometimes you need pseudo-random numbers which are not dependent on time and which are always reliably identical and given in the same order when ever you re-start the application or re-create the <code>Random</code> generator object.</p><p>This can be achieved by giving the <code>Random</code> generator instance a seed value.</p><pre><code class=\"language-cs\">Random random = new Random(1273456);\n</code></pre>\n<p>This is very useful in situations where you, for example, need to generate identical terrain each time your game runs.</p><p>The seed value could be shared between client and server or between friends to generate the same world on different machines provided that the generation code remains identical between versions of the application.</p><h2 id=\"several-random-number-generators-sharing-a-seed\">Several Random Number Generators Sharing a Seed</h2>\n<p>Csharp’s random number generator is not thread safe. This means if you need random number generation and you have several threads which need those numbers they can’t share the same instance, it’s not safe to do so.</p><p>In such cases you might need to have several random number generators which are based on the same seed to keep the behavior consistent.</p><p>A common way to do this is to use a master random number generator and have that generate the seed values for any subsequent random number generators. But this approach has problems even though it’s common. If you do this you will get bi-modal peaks for your range where it’s more likely to get numbers from those peaks - making the random generation less random.</p><p>A simple working solution to this problem is to increment your seed by +1 for each new subsequent random number generator like shown in the example below.</p><pre><code class=\"language-cs\">using System; \n \ninternal class SeededRandomExample { \n public Random TerrainRandom; \n public Random BiomeRandom; \n public Random VegetationRandom; \n public int Seed { get; set; } = 481203849; \n public SeededRandomExample() { \n int terrainSeed = Seed; \n TerrainRandom = new Random(terrainSeed); \n int biomeSeed = Seed + 1; \n BiomeRandom = new Random(biomeSeed); \n int vegetationSeed = Seed + 2; \n VegetationRandom = new Random(vegetationSeed); \n } \n}\n</code></pre>\n<p>This solution will give you better and more consistently (pseudo-) random numbers while keeping the random number generators tied to the same seed value.</p>",
"image": "https://pilvimaa.fi/media/posts/9/Dice.jpg",
"author": {
"name": "Pilvinen"
},
"tags": [
"World Generation",
"Random Numbers",
"C#"
],
"date_published": "2022-07-14T20:56:37+03:00",
"date_modified": "2022-07-14T21:10:44+03:00"
},
{
"id": "https://pilvimaa.fi/godot-multimesh-setasbulkarray-method/",
"url": "https://pilvimaa.fi/godot-multimesh-setasbulkarray-method/",
"title": "Godot MultiMesh SetAsBulkArray Method",
"summary": "This article tries to bridge the gaps and ambiguities in the official Godot documentation for SetAsBulkArray(). We don’t go over everything. But armed with this information you should be able…",
"content_html": "<p>This article tries to bridge the gaps and ambiguities in the official Godot documentation for <code>SetAsBulkArray()</code>. We don’t go over <em><strong>everything</strong></em>. But armed with this information you should be able to figure it out.</p><p><code>MultiMeshInstance</code>‘s <code>MultiMesh</code> resource has a <code>SetAsBulkArray()</code> method which allows you to set all the data for your <code>MultiMesh</code> directly from a <code>float[]</code> array in one swift operation.</p><p>The great thing about this is that it’s as efficient as it can get. And you get to generate the data yourself in any way you want.</p><h2 id=\"but-how-to-generate-the-data\">But how to generate the data?</h2>\n<p>The documentation for <code>SetAsBulkArray()</code> at the time of writing this is pretty terrible, so let’s go over the essentials.</p><p>The data for the array can be composed of three different parts:</p><ul>\n<li>Transform data</li>\n<li>Color data</li>\n<li>Custom data</li>\n</ul>\n<p>Transform data is mandatory, but the color data and custom data are optional.</p><h3 id=\"transform-data\">Transform data</h3>\n<p>What the transform data does is it tells <code>MultiMeshInstance</code> where your objects instances should be located, what their scale should be, and what their shears should be.</p><p>The transform data is a matrix of 12 <code>float</code> values:</p><pre><code class=\"language-cs\">// Transform data for a single mesh instance. \nfloat scaleX = 1f, shearXalongY = 0f, shearXalongZ = 0f, translateX = xOffset, // 3 Basis and Origin X. \n shearYalongX = 0f, scaleY = 1f, shearYalongZ = 0f, translateY = yOffset, // 3 Basis and Origin Y. \n shearZalongX = 0f, shearZalongY = 0f, scaleZ = 1f, translateZ = zOffset; // 3 Basis and Origin Z.\n</code></pre>\n<p>It is noteworthy that the offsets <code>translateX</code>, <code>translateY</code>, and <code>translateZ</code> are placed always right after the 3 basis values (eg. <code>scaleX</code>, <code>shearXalongY</code>, <code>shearXalongZ</code> in the above example) interleaved in the data instead of having them sitting at the end grouped together like you might expect.</p><p>The scale values change the scale of the mesh like you would expect. The shear values deform the mesh in different ways. And the translate values move the mesh around along the <code>x</code>, <code>y</code>, and <code>z</code> axis.</p><h3 id=\"color-data\">Color data</h3>\n<p>Vertex color data can be passed to <code>SetAsBulkArray()</code> in two formats.</p><p>You can pass it either as four <code>float</code>s (more accurate colors) representing the color data as rgba (red, green, blue, alpha) or as a single <code>float</code> (faster, smaller) which has four <code>byte</code>s crammed into it forcibly as Color8. These four bytes represent the <code>rgba</code> values but with less data and less accuracy (you’re never going to notice).</p><p>You can also disable the color information if you don’t need it.</p><p>When we create the <code>MultiMesh</code> we need to declare which format were are going to use.</p><p>NOTE: Which ever <code>ColorFormat</code> you choose the data you generate yourself will always has to match the selected <code>ColorFormat</code> or you will get errors and nothing will work.</p><p>Let’s look at practical examples where we declare the format when we create a new <code>MultiMesh</code>. I have removed all other values so we can focus on the color format:</p><h4 id=\"example-1-declaring-we-use-the-binary-format\">Example 1: Declaring we use the binary format</h4>\n<pre><code class=\"language-cs\">MultiMesh multiMesh = new () { \n ColorFormat = MultiMesh.ColorFormatEnum.Color8bit; \n};\n</code></pre>\n<p>Above we declare we are going to use the Color8 byte format where we pass a single float.</p><h4 id=\"example-2-declaring-we-use-the-float-format\">Example 2: Declaring we use the float format</h4>\n<pre><code class=\"language-cs\">MultiMesh multiMesh = new () { \n ColorFormat = MultiMesh.ColorFormatEnum.Float; \n};\n</code></pre>\n<p>Above we declare we are going to use the format with four float values representing the rgba values.</p><h4 id=\"example-3-declaring-we-have-no-color-information\">Example 3: Declaring we have no color information</h4>\n<pre><code class=\"language-cs\">MultiMesh multiMesh = new () { \n ColorFormat = MultiMesh.ColorFormatEnum.None; \n};\n</code></pre>\n<h3 id=\"creating-the-color8bit-color-data\">Creating the Color8bit color data</h3>\n<p>Let’s start right off by diving into some code.</p><pre><code class=\"language-cs\">// Our colors as raw values (between 0 and 1).\nfloat red = 0.1f;\nfloat green = 0.2f;\nfloat blue = 0.3f;\nfloat alpha = 1f;\n\n// Convert to RGBA from 0 to 255.\nred = red * 255;\ngreen = green * 255;\nblue = blue * 255;\nalpha = alpha * 255;\n\n// We need to pass an array, so we create one.\nbyte[] myColors = new byte[4];\n\n// Assign colors to the array we need to input.\nmyColors[0] = (byte) red;\nmyColors[1] = (byte) green;\nmyColors[2] = (byte) blue;\nmyColors[3] = (byte) alpha;\n\n// This is how we cram 4 bytes into a float.\nfloat color = BitConverter.ToSingle(myColors, 0);\n</code></pre>\n<p>Keep in mind that this is a <em><strong>contrived</strong></em> example and you will have to think for yourself how to solve your particular loops, functions, and such for constructing the <em><strong>practical</strong></em> color data for your meshes.</p><p>The example above shows you how to get a <code>float</code> which some of you might find to be a rather strange <code>float</code>. It has 4 bytes crammed into it and it might be a negative number or otherwise rather curious in it’s value range.</p><p>The example above is all you really need. But for a deeper understanding, let’s go over the code in detail.</p><pre><code class=\"language-cs\">float red = 0.1f;\nfloat green = 0.2f;\nfloat blue = 0.3f;\nfloat alpha = 1f;\n</code></pre>\n<p>First, we need to have some <strong>color values</strong> to work with. So we create some in the <strong>raw format</strong> which ranges from <code>0</code> to <code>1</code> so we can better understand how to convert raw values to the format we actually need. Feel free to skip this stage if you’re not using raw values and your color data is already in the <code>0</code> to <code>255</code> range.</p><p>Just note that you will get trouble if you try to use the wrong color format.</p><p>You would most likely have a function which gives you the colors you want. But for the sake of this example it doesn’t really matter where your colors come from, or in what format, as long as you have your colors ready at hand and in the correct format by the time you’re ready to pass them on.</p><pre><code class=\"language-cs\">red = red * 255;\ngreen = green * 255;\nblue = blue * 255;\nalpha = alpha * 255;\n</code></pre>\n<p>By multiplying the raw colors that are in the scale of <code>0</code> to <code>1</code> with <code>255</code> we transform them from the scale of <code>0</code> to <code>255</code>. It is required for the Color8bit binary format.</p><pre><code class=\"language-cs\">byte[] myColors = new byte[4];\n</code></pre>\n<p><code>BitConverter</code> uses <code>byte[]</code> as input, so we need to have a byte array in which to pass our data. The size of the array has to be to be <code>4</code> as we have <code>4</code> colors: red, green, blue, and alpha.</p><p>NOTE: You most likely do not want to declare this array <em><strong>inside</strong></em> of your color processing loop. You might be generating a lot of mesh instance data and creating a lot of new arrays which become useless right after might not be a good idea. So I recommend declaring the array outside of your loop and reusing the array.</p><pre><code class=\"language-cs\">myColors[0] = (byte) red;\nmyColors[1] = (byte) green;\nmyColors[2] = (byte) blue;\nmyColors[3] = (byte) alpha;\n</code></pre>\n<p>Next we simply assign the color values to the array and cast them as bytes since a <code>byte</code> array is required and our color values are still floats.</p><pre><code class=\"language-cs\">float color = BitConverter.ToSingle(myColors, 0);\n</code></pre>\n<p>Finally we use <code>BitConverter.ToSingle()</code> to get our weird-ass <code>float</code> which has 4 colors packed as a single <code>float</code>.</p><p>What <code>BitConverter</code> does is it basically uses <code>unsafe</code> methods to copy the data as-is really fast and efficiently from <code>myColors</code> array directly to the <code>4</code> bytes in the target <code>float</code>.</p><p>That’s it. You can now use the single <code>float</code> in your <code>MultiMesh</code> data array.</p><p>If you feel the urge to understand on a deeper level why this weird dance is necessary you have to look into how <code>float</code> values work.</p><p>Floating point values quite complex and clever under the hood and that’s why you need special considerations when putting them together from bytes. But we won’t get deeper into that here as it’s a whole subject unto itself.</p><p>NOTE: There might be a simpler way of doing this. But I’m not aware if it at the time of writing this.</p><h3 id=\"creating-the-float-color-data\">Creating the float color data</h3>\n<pre><code class=\"language-cs\">float red = 0.5f\nfloat green = 0.5f\nfloat blue = 0.5f\nfloat alpha = 1f\n</code></pre>\n<p>And you’re done. Just replace the values with the color values you want using the raw color format with values between <code>0</code> and <code>1</code>.</p><h4 id=\"accessing-the-data-from-a-shader\">Accessing the data from a shader</h4>\n<p>The color information can be accessed via <code>COLOR</code> in the shader automatically.</p><p><strong>Example:</strong></p><pre><code class=\"language-cs\">void fragment() {\n ALBEDO = COLOR.rgb;\n}\n</code></pre>\n<h3 id=\"custom-data\">Custom data</h3>\n<p>The process for custom data is <em><strong>largely identical</strong></em> to the color data (except for the color specific parts). Read the color data section above for the details.</p><p><code>MultiMesh</code> custom data can be accessed automatically in the shader via <code>INSTANCE_CUSTOM</code> and the id number with <code>INSTANCE_ID</code>.</p><h3 id=\"putting-it-all-together\">Putting it all together</h3>\n<p>You have your transforms, you have your color data, and you have your custom data. Now we need to put it into an array that represents all the data for all the meshes in your <code>MultiMesh</code>.</p><h4 id=\"create-and-pass-your-multimesh-to-your-multimeshinstance\">Create and pass your MultiMesh to your MultiMeshInstance</h4>\n<pre><code class=\"language-cs\">MultiMesh multiMesh = new () { \n TransformFormat = MultiMesh.TransformFormatEnum.Transform3d, \n ColorFormat = MultiMesh.ColorFormatEnum.Color8bit, \n CustomDataFormat = MultiMesh.CustomDataFormatEnum.Float, \n InstanceCount = totalCount, \n VisibleInstanceCount = -1, \n Mesh = mesh, \n}; \n \nMultimesh = multiMesh;\n</code></pre>\n<p>You would do this inside of your <code>MultiMeshInstance</code> Make sure all the data is set correctly and to correct values for your use case.</p><h4 id=\"generate-multimeshdata-full-example\">Generate MultiMeshData full example</h4>\n<pre><code class=\"language-cs\">internal float[] GenerateMultiMeshData() { \n \n int transformDataSize = 12; \n int colorDataSize = 1; \n int customDataSize = 4; \n int dataSize = transformDataSize + colorDataSize + customDataSize; \n int maxIterations = 10; \n int maxDataSize = maxIterations * dataSize; \n int rgbaDataSize = 4; \n byte[] randomColorsArray = new byte[rgbaDataSize]; \n float[] multiMeshData = new float[maxDataSize]; \n Random random = new Random(); \n \n int dataIteration = 0; \n for (; dataIteration < maxDataSize; dataIteration += dataSize) { \n \n int xOffset = dataIteration / dataSize; \n int yOffset = 0; \n int zOffset = 0; \n \n // Generate transforms data. \nfloat scaleX = 1f, shearXalongY = 0f, shearXalongZ = 0f, translateX = xOffset, \n shearYalongX = 0f, scaleY = 1f, shearYalongZ = 0f, translateY = yOffset, \n shearZalongX = 0f, shearZalongY = 0f, scaleZ = 1f, translateZ = zOffset; \n \n // Generate random color data. \nfloat red = random.Next(0, 256); \n float green = random.Next(0, 256); \n float blue = random.Next(0, 256); \n float alpha = 255f; \n randomColorsArray[0] = (byte) red; \n randomColorsArray[1] = (byte) green; \n randomColorsArray[2] = (byte) blue; \n randomColorsArray[3] = (byte) alpha; \n float color = BitConverter.ToSingle(randomColorsArray, 0); \n \n // Generate custom data. \n float dataA = 0f, dataB = 0f, dataC = 0f, dataD = 0f; \n \n // Assign the data of a single mesh to the array one mesh at a time per loop iteration. \n multiMeshData[dataIteration] = scaleX; \n multiMeshData[dataIteration + 1] = shearXalongY; \n multiMeshData[dataIteration + 2] = shearXalongZ; \n multiMeshData[dataIteration + 3] = translateX; \n multiMeshData[dataIteration + 4] = shearYalongX; \n multiMeshData[dataIteration + 5] = scaleY; \n multiMeshData[dataIteration + 6] = shearYalongZ; \n multiMeshData[dataIteration + 7] = translateY; \n multiMeshData[dataIteration + 8] = shearZalongX; \n multiMeshData[dataIteration + 9] = shearZalongY; \n multiMeshData[dataIteration + 10] = scaleZ; \n multiMeshData[dataIteration + 11] = translateZ; \n multiMeshData[dataIteration + 12] = color; \n multiMeshData[dataIteration + 13] = dataA; \n multiMeshData[dataIteration + 14] = dataB; \n multiMeshData[dataIteration + 15] = dataC; \n multiMeshData[dataIteration + 16] = dataD; \n } \n return multiMeshData; \n}\n</code></pre>\n<h4 id=\"error-condition-dsize--p_arraysize-is-true\">ERROR: Condition “dsize != p_array.size()” is true.</h4>\n<p>This error is caused by your data not having the length you told <code>MultiMesh</code> it would have.</p><ol>\n<li><p>Make sure your <code>ColorFormat</code>, <code>CustomDataFormat</code>, and <code>InstanceCount</code> are set to the correct values reflecting what your data has.</p></li>\n<li><p>Make sure your generated data is of correct length. Make sure you are not accidentally missing data fields.</p></li>\n<li><p>Make sure you are iterating through the data correctly in your loops. Check your index values and how they are used and incremented in code.</p></li>\n<li><p>It didn’t fix the issue? Go through the checklist again, carefully.</p></li>\n</ol>\n",
"image": "https://pilvimaa.fi/media/posts/8/MultiMeshBlocks.png",
"author": {
"name": "Pilvinen"
},
"tags": [
"MultiMeshInstance",
"Godot Game Engine",
"C#"
],
"date_published": "2022-07-13T16:37:45+03:00",
"date_modified": "2022-07-14T21:10:52+03:00"
},
{
"id": "https://pilvimaa.fi/inheritance-with-constructors/",
"url": "https://pilvimaa.fi/inheritance-with-constructors/",
"title": "Inheritance with Constructors",
"summary": "Here we call the constructor of the base class A and pass the id as a parameter to initialize _id in the constructor of A class. By doing this way…",
"content_html": "<p>Here we call the constructor of the <strong>base class A</strong> and pass the <code>id</code> as a parameter to initialize <code>_id</code> in the <strong>constructor</strong> of <strong>A</strong> class.</p><p>By doing this way we can avoid unnecessary <em>code duplication</em>.</p><pre><code class=\"language-cs\">internal class A {\n string _id; \n internal A(string id) => _id = id;\n}\n\ninternal class B : A {\n string _name;\n internal B(string name) : base(id) => _name = name;\n}\n</code></pre>\n<p>Here we call another constructor inside the same class and create a new <code>Author</code> object from the data provided to the first constructor. This is useful in cases where you already have an object constructed which you want to reuse.</p><pre><code class=\"language-cs\">internal class C {\n Author _author; \n string _message;\n \n internal C(Author author, string message) {\n _author = author;\n _message = message;\n }\n\n internal C(string id, string name, string message) : this(new Author(id, name), message) {}\n}\n</code></pre>\n<p>Passing in <strong>default values</strong> when default values cannot be used.</p><p>This example will not compile, but this is what we’d like to do.</p><pre><code class=\"language-cs\">public class D {\n public D(string[] myArray = new string[] {"Entry1", "Entry2"}) {}\n}\n</code></pre>\n<p>We can make it work by passing a faked default value.</p><pre><code class=\"language-cs\">public class E {\n public E(string[] myArray) {}\n\n public E() : this(new string[] {"Entry1", "Entry2"}) {}\n}\n</code></pre>\n",
"image": "https://pilvimaa.fi/media/posts/7/Binary.png",
"author": {
"name": "Pilvinen"
},
"tags": [
"Inheritance",
"Constructors",
"C#"
],
"date_published": "2022-07-11T14:45:47+03:00",
"date_modified": "2022-07-14T21:11:01+03:00"
},
{
"id": "https://pilvimaa.fi/vectors/",
"url": "https://pilvimaa.fi/vectors/",
"title": "Introduction to vectors",
"summary": "I'm going to talk a little bit about vectors from my own and from game development perspective. It's by no means complete or definitive description of what vectors are or…",
"content_html": "<p>I'm going to talk a little bit about vectors from my own and from game development perspective. It's by no means complete or definitive description of what vectors are or how they can be used.</p>\n<p>I understand vectors as a bunch of floating point numbers (eg. decimal numbers like 1.123, 1.0, 100.01, etc.) that are grouped together. That's it. Nothing special or particularly difficult about it.</p>\n<p><code>var myVector = new Vec2(2, 3);</code></p>\n<p>Here I've declared a new vector of type Vec2 and assigned it to a variable named \"myVector\". The vector contains the values 2 and 3. Vec2 just means that it takes in exactly two floating point numbers.</p>\n<p><code>var myVector = new Vec3(2, 3, 4.5);</code></p>\n<p>And here I've declared a Vec3 vector. As you can see it takes three values instead of two. Nothing special about it. But you can probably already start to see a repeating pattern here. Bigger number -> holds more values. That's it.</p>\n<p>Computers like vectors. Computers think vectors are really yummy. CPUs are really good at processing vectors. So, we like to use vectors to do computer stuff. That's really all you need to know about it at this level.</p>\n<p>Most of the utility of vectors comes <em>simply from how you decide to use them</em>. I can't stress this enough.</p>\n<p>Different kinds of vectors are called by different names depending on what kind of values they hold and what those values are supposed to represent (yet the vectors still look exactly the same as any other vectors). At the end of the day all vectors - no matter what they are called - are just a bunch of floating point numbers stuffed together.</p>\n<p>Vectors can be used in computer graphics, they can be used to do all kinds of math, or to copy data from memory really fast, etc.</p>\n<p>But we're going to be focusing on vectors being used to represent various aspects of the 2D spaces and any entities therein. In other words let's move and rotate something. We'll stick to 2D in the examples for simplicity. Therefore we'll be using vectors which hold only two values like in the <code>Vec2(2, 3)</code> example we saw earlier.</p>\n<h3>What are vectors good for in game dev?</h3>\n<p>Two dimensional vectors can be used to represent basically <em>anything</em> that has some kind of <strong>magnitude</strong> and <strong>direction</strong>. They are really good at that.</p>\n<p>One way to think of vectors is to see them as arrows (of varying lengths or \"magnitude\") that are pointing towards something. The direction of the arrow can represent movement direction, rotation, or basically pretty much anything. The magnitude (or length) of the vector can represent things like force, velocity, etc.</p>\n<p>You might already be confused and be thinking something along the lines of \"How can something that has only two values (defining a point in space) represent <strong>both</strong> magnitude and direction at the same time? It makes no sense. Is there a hidden value somewhere?\"</p>\n<p>The answer is, kind of.</p>\n<p>Magnitude is calculated based on the <strong>origin</strong> point (which is not stored explicitly inside the vector itself) and the coordinates of the vector itself. It's <strong>important</strong> to note that the vector is a <strong>translation</strong> or an \"<strong>offset</strong>\" <em>from</em> it's origin -> to the point defined inside the vector.</p>\n<p>Let's look into a distance to target and some other things to understand our magnitude and direction better.</p>\n<h3>Pythagoras</h3>\n<p>In game engines you are most commonly using your direction/position vectors to represent a <strong><em>change</em></strong> from a point of <strong>origin</strong>. We're saying something like \"You are at location 1,2 (your origin) and now you want to transform your position by 1,3\". That is <em>not</em> \"Move <strong>to</strong> location 1,3\", that is: \"Move 1 step on the X-axis horizontally, and 3 steps on the Y-axis vertically <strong>from your current location, ie. origin</strong>. Therefore you would end up at location 2,5, not at location 1,3. Got that? Great.</p>\n<p>But how can we find out what the <strong>distance to the target</strong> is on a straight line? It's unlikely we're going to want to move like the knight on chess board.</p>\n<p>When you move like that the A amount of steps you take on the X-axis and B amount of steps you take on the Y-axis are always creating a right angle of 90°. Finally, if you draw a straight line from A to B (in addition to the straight angle) what you have is a proper right angled triangle! Are you starting to see where this is going?</p>\n<p>That's when Pythagoras comes in to play.</p>\n<p>Pythagorean Theorem tells us that with every right angled triangle you can calculate the length of the longest line on the triangle with the famous formula <code>A^2 + B^2 = C^2</code> which in essence means that you can figure out the length of that straight line you drew from A to B (also known as hypotenuse) by using this equation.</p>\n<p>Let's do an exercise and assume we have <code>var myVector = new Vec2(3, 4);</code> as our transformation and our origin is at (0,0). In other words we want to move x:3 and y:4 steps from our current location.</p>\n<p>To get a proper vector arrow from A to B instead of the chess-knight like pattern we'll plug-in our numbers to the Pythagorean Theorem:</p>\n<p><code>3^2 + 4^2 = DistanceToTarget^2</code></p>\n<p>Above you see that I plugged in the <code>x:3</code> and <code>y:4</code> to the left side of the equation and raised the both values to the power of two like Pythagorean Theorem tells us to do. On the right side of the equation I renamed the <code>C</code> to <code>DistanceToTarget</code> to make it clearer what's going on. DistanceToTarget also needs to be raised to the power of two.</p>\n<p>Raising to the power of two is also called \"squaring a number\". When we take the number 3, for example, we create a square shape where each side of the square is 3 units long and thus we have a 3 times 3 square composed of 9 units. Essentially you are multiplying a number by itself as many times as the exponent tells you. In this case we multiply 3 by itself two times, ie. <code>3 * 3 = 9</code> and 4 by itself two times, ie. <code>4 * 4 = 16</code> which changes our equation to:</p>\n<p><code>9 + 16 = DistanceToTarget^2</code></p>\n<p>Therefore:</p>\n<p><code>25 = DistanceToTarget^2</code></p>\n<p>Now we're very close to the solution, but we're still left with a pesky power of two hanging above our DistanceToTarget. We can't calculate DistanceToTarget away because it's the very number we are trying to figure out. But we do need to get rid of it. How are we going to do that?</p>\n<p>The opposite of multiplication is division and in similar fashion the opposite of a power of two happens to be the <strong>square root</strong>. So if we apply a square root on both sides of our equation we should be able to get rid of that extra power of two.</p>\n<p><code>sqrt(25) = sqrt(DistanceToTarget^2)</code></p>\n<p>Pardon my non-mathematical notation. But you get the point. The square root cancels out the power of two and we get:</p>\n<p><code>5 = DistanceToTarget</code></p>\n<p>Which is our final answer.</p>\n<p>As we don't want to be distracted by the numbers when explaining a concept, in this example I purposefully picked numbers which are easy to calculate and which result into integers.</p>\n<p>As a reminder the <strong>square root</strong> of a number gives you as an answer the number which you need to <em>multiply by itself</em> to get that original value. You should be able to easily see why square root and power of two are the polar opposites of each other. Essentially in our case we are taking 25 units and arranging them into a square where each side is equally long, ie. 5 units long. 5 times 5 is 25, therefore the square root of 25 must be 5. The math proof for doing this by hand and not in reverse is complex. Usually you just use a calculator to figure out square or cubic roots (it's the same, but it's a cube!).</p>\n<p>The most important thing to understand about square roots is simply to be able to visualize geometrically what is going on with those numbers. When you take a square root of something - it's a number of things arranged into a square. That's all there is to it!</p>\n<p>In most game engines you usually have a function to figure out things like \"Distance from vector A to vector B\" or \"Distance to target\". But you should still understand what is going on under the hood so you can effectively reason about your code and debug it.</p>\n<h3>Unit vectors aka normalized vectors</h3>\n<p><strong>Unit vectors</strong> are also called <strong>direction vectors</strong> and <strong>normals</strong>. They are vectors which have been \"normalized\", ie. their <strong>magnitude</strong> has been reduced to <strong>1</strong> while <strong>preserving</strong> their <strong>direction </strong>by dividing all the values inside a vector by the calculated length of the vector.</p>\n<p>Imagine that you take a car sized arrow that is pointing towards your home and you shrink it until it's the length of your arm - a much more reasonable size for an arrow. And imagine that you take a tiny matchbox sized arrow and stretch it until it also is the length of your arm. And let's call that arm length the length of one. Now you only resized your arrows, they are still pointing towards your home. Congratulations, you understand the most relevant part of normalization.</p>\n<p>So, why normalize?</p>\n<p>The short answer is: to turn vectors into comparable scale.</p>\n<p>To take a contrived example, imagine that you have a treasure chest full of cents, dimes, quarters, and dollars. You also have a scale and you would very much want to figure out how much money you have by weighing your coins. An arduous process when all of your coins have different value and weight and they are all mixed together! So to make the problem simpler you wave your magic wand of normalization and turn all of your coins into the appropriate and comparable amount of pennies. Now that all of your coins have the same weigh and value it's trivial to figure out by weighing them how many you need to pay for a loaf of bread (in case you were wondering, one freshly minted US penny weighs 2.5 grams).</p>\n<p>When we normalize vectors we retain their most important quality - their direction - while making them of a standard magnitude (or size/length/etc). Having the same scale makes it trivially easy to run operations on various different vectors.</p>\n<p>Let's normalize something for fun. Let's take the example from before with <code>Vec2(3,4)</code>:</p>\n<pre>3^2 + 4^2 = DistanceToTarget^2 <br>9 + 16 = DistanceToTarget^2<br>sqrt(25) = sqrt(DistanceToTarget^2)<br>5 = DistanceToTarget</pre>\n<p>Now that we have our calculated magnitude, ie. the length of our vector arrow, which is <code>5</code>, we divide all our vector's values with the magnitude of the vector (5) to get, in effect, a normalized magnitude of 1:</p>\n<p><code>3 / 5 = 0.6</code><br><code>4 / 5 = 0.8</code></p>\n<p>Here's our new normalized vector:</p>\n<p><code>var myNormalizedVector = new Vec2(0.6, 0.8);</code></p>\n<p>Your vector is still pointing to the same direction, but it is of \"standard length\" or \"magnitude\" now. Nice.</p>\n<p>Again, most game engines can do this for you via their pre-implemented functions. But you should still understand how they work to avoid getting confused with your own code.</p>\n<h3>Scalars</h3>\n<p><strong>Scalar</strong>, like its name tells us, is a value which can be used to scale vectors. In other words it only has a magnitude. It cannot represent a direction.</p>\n<p><strong>Vector multiplication and division</strong> by a scalar works by multiplying or dividing each of the vector's values one by one, eg:</p>\n<pre>var myVector = new Vec2(3, 4);<br>var multipliedVector = myVector * 2; // (3, 4) * 2 = (6, 8)<br>var dividedVector = myVector / 2; // (3, 4) / 2 = (1.5, 2)</pre>\n<p>This allows you to make vectors bigger or smaller, ie. you can scale them without changing their direction.</p>\n<h3>Dot product</h3>\n<p>Dot product is a method for comparing the relationship between two vectors by returning a <strong>scalar</strong>. Dot product is especially useful when used with normalized vectors.</p>\n<p>Dot product can be used in game development to answer questions like (for example) \"Am I looking directly at you?\" or \"How far away from you am I looking at?\" or \"Am I looking in the same direction as you?\" or \"Can I see you if I look at this direction given a field of view of X?\", etc.</p>\n<p>The scale of the returned values from dot product for normalized vectors ranges from -1 to +1 which represent different rotation degrees where -1 generally means 180° and +1 means 0°.</p>\n<h5>Coordinates and other math</h5>\n<p>When dealing with coordinates dot product is the <strong>sum</strong> of the <strong>products</strong> of the <strong>corresponding</strong> entries of the <strong>two sequences of numbers</strong>. In other words if you have two vectors <code>(x:3, y:4)</code> and <code>(x:7, y:24)</code> you multiply the numbers of each vector which correspond with each other (x's with x's, and y's with y's, etc) and finally you add the results together.</p>\n<p>Let's try it with our vectors:</p>\n<p><code>3 * 7 + 4 * 24 = 21 + 96 = 117</code>.</p>\n<p>If we normalize the vectors first into <code>(x:0.6, y:0.8)</code> and <code>(x:0.28, y:0.96)</code> that gives us:</p>\n<p><code>0.6 * 0.28 + 0.8 * 0.96 = 0.168 + 0.768 = 0.936</code></p>\n<h5>Geometry</h5>\n<p>When looked at from the perspective of <strong>geometry</strong> dot product is the <strong>product</strong> of the <strong>magnitudes</strong> (ie. length) of the <strong>two vectors</strong> and the <strong>cosine</strong> of the <strong>angle between them</strong>. Or - if you <em>normalize the vectors first</em> - then you can just calculate the <strong>cosine</strong> of the <strong>angle between the two vectors</strong>!</p>\n<p>(Of course you first need to get the angle somehow. I won't get into it here because it is a bit math intensive).</p>\n<p>Without normalizing first the formula is:<br><code>a · b = |a| * |b| * cos(θ)</code></p>\n<p>And with normalizing the formula is simply:<br><code>cos(θ)</code></p>\n<pre><code>a · b</code> signifies the dot product of the vectors a and b.<br>|a| signifies the magnitude (ie. length) of the vector a.<br>|b| signifies the magnitude (ie. length) of the vector b.<br>cos() signifies cosine.<br>θ (theta) is the angle between the vectors a and b.</pre>\n<p><strong>Cosine</strong> is the ratio between length of the hypotenuse of a triangle and length of the adjacent side of a triangle.</p>\n<p>We're not going to be calculating cosine by hand because it's generally something you want to use a calculator or math functions of a programming language to solve - unless you're really into math, in which case you can get an approximation by hand, but it's non-trivial to calculate for most people.</p>\n<p>Again, game engines come with functions to solve the dot product.</p>\n<h3>Math and vectors</h3>\n<p>Unlike with regular numbers math with vectors is all about conventions. In other words basically a bunch of people agreed to a set of arbitrary rules defining how math with vectors works and that's what we're using.</p>\n<p>- Two vectors can be added.<br>- Two vectors can be subtracted.<br>- A single vector can be multiplied and divided by a scalar.<br>- Two vectors can be \"multiplied\", aka cross product (which we won't deal with here).<br>- Vectors <em><strong>cannot</strong></em> be divided by vectors.</p>\n<h5>Adding and subtracting vectors</h5>\n<p>When you add two vectors <code>(x:1, y:2)</code> with <code>(x:4, y:5)</code> what you do is you add all of their matching components together. X goes with X, Y goes with Y, and so on.</p>\n<pre>var a = new Vec2(1, 2);<br>var b = new Vec2(4, 5);<br>var result = a + b; // (1, 2) + (4, 5) = (5, 7)</pre>\n<p>Order of addition <em>does not matter</em>. The same result is gained both ways, ie. by adding a to b and adding b to a.</p>\n<p>Adding a velocity vector to a position vector will result in movement to a new position. Simple as that.</p>\n<pre>var velocity = new Vec2(5, 2);<br>var newPosition = currentPosition + velocity;</pre>\n<p>Subtraction works in the same way but in reverse.</p>\n<pre>var a = new Vec2(1, 2);<br>var b = new Vec2(4, 5);<br>var result = a - b; // (1, 2) - (4, 5) = (-3, -3)</pre>\n<p>To get a <strong>direction towards target</strong> vector B from vector A you can subtract <code>B - A = DirectionTo</code>. To understand why this works it's best to try it our yourself a few times on a grid paper.</p>\n<h5>Scalar multiplication and division</h5>\n<p>We already covered scalar multiplication above briefly. As a refresher multiplying a vector by a scalar changes the scale, not direction:</p>\n<pre>var myVector = new Vec2(3, 4);<br>var multipliedVector = myVector * 2; // (3, 4) * 2 = (6, 8)<br>var dividedVector = myVector / 2; // (3, 4) / 2 = (1.5, 2)</pre>\n<p>However, multiplying a vector by a <strong>negative scalar</strong> changes not only the scale but also <strong>reverses the direction</strong> of the vector.</p>\n<p>Dividing a vector by a scalar only affects the scale.</p>",
"image": "https://pilvimaa.fi/media/posts/6/TriangleRuler.png",
"author": {
"name": "Pilvinen"
},
"tags": [
"Vectors",
"Math"
],
"date_published": "2021-08-27T12:13:21+03:00",
"date_modified": "2021-08-27T20:07:52+03:00"
},
{
"id": "https://pilvimaa.fi/data-oriented-design/",
"url": "https://pilvimaa.fi/data-oriented-design/",
"title": "Data Oriented Design",
"summary": "A few notes on Data Oriented Design. - Study the data access patterns to determine where performance bottlenecks are. - Group things together that are used together. - Avoid creating…",
"content_html": "<p>A few notes on Data Oriented Design.</p>\n<p>- Study the data access patterns to determine where performance bottlenecks are.<br>- Group things together that are used together.<br>- Avoid creating dependencies between properties.<br>- Split infrequently accessed data as it's own thing.</p>\n<p>Traditional Object Oriented Approach:</p>\n<p><code>// Single object, everything grouped together.<br>class Circle {<br> Point Position;<br> Color Color;<br> float Radius;<br><br> void Draw() {}<br>}</code></p>\n<p>And you would store the Circle instances in a collection.</p>\n<p>Data Oriented Design:</p>\n<p><code>// Data that is used frequently together is grouped together.<br>class Body {<br> Point Position;<br> float Radius;<br>}<br><br>// Contains all the implied, non-explicit, circles.<br>class Circles {<br> List<Body> Bodies;<br> List<Color> Color;<br><br> void Draw() {}<br>}</code></p>\n<p>In this design there's no single Circle, just a bunch of implied circles. Operations can be run on the the circles at the same time. There's a separation of functionality. When you want to process an OO Circle you get all it's properties all at once even if you don't need them. In DO design the data that is used together is grouped together.</p>\n<p>Results:</p>\n<p>- Less cache misses.<br>- Improved performance in many cases.</p>",
"image": "https://pilvimaa.fi/media/posts/5/circles-1428521_1920.jpg",
"author": {
"name": "Pilvinen"
},
"tags": [
"Data Oriented Design",
"DOD"
],
"date_published": "2021-07-16T01:20:06+03:00",
"date_modified": "2021-07-16T01:20:06+03:00"
},
{
"id": "https://pilvimaa.fi/notes-on-why-oop-is-bad-and-how-to-solve-it/",
"url": "https://pilvimaa.fi/notes-on-why-oop-is-bad-and-how-to-solve-it/",
"title": "Notes on why OOP is bad (and how to solve it)",
"summary": "These are my study notes on a controversial video published on YouTube in 2016 by Brian Will called \"Object-Oriented Programming is Bad\". The video addresses many of the concerns I've…",
"content_html": "<p>These are my study notes on a controversial video published on YouTube in 2016 by <a href=\"https://www.youtube.com/channel/UCseUQK4kC3x2x543nHtGpzw\" target=\"_blank\" rel=\"noopener noreferrer\">Brian Will</a> called \"<strong>Object-Oriented Programming is Bad</strong>\".</p>\n<p>The video addresses many of the concerns I've had ever since I first started learning Java and OOP years ago. Since then I have switched to C#, but the concerns have remained mostly unchanged.</p>\n<p>The solution Brian Will suggests on the video is a combination of procedural and functional programming.</p>\n<p>From where I'm standing his solution seems ideal to many of my problems. Separation of data from logic clicks hard with me and I absolutely love certain concepts in functional programming (such a purity of functions) while I would not necessarily want to program fully functionally or abandon the notion of classes and objects altogether.</p>\n<p>If you are interested in functional programming in C# in particular I recommend Enrico Buonanno's book \"<strong>Functional Programming in C#</strong>\", which I own both as a paperback edition and as a digital book.</p>\n<p>However functional programming doesn't come without it's set of problems (to which I won't go in a depth here) and the combination of procedural and functional Brian Will suggest in the video below is a perfect match in my opinion.</p>\n<figure class=\"post__video\"><iframe loading=\"lazy\" width=\"560\" height=\"314\" src=\"https://www.youtube-nocookie.com/embed/QM1iUe6IofM\" allowfullscreen=\"allowfullscreen\" data-mce-fragment=\"1\"></iframe></figure>\n<p>My study notes on the video start here:</p>\n<p><strong>Problems with OOP:</strong><br><br><strong>NOT the problem:</strong><br>- Classes<br>- Performance<br>- Abstraction<br>- Aesthetics<br><br><strong>Code Aesthetics DO matter:</strong><br>- Elegance<br>- Simplicity<br>- Flexibility<br>- Readability<br>- Maintenance<br>- Structure<br><br><strong>Competing paradigms:</strong></p>\n<p><strong>Procedural and imperative (the default)</strong><br>- Procedural: \"No explicit association with data types and functions and behaviors.\"<br>- Imperative: \"Mutate state whenever you feel like it. No special handling for shared state. Cope with the problems as they arise.\"<br><br><strong>Procedural and functional (minimize state)</strong><br>- Get rid of state as much as possible.<br>- All or most of the functions should be pure, they should not deal with state.<br><br><strong>Object oriented and imperative (segregate state)</strong><br>- Segregate state. Divide and conquer the problem. Separate everything into objects.<br>- Segregation is a viable strategy up to a point of complexity.<br><br><strong>Claims:</strong><br>- Procedural code is better (even when not functional)<br>- Inheritance is irrelevant.<br>- Polymorphism is not exclusively OOP.<br>- Encapsulation does not work at fine-grained levels of code. This is the biggest problem with OOP.<br>- Fractioning code artificially to follow OOP rules leads to unnecessary complexity which is hard to follow.<br><br><strong>What is an object?</strong><br><br>An object is a bundle of encapsulated state. We don't interact with the state of that object directly. All interactions with that state from the outside world come in through from messages. The object has a defined set of messages called it's interface. We have private information hidden behind the public interface. When an object receives a message it may in turn send messages to other object. We may conceive of an object-oriented program being as a graph of object all communicating with each other by sending messages.<br><br>For object A to send a message to object B, A must hold a private reference to B.<br>Messages may indirectly read and modify state.<br>The moment objects are shared encapsulation flies out of the window.<br><br><strong>Solution, procedural programming:</strong><br><br>- Prefer <strong>functions</strong> over methods. Write <strong>methods</strong> only when the exclusive association with the data type is not in doubt, e.g. ADT's (abstract data types like queues, lists, etc.)<br><br>- When in doubt -> parameterize. Do not encapsulate the state of the program at fine-grained level. However, shared state is a problem. It cannot be fully solved without pure functional programming. This means that rather then passing data through global variables you should instead make that data explicit parameter of the function so it has to be explicitly passed in. Any time you get the temptation to pass in data through a global because it's convenient you should seriously reconsider.<br><br>- When you DO end up with globals - Bundle the globals into structs/records/classes, ie. bundle them logically into data types. Even if this effectively means you have a data type with one instance in your whole program this little trick can often make your code seem just a little bit more organized. In a sense you are just using data types in this way to create tiny little sub namespaces. But if you do a good job logically grouping your globals this way as a side benefit this supports parameterization - you can more conveniently pass this global state to functions.<br><br>- Favor pure functions. If you see an opportunity to make a function pure it's a good policy to take that opportunity. Pure functions are easier to understand and to make correct. This is easier when efficiency is not a priority.<br><br>- You should try to encapsulate (loosely) at the level of namespaces/packages/modules. Think of each package as having it's own private state and public interface.<br><br>- Don't be afraid of long functions! Most programs have key sections. The problem of extracting everything into separate functions breaks up the natural sequence of code and is spread out of order throughout the code base. Prefer commenting each section of the function when needed over extracting the sections. Keep in mind general code readability for long functions: Prefer extracting to nested functions. Don't stray from left margin too far or for too long. Watch out for too much complexity and split up and extract to other functions as needed. Constrain scope of local variables. When in doubt enclose variables into curly braces to limit their scope - even better, enclose them into their own anonymous functions.</p>\n<p>Good luck!</p>",
"image": "https://pilvimaa.fi/media/posts/4/work-731198_1920.jpg",
"author": {
"name": "Pilvinen"
},
"tags": [
"Procedural Programming",
"OOP",
"Functional Programming"
],
"date_published": "2021-05-23T15:58:49+03:00",
"date_modified": "2021-05-23T16:06:34+03:00"
},
{
"id": "https://pilvimaa.fi/radians-to-degrees-made-simple/",
"url": "https://pilvimaa.fi/radians-to-degrees-made-simple/",
"title": "Radians to degrees made simple",
"summary": "I was thinking about radians today and how they are annoying and unintuitive to deal with. After thinking about it for a while I realized that when you look at…",
"content_html": "<p>I was thinking about radians today and how they are annoying and unintuitive to deal with. After thinking about it for a while I realized that when you look at radians in a certain way, there's an emerging pattern which makes radians intuitive, fun, and easy.</p>\n<p>You know how we're taught about radians that:</p>\n<pre>2π radians = 360°<br>π radians = 180°</pre>\n<p>And so on. And you can do your degree conversions like so:</p>\n<pre> π radians<br>----------- = 1°<br> 180</pre>\n<p>And it's all right and well, but... radians can sometimes be kind of hard to keep in your head when you do more complex conversions.</p>\n<p>And if you're like me, it's easy to lose track of what you're doing and what the numbers actually represent. You end up going back and forth and becoming confused.</p>\n<p>Don't worry. There's an easier way to visualize radian conversions.</p>\n<p>Take a look at this:</p>\n<pre>2 / 1 * π radians = 360°<br>2 / 2 * π radians = 180°<br>2 / 3 * π radians = 120°<br>2 / 4 * π radians = 90°<br>2 / 5 * π radians = 72°<br>...</pre>\n<p>When we always divide two by parts-of-a-circle we get a really nice uniform and intuitive progression of numbers.</p>\n<p>2 / 1 is of course equal to 2, so that would be the 2π radians, giving us 360°.</p>\n<p>2/2 is of course equal to 1, ie. 180°.</p>\n<p>The only reason I even put them there is to make the whole thing uniform and easy to visualize.</p>\n<p>Notice how the divisor starts from 1 and goes to 2, 3, 4, 5 ... and so on. You can think of the divisor as \"parts of the circle\". Two times π is a full circle, 360°. When your dividend is always two, like in the above example, the divisor then always directly represent into how many parts the circle has been divided into.</p>\n<pre>1 = full circle, 360°.<br>2 = divided into two parts, 180°.<br>3 = divided into three parts, 120°.<br>4 = divided into four parts, 90°.<br>...</pre>\n<figure class=\"post__image\"><img loading=\"lazy\" src=\"https://pilvimaa.fi/media/posts/3/Radians-2.png\" alt=\"Radians and other units\" width=\"1920\" height=\"1080\" sizes=\"(max-width: 1920px) 100vw, 1920px\" srcset=\"https://pilvimaa.fi/media/posts/3/responsive/Radians-2-xs.webp 640w ,https://pilvimaa.fi/media/posts/3/responsive/Radians-2-sm.webp 768w ,https://pilvimaa.fi/media/posts/3/responsive/Radians-2-md.webp 1024w ,https://pilvimaa.fi/media/posts/3/responsive/Radians-2-lg.webp 1366w ,https://pilvimaa.fi/media/posts/3/responsive/Radians-2-xl.webp 1600w ,https://pilvimaa.fi/media/posts/3/responsive/Radians-2-2xl.webp 1920w\"></figure>\n<p>And so on. So, how many radians are in one degree? Easy. There are 360 degrees in a full rotation, so we just drop in 360:</p>\n<pre>2 / 360 * π radians = 1°</pre>\n<p>Why does it work you ask?</p>\n<p>Since there are <em><strong>two</strong></em> π radians in a full circle, dividing two by how many degrees we want we get a multiplier for the conversion and everything stays nice and uniform.</p>\n<p>In my opinion this approach makes it much easier to visualize radians to degrees conversions than using \"π radians = 180°\" as the starting point.</p>",
"image": "https://pilvimaa.fi/media/posts/3/Radians.png",
"author": {
"name": "Pilvinen"
},
"tags": [
"Radians",
"Math"
],
"date_published": "2021-01-07T20:33:13+02:00",
"date_modified": "2021-01-07T21:06:38+02:00"
},
{
"id": "https://pilvimaa.fi/binary-addition/",
"url": "https://pilvimaa.fi/binary-addition/",
"title": "Binary addition",
"summary": "Let's take a look at how binary addition can be done by using bitwise operations. Why would we want to do this? Simply because we can. And also because it's…",
"content_html": "<p>Let's take a look at how binary addition can be done by using bitwise operations. Why would we want to do this? Simply because we can. And also because it's fun and will help us understand how bitwise operations work and can be used together.</p>\n<pre><code class=\"language-cs\">\npublic byte AddBytes(byte a, byte b) {\n while (b != 0) {\n var carryBits = (byte) (a & b);\n a = (byte) (a ^ b);\n b = (byte) (carryBits << 1);\n }\n return a;\n}\n</code></pre>\n<p>Let's take an overview of what just happened.</p>\n<p>Essentially we <strong>add</strong> two bytes together. You get that much from the name of the method.</p>\n<p>The signature of the <strong>AddBytes</strong> method also tells us that it takes in two <strong>bytes</strong>, <strong>a</strong> and <strong>b</strong> as parameters, and returns a <strong>byte</strong> which contains the result of the addition.</p>\n<p>Inside the method we loop until <strong>b</strong> is zero. Inside the while loop we <strong>AND</strong> (<strong>&</strong>), then we <strong>XOR</strong> (<strong>^</strong>), and finally we <strong>left shift</strong> (<strong><<</strong>) by one.</p>\n<p>And, apparently, as a result we get two binary numbers added together nicely, just like in our everyday base-10, where we could calculate something like <code>2 + 2 = 4</code> </p>\n<p>So why does the above piece of code work and do what it does? Let's break it down and make it simple.</p>\n<p>The first operation inside the while loop is storing temporarily in <strong>carryBits</strong> variable the result of the bitwise <strong>AND</strong> (<strong>&</strong>) operation between a and b, ie:</p>\n<pre><code class=\"language-cs\">var carryBits = (byte) (a & b);</code></pre>\n<p>There's a little bit of casting going on here through and through because C# doesn't support performing bitwise operations directly on the actual <code>byte</code> type, it converts them for the bitwise operations. You could also perform these operations on the <code>int</code> type, for example, in which case you would have:</p>\n<pre><code class=\"language-cs\">var carryBits = a & b;</code></pre>\n<p>Don't get distracted by the casting.</p>\n<p>So, we're carrying bits. But what is carrying? Let's take a quick refresher on carrying in math. Carrying is just like in normal everyday addition:</p>\n<pre><code class=\"language-cs\">\n 122\n+ 921\n= 1043</code></pre>\n<p>Where you add the numbers together which are on top of each other and you combine them at the bottom for the final result. You have the ones, you have the tens, you have the hundreds, and you have the thousands. In the same way in binary you have the ones, you have the twos, you have the fours, you have the eights, and so on. It's just base-2 (0, and 1) instead of base-10 (0, 1, 2, 3, 4, 5, 6, 7, 8, and 9) before the numbers flip over to the next scale.</p>\n<p>In the above example carrying happens when you add the one hundred and nine hundred together, you carry the one to the thousands and in hundreds you then have a zero because <code>100 + 900</code> doesn't leave a remainder in the hundreds. If you had <code>100 + 1100</code> instead you would add the thousands: <code>0 * 1000 + 1 * 1000 = 1000</code>, and then you would add the hundreds: <code>1 * 100 + 1 * 100 = 200</code>. And finally you would add all the different values together (no more carrying to process) and you'd end up with a total of 1200.</p>\n<p>So carrying happens when you add two numbers together (for example <code>9 + 9</code>) and they don't fit in the scale (in this case the ones) and you have to move, ie. you'd have to carry, the overflow to the tens. You'd end up with 18.</p>\n<p>In binary it works in exactly the same way. When you get overflow from addition you move it up, you carry it over.</p>\n<p>The only differences are that in binary you, usually, go from right to left, and 0 means that the value isn't set, and 1 means the value is set. Therefore:</p>\n<pre><code class=\"language-cs\">1101</code></pre>\n<p>Simply means, from right to left:t 1 * 1 + 0 * 2 + 1 * 4 + 1 * 8. From right to left -> ones (set), twos (not set), fours (set), eights (set). Giving us the total of 13 in our every day base-10.</p>\n<pre><code class=\"language-cs\">\nvar a = (byte) 0b_0101; // (This is a \"binary literal\" in C#)\nvar b = (byte) 0b_0110;\nvar carryBits = (byte) (a & b);</code></pre>\n<p>So, when we do a bitwise AND operation, like <code>0101 & 0110</code>(as shown in the above example) simply imagine in your head that you place the numbers on top of each other like in regular base-10 calculus:</p>\n<pre><code class=\"language-cs\">\n 0101\n& 0110\n= 0100</code></pre>\n<p>The bitwise AND operation returns 1 only when the two overlapping binary numbers are both 1. For all other binary values it returns 0.</p>\n<p>So why are we doing this and storing the result in <code>carryBits</code>? Because it's exactly the same as when you add <code>100 + 900</code>, you know you need to carry the hundreds into thousands, except now you need to carry the overflowing bits. Now we know that there are overlapping values, and when we add them together we will need to carry this bit position to the next one.</p>\n<p>It should be starting to make sense now. Let's move on.</p>\n<pre><code class=\"language-cs\">a = (byte) (a ^ b);</code></pre>\n<p>Here we are storing the result of an <strong>XOR</strong> (<strong>^</strong>) operation between a and b in the <strong>a</strong>. We are basically <em>simulating addition</em> with XOR.</p>\n<p>What XOR does is:</p>\n<pre><code class=\"language-cs\">\n 0101\n^ 0110\n= 0011</code></pre>\n<p> It returns 1 only when the two bits that are being compared are different from each other.</p>\n<p>We have already safely stored the overflowing bits in the temporary <code>carryBits</code>and now we have copied the rest of the bits which are <em>not</em> overflowing (no need to carry anything) to <strong>a</strong>.</p>\n<p>We can now perform the final bitwise operation which is the <strong>left bitshift</strong>. What left bitshift does is that it simply moves all the bits left by whatever number you want to move them. For example:</p>\n<pre><code class=\"language-cs\">\n var a = (byte) 0b_0001; // a is 0001\n a = a << 1; // a is 0010\n a = a << 1; // a is 0100\n a = a << 1; // a is 1000\n a = a << 1; // a is 0000</code></pre>\n<p>In the final left bitshift operation we lose our data. By default we get behavior which simply drops overflowing bits - you lose them, they are gone.</p>\n<p>And if you move it by two:</p>\n<pre><code class=\"language-cs\">\nvar a = (byte) 0b_0001; // a is 0001\na = a << 2; // a is 0100</code></pre>\n<p> The bits are simply shifted left by two positions.</p>\n<p>By now you might be starting to realize \"Wait... but what if I have an overflow, carry bit, at position like:</p>\n<pre><code class=\"language-cs\">1000</code></pre>\n<p>Where there is nowhere to go?\" </p>\n<p>That's right. In that kind of situations you would get an incorrect answer from bitwise binary addition. For simplicity's sake this article doesn't show you how to handle situations like that where you actually run out of space from your value type. It can be handled, but the code gets much more complex and is therefore not a very good place to show the basic principles of binary bitwise addition and is therefore out of the scope of this article.</p>\n<pre><code class=\"language-cs\">\nb = (byte) (carryBits << 1);</code></pre>\n<p>Now that you understand what a left bitshift does, it's not hard to see what's going on here. We're simply <em>moving the carry bits</em>, the overflowing bits, one step further in the scale of numbers. One becomes two, two becomes four, and so on.</p>\n<p>We assign the result into <strong>b</strong>, all the numbers in b just moved one step left. The while loop is now ready for another round until there are no more <code>1</code> bits left in <strong>b</strong>.</p>\n<p>When b is zero we're ready to exit the while-loop and return <strong>a</strong> where we have shifted, combined, and shuffled all of our bits iteration by iteration. We're moving and fitting everything together in a nice and orderly line of bits.</p>\n<p>Logic! There's nothing better.</p>\n<p>If you don't understand binary addition straight away by simply reading this article, don't fret. There's hope for you yet. It's like driving a bicycle. You don't learn how to drive by simply reading a manual. Once you understand the basic principles of binary bitwise operations you have to play with them, and experiment with them.</p>\n<p>That's how you learn.</p>",
"image": "https://pilvimaa.fi/media/posts/2/Binary-1920x1280.jpg",
"author": {
"name": "Pilvinen"
},
"tags": [
"Csharp",
"C#",
"Bitwise",
"Binary"
],
"date_published": "2020-10-28T23:12:01+02:00",
"date_modified": "2020-10-29T14:08:34+02:00"
},
{
"id": "https://pilvimaa.fi/array-flattening/",
"url": "https://pilvimaa.fi/array-flattening/",
"title": "Array flattening",
"summary": "One dimensional arrays, or flat arrays as they are sometimes called, have desirable properties. They are fast. They are simple to access and to iterate through. They can easily be assigned…",
"content_html": "<figure class=\"post__image\"><img loading=\"lazy\" src=\"https://pilvimaa.fi/media/posts/1/Array_flattening.png\" width=\"1281\" height=\"720\" sizes=\"(max-width: 1920px) 100vw, 1920px\" srcset=\"https://pilvimaa.fi/media/posts/1/responsive/Array_flattening-xs.webp 640w ,https://pilvimaa.fi/media/posts/1/responsive/Array_flattening-sm.webp 768w ,https://pilvimaa.fi/media/posts/1/responsive/Array_flattening-md.webp 1024w ,https://pilvimaa.fi/media/posts/1/responsive/Array_flattening-lg.webp 1366w ,https://pilvimaa.fi/media/posts/1/responsive/Array_flattening-xl.webp 1600w ,https://pilvimaa.fi/media/posts/1/responsive/Array_flattening-2xl.webp 1920w\"></figure>\n<p><strong>One dimensional arrays</strong>, or <strong>flat arrays</strong> as they are sometimes called, have desirable properties. They are fast. They are simple to access and to iterate through. They can easily be assigned to contiguous memory blocks.</p>\n<p>The above picture shows how <strong>indexing</strong> works when we turn our multi-dimensional array into a flat array.</p>\n<pre><code class=\"language-cs\">int index = rowWidth * row + col;</code></pre>\n<p>The above code pretty much explains it all. But in case you're like me, and you sometimes have difficulties understanding things until you've studied them thoroughly, I will walk you through the gist of it.</p>\n<p>In the example above we have a multi-dimensional <code>3 x 4</code> array. 3 rows (0-2) and 4 columns (0-3) and, and we want to find the index for <code>1,2</code>in other words, we want the index for <strong>row position 1</strong>, <strong>column position 2</strong>, and we want to find that index position in our <em>one dimensional flat array</em> which is essentially emulating a multi-dimensional 3 x 4 array.</p>\n<p>We take the <strong>width</strong> of our <strong>rows</strong>, ie. their actual size (<strong>4</strong> columns wide) and we <strong>multiply</strong> it with the <em>index</em> of the <strong>row</strong> that we want to access (<strong>1</strong>). In other words <code>rowWidth * row</code> ie. <code>4 * 1</code> in our example. This gives us the combined length of all the <em>previous</em> rows of data (because the index starts from 0, we essentially always skip the current one), ie. <strong>row 0</strong> is the previous row in this case. <code>4 * 1 = 4</code>We have 4 entries in all the previous rows.</p>\n<p>Next we want to add our index location on the <strong>column</strong> to this number. This gives us the final index value. In our example our location on the column is 2, therefore we add <code>4 + 2 = 6</code>, giving us the final index of <strong>6</strong>.</p>\n<p>The explanation is probably harder to follow than the code and picture, but there you have it.</p>",
"image": "https://pilvimaa.fi/media/posts/1/Array_flattening.png",
"author": {
"name": "Pilvinen"
},
"tags": [
"Csharp",
"C#",
"Arrays"
],
"date_published": "2020-10-28T16:42:04+02:00",
"date_modified": "2020-10-29T02:57:35+02:00"
}
]
}