• entries
29
41
• views
1502

Unsettled World, the working title for my most overly-ambitious project yet.  Here I shall blog all of the resultant madness.

## It's NOT a Simulation! :D

I think I've finally put my finger on the button(s)(quite a few apparently) that may explain my project.  It's helping me to clarify my vision anyhow, so just play along okay? I'm not building a game simulation....  I've been trying to use that term because it's what everybody else uses, and it really just doesn't fit my project at all. There is no single starting point and there is no single ending point.  The story elements are to be primarily interaction based and not strictly tied to highly specific locations or circumstances.  The visual synchronicity of the experience is only dependent on entity proximity, which in effect makes it more of a relativistic kind of synchronicity than the absolute kind anyhow.  All gaming entities(players,npcs,mobs,bosses..etc) will be autonomous actors in the gaming environment, regardless of what controls it.  e.g. Each NPC will essentially be their own entirely isolated behavioral code(running on a server OR client node somewhere).  This code will generate a game entity that is just as actualized in the environment as any other object or player character, it will just behave according to its "script".  All in real-time, with client controlled physics. So, I'm building a "Multiple Entity Gaming Environment".... It's a working title..   In essence, instead of streaming data that has been aligned to a unified simulation out to many many clients, I'm streaming data about many many ongoing semi-synchronous real-time "INTERACTIONS" from game clients into a massive, fast, circular buffer.  From which, the servers shall draw conclusions and route corrective actions to multiple endpoints simultaneously, and hopefully in many cases, preemptively. When we're worrying about things in a game becoming out of sync, it's usually in relation to some kind of fast motion or relative positioning, a gun-shot or a left hook, something that is moving/has moved/will move and the event needs to have the same outcome on multiple gaming clients.  Users in most games with this kind of action, don't generally care if their team-mate was .5 meters closer to them then they looked like they were when they helped shoot down the boss.  They only care that the shots they saw coming from that team-mates gun were hitting the mark that the team-mate was aiming at, which was hopefully the boss, if the team-mate is any good. This may be something of a contrived example, but it more or less illustrates my point.  As long as the servers can provide the appropriate real-time adjustments to certain aspects of the entity interactions to make the synchronicity fall into a zone of acceptability, then nearly all the heavy lifting can be done by the client without running every client input into and back out of a tightly wound server controlled simulation.  Then, how do we control anything?  The major change here is how Authority is implemented, in a standard server-simulation, the policy is trust nobody.  Here, it is trust everybody, but also verify and cross-check everything.  In this paradigm the authority is purely corrective in nature, with designs on preemptive corrective abilities(where applicable), but primarily relying on minuscule corrective actions that steer the simulation variances into a zone of acceptability. Another fairly extensive level of control comes from the decoupled nature of the system.  Since all entities are autonomous components, they can each be turned on or off at will.  So, that pretty much gives us all the control, never heard of before.  Each entity can be rewritten, debugged, uploaded and instantiated into the game.  Without a single system restart, or change to the game code(goals, I got em).    So, since we aren't wasting all of our server horsepower on a massive interactive simulation, we can use it to play cop, crossing-guard, mail-carrier and chauffeur all at once. We can implement heavy-handed position and relative distance checking into the entity data feeds that are being streamed INTO the servers, we can correlate those patterns with known good behaviors and known cheat behaviors/known out of bounds behaviors.  We can implement corrective actions that will steer the entities back into synchronous path(s) when necessary.  And we can allow certain entities to become out of sync for longer periods without risking the integrity of any one game-wide "simulation".  Generally speaking, entities that fall too far out of sync can either get dropped like a laggy player, or will be re-instantiated from a node of the network closer to the action, depending on it's level of importance to the current branch of the narrative/network or game conditions. Haha, well I hope that this rambling mess helps you understand what I'm doing better.  The more I write it down the clearer it becomes to me.  I started building this beast before I even knew what it was going to look like.

## All Servers Are Now On Linux!

Okay, the servers are now all running on Linux.  I had initially intended to wait until all development was mostly completed to make the transition but now I'm glad I've done it.  And, the more I use Visual Studio Code, the more I appreciate its simplicity and how well it's adopted the Linux environment.  It's starting to feel like home now that I've got a few active projects going in it.  Plus it's nice to clear my Windows development space, I could have 6 or 7 copies of Visual Studio open at one time before this, now I've only got the Unity game client and whatever test projects I need to sort out the next functional leap.   The rest is all in a Linux VM that I can VNC into if I need to use Visual Studio Code, otherwise I can do everything server side with an SSH client. The next step for these servers is to massage them into actual Linux Daemons, which shouldn't be HUGE, but it will take a minor rewrite of some bits of code.  Not a huge issue until I have a real server though.  So, really the next step is to get the base functionality built out in the next 3 Servers(Mob, Narrative, & Social) Here's a quick video of the client(Unity Windows) testing out all 3 current servers running on Linux. Top to Bottom: Avatar Server(Authentication/inventory/etc..), Economy Server(Banking/etc.), Action Server(Online Multi-Player/etc..) First we test the Action Server with the standard Ghost test you've seen here before, but then I mess a little with the banking features(transferring credits to/from inventory), and then I show how the drop item from Inventory and Pickup item(into inventory) works. Enjoy.   As always, more to come soon. linux_3.mp4

## And the Messages are ROUTING!!!

I have succeeded in creating a cross-platform, custom combination MQTT Client/Broker or "MQTT Router" that can Route messages to other MQTT Brokers/Routers.  They dynamically build connections to each other and test route latency.  They currently do NOT do any best route calculations.  But that is only a small behavioral ability that I can add at a later date and still feel like it's totally functional right now. In the below images you will see 3 windows, TOP = PRIMARY Router(Kinda like a DNS server, it distributes the Router hellos around so everybody knows where everybody else is. MIDDLE = PEER Router #1 on Linux BOTTOM = PEER Router #2 on Windows   Here you see the three servers connecting and subscribing to each other's publications and whatnot.   Here the Route-able message is submitted to the PRIMARY, Routed Through PEER#2  for  PEER#1   Submitted to PRIMARY, Routing Through PEER#1  for  PEER#2   And Submitted to PEER#2, Routed Through PEER#1  for  PRIMARY   Not the most interesting screen shots, maybe I'll put together a little video showing it in ACTION! haha.. Either way, a few days of hacking and I now have the core of my Content Delivery Network, at least ready for the next phase of integration and testing. Time to get back to writing the actual GAME SERVERS!!  hahaha I've got some serious refactoring and whatnot before I post any of this code though, so please be patient if you're actually interested in seeing it.

## A whole lot of Hellos..

Well, I've made some significant progress on my MQTT Router.  I've successfully brought 3 nodes online, 1 Primary and 2 Peers, and they are communicating Hellos and building connections between each other. Here you see the Primary Router's output(Linux): Checks command line arguments (mode, local address/port, primary router address/port) Integrated client subscribes to it's local command feed (IP:Port) Integrated client ON Primary subscribes to the "Router-Hello" feed. Waits for peers to say Hi. Builds new connections to new Peers ReQs Hellos for each Router node on the network. Peer Router #1(Windows): Checks command line arguments (mode, local address/port, primary router address/port) Integrated client subscribes to it's local command feed (IP:Port) Begins sending periodic Hellos to Primary Router Node Processes Hellos from other router nodes requeued by the Primary. Builds connections to other nodes. Monitors those connections by sending Ping Messages to calculate the RTT. Peer Router #2(Windows): Same as Peer1 Here's what the ping output looks like(I had to get rid of some console output to see all the hellos and get them working right.)   So, now that my routers know where everybody is, and how long it takes to get there.  All I need to do now is iron out the message "routing" bits and these things will actually be dynamic routers for the MQTT protocol... I'm kinda pleased with myself so far.  You're probably still wondering what the hell I'm doing with this stuff... That's okay, I am too.  Kinda.  I'm currently thinking of it as a Content Delivery Network.  It allows me to push Content out to clients, but it also allows clients to publish/subscribe Content to/from Other Clients. If I integrate this into my game client, it gives me an entirely separate data channel for content delivery, not to mention the peer-to-peer networking implications. All for now, will share some code and an updated specification when they're moving messages.

## Let's Make Routing!!

So, the MQTT exercises continue.  Now that I've established the basic topology.  Let's throw together a simple protocol to make it all work!!  We'll call it MQTT-rp: Okay, what's the purpose here?  We need a protocol to allow a combined MQTT server & client to become a Message Router without changing the MQTT protocol they speak. Well, unlike almost any other routing protocol on the planet, this one will completely live in the application layer, but that gives us some options.  We've basically got 2 different data spaces we can play with.  We have the topic or the message/payload field in which we can place our special routing codes.  Since MQTT is already built to "route" the message based on the content of the topic field, we should use that to our advantage and keep all direct routing codes in the topic field.  First things first, our MQTT-Routers will need a way to contact/find each other, so the protocol will have to hinge on at least 1 primary network node which will host a channel that distributes connect info to all other Routers.  All other authenticated routers will periodically(less than 30sec) post up their info to this channel, timestamped at the point of origin so the subscribed routers can calculate the latency on that route.  Router Hello Message Format: Topic: "Router-Hello" Hello Message: 4Byte Router ID(IP Address), 4Byte Origin Time Stamp, + 8Bytes for each hop(ip & timestamp) Time Message: 4bytes '0000', 4 byte time stamp. Also on the Router-Hello channel the Primary Node will publish a regular time code so each Router can synchronize its clock. Okay, we've established that all routers will subscribe to the "Router-Hello" channel of their "Primary Node" and this router/channel will distribute connection and time information around the network just by being an MQTT channel.  Very nice.  Now that we know where everybody is and approximately how much time it takes THEM to get to the primary node, let's do some proactive routing table building and start pinging each node for latency information.  In order to do this, we'll need to establish a return path for data to follow, preferably one that doesn't route everything off to the primary node or something silly first.  Each Router will establish a channel for each other known router on the network, with a Topic that matches the other Routers ID.  And each Router will subscribe to ALL of its named channels.  These channels will be used to route messages and to return pings for latency testing.  When a Router needs to test its latency to another router, all it has to do is send a message with it's own ID as the topic. Okay, so that lets us get the latency numbers for all of the direct hops on the network.  Now what about actual routing path latency and actual message routing? Routed Message Format: Topic: 4byte destination router ID Message: For Delivery To 4byte ID | 1byte topic length | 4bytes message length | Delivery Topic | Delivery Message | Tracking Information(+ 8Bytes for each hop(ip & timestamp)) Now, we know what our routed message looks like, how does that help us figure out an actual routing table and latency?  The "For Delivery To" field will give us that.  This field allows us to send a message addressed to a specific next-hop router, with instructions on where to send it immediately afterwards.   If we also set the "Delivery Topic" to the source router ID this gives us the ability to route a message across a second hop before it returns back to origin.  And now we can start doing some more useful routing table construction. So, each router will maintain a sorted list of some type that contains the latency to each other router, and the assisted path latency to other routers via every available next hop Router.  Okay, now our Routers can make some educated guesses as to the best next hop to send messages to that are addressed for other routers. ...  with this information I think I can begin testing. Thanks for following along..   I'll update as soon as I have some results/code to share.

## More Crazy Infrastructure.

The past few days I've been working on figuring out how the "peer-to-peer" bits of my game network are going to work.  For now I'm testing with MQTT, because it's light and fast and reliable, but you could pretty much replace MQTT with ZeroMQ or just some raw TCP/UDP sockets code or anything else that fits the bill.  In order to build the most robust gaming environment I can I want to provide the capabilities to the player/community to help build out the games network infrastructure.  Allowing a player to opt-into hosting a relay node, or simply enabling the built in relay features in their clients.  In that spirit, I'm going for something of a distributed mesh type topology with some rudimentary "routing" code built into the nodes themselves.  For MQTT, I'm planning to use specific subscription topics that are universal throughout the system like node names or etc, so that the "Relays" or "Routers" can determine which channel(s) to put the data on based on latency/etc.  Obviously, if I'm going to use MQTT, there aren't really any out of the box solutions for what I'm trying to achieve.  Additionally, I'll be wanting to authenticate the MQTT network based on data in my game server cluster(probably via Redis), so it'll be a custom code solution using somebody else's brilliant netcode. Below you will see a screenshot of my first performance tests of my base functional MQTTnet server & a simple mqtt client hammering away at it.  The server is .net core running on a linux VM on my local machine.  The client is using MQTTnet as well, running on the windows client. The client here is sending batches of 10000 messages to the server, it's also subscribed to the same topic, so it waits until it gets all the sent messages back and then outputs the time it took in ms. The messages are set to a topic of "LoadTestinAllDayLong" and the message is just a random GUID.  So, it looks like right now it's pushing about 2000 messages per second, running over TCP, with reliability(on a 4core 4gb virt essentially over a loopback)..  Not too bad at all, can't wait to test it over a real network though. Here's a quick sketch of the idea as it stands, broad strokes again.. Keep in mind now, this won't be the primary game network, it will be used for localized simulations, direct peer-to-peer activities, or alternative channels for transient data to be moved around the network. Server Source: using System; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using MQTTnet; using MQTTnet.Server; using MQTTnet.Protocol; using MQTTnet.Diagnostics; namespace UWMqtt { class Program { public static async Task Main(string[] args) { MqttServerOptions options = new MqttServerOptions(); options.DefaultEndpointOptions.ConnectionBacklog = 10000; options.DefaultEndpointOptions.Port = 1883; options.DefaultCommunicationTimeout = new TimeSpan(0,0,5); options.ConnectionValidator = c => { if (c.ClientId.Length < 10) { c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; return; } if (c.Username != "yummyusername") { c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; return; } if (c.Password != "chewypasswordstring") { c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; return; } c.ReturnCode = MqttConnectReturnCode.ConnectionAccepted; }; MqttNetGlobalLogger.LogMessagePublished += (s, e) => { if (e.TraceMessage.Level == MqttNetLogLevel.Info || e.TraceMessage.Level == MqttNetLogLevel.Error || e.TraceMessage.Level == MqttNetLogLevel.Warning) { String trace = $">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}"; if (e.TraceMessage.Exception != null) { trace += Environment.NewLine + e.TraceMessage.Exception.ToString(); } Console.WriteLine(trace); } }; IMqttServer mqttServer = new MqttFactory().CreateMqttServer(); await mqttServer.StartAsync(options); Console.WriteLine("Press any key to exit."); Console.ReadLine(); await mqttServer.StopAsync(); } } } Client Source: using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using MQTTnet; using MQTTnet.Client; namespace mqttClientHammer { class Program { public static bool running = true; static long mrec = 0; static long msen = 0; public static void Main(string[] args) { MqttFactory factory = new MqttFactory(); IMqttClient mqttClient = factory.CreateMqttClient(); IMqttClientOptions options = new MqttClientOptionsBuilder() .WithClientId(Guid.NewGuid().ToString()) .WithTcpServer("ser.ver.ip.add", 1883) .WithCredentials("yummyusername","chewypasswordstring") .Build(); mqttClient.Disconnected += async (s, e) => { Console.WriteLine("### DISCONNECTED FROM SERVER ###"); await Task.Delay(TimeSpan.FromSeconds(1)); try { await mqttClient.ConnectAsync(options); } catch { Console.WriteLine("### RECONNECTING FAILED ###"); } }; mqttClient.Connected += async (s, e) => { Console.WriteLine("### CONNECTED WITH SERVER ###"); // Subscribe to a topic await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic("LoadTestinAllDayLong").Build()); Console.WriteLine("### SUBSCRIBED ###"); await Task.Factory.StartNew(() => { publisher(mqttClient); }); }; mqttClient.ApplicationMessageReceived += (s, e) => { //Console.WriteLine("### RECEIVED APPLICATION MESSAGE ###"); //Console.WriteLine($"+ Topic = {e.ApplicationMessage.Topic}"); //Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}"); //Console.WriteLine($"+ QoS = {e.ApplicationMessage.QualityOfServiceLevel}"); //Console.WriteLine(\$"+ Retain = {e.ApplicationMessage.Retain}"); //Console.WriteLine(); mrec++; }; // StartAsync returns immediately, as it starts a new thread using Task.Run, // and so the calling thread needs to wait. mqttClient.ConnectAsync(options); Console.ReadKey(); } static void publisher(IMqttClient mc) { long lmr = 0; Stopwatch sw = new Stopwatch(); while (running) { if (mc.IsConnected) { sw.Start(); Parallel.For(0, 10000, i => //for (int i = 0; i < 1000; i++) { try { mc.PublishAsync("LoadTestinAllDayLong", Guid.NewGuid().ToString()); msen++; } catch (Exception) { } }); } else { Console.WriteLine("Load Test Waiting on Reconnect..."); } if (mrec != msen) { lmr = mrec; Thread.Sleep(100); while(mrec != lmr) { lmr = mrec; Thread.Sleep(100); } } Console.WriteLine("MRec: " + mrec.ToString() + " MSen: " + msen + " T: " + (sw.ElapsedMilliseconds).ToString()); sw.Stop(); sw.Reset(); Thread.Sleep(1); } } } }

## Elucidation or Hallucination?

I've been having some trouble explaining myself lately.   So I thought I might draw some more pictures instead.  Please tell me, does this paint a clearer picture of my rambling madness?  In the picture below you will find my effort to explain how the system I'm building is structured, conceptually.  In a standard multiplayer game, there is only one simulation, and generally it's being tightly controlled by its game server(s).  All servers and all clients are running the exact same simulation, well except for those that can't play because of lag.  But I don't need to explain that.. As you can hopefully see, the system I'm attempting to build will be more like a conglomerate simulation.  One which cannot play out EXACTLY the same for everybody, but close enough that it can still feel like a shared experience.  One in which there are autonomous pieces of code that exist entirely outside the scope of the games internal logic loops, as separate entities within the game construct.  And when a player has too much lag for multi-player action, they can still explore the world and interact with the games autonomous AI with nearly the same quality of experience, since AI can buffer and offload time sensitive interactive processing onto the client. So, really, my client isn't playing animations to a clock tick.  It's running code chunks in a space/time construct defined only by its ability to communicate with the available server resources and/or peers(something I've not really touched on anywhere, down the road maybe). The animations that result from this process are kinda like the particles in a standard game, the server allowed the shot and controlled precisely its path, but the particle effects are controlled by the client and are what the player sees and expects when they shoot something.  ALL the animations(particle effects & everything else visible) that happen in the client construct here are just the presentation of code running in an approved region within the construct(code bullets moving through my simulation), that region might be isolated on one client, or it might be a shared simulation that interacts with all players forming a key part of the games Narrative. Any and all feedback is appreciated.   The more I explain this to other people, the clearer it becomes to me.

## The Wheel of Time Time Time..

I posted this in the forum earlier from my phone and then realized it wasn't really a forum type post...  So, here it is in the permanent record of my project blog where it belongs. So, I've been struggling with my perception of time.  Haha, at least with how it pertains to the game system I'm building.  Some of you may have even noticed. My biggest hurdle has been language I think.  Everybody uses words and sometimes I'm not sure they are even sure what those words really mean.  E.g. Frame, Simulation, Tick, Time..  It's taken me a few weeks of just watching how they are used to put them into any kind of context that makes sense for my game. So I took a long look at the code I'm writing and lo and behold, I'm essentially creating a simulation frame number that's synchronizing the rest of the system..  I'm just doing it in a very silly and wasteful way. So I guess this is more about me saying, yup you were right all the TIME.. Lol Anyhow, the primary reason behind most of my confusion is my desire to build a system(servers and clients) that can allow the clients to operate somewhat autonomously in a bulk of the gameplay senarios that I have in mind.  By that I mean the system will be retrospectively authoritative wherever possible.  For all of this to work, it implied to my mind that the clients essentially are running different simulations from each other.  And there we find our culprit.  Somehow while riding my bicycle today, clarity.  In order for simulation elements to truly be shared, there has to be a "server simulation" that synchronizes the shared portion of each clients simulation.  And as soon as you refactor the client only simulations as more or less unrelated client code..  Its the same simulation frame synchronization scheme everybody else uses...    Smh.   ...when you end up poorly reinventing the wheel and don't even notice until it goes flat...

## Linux Server Action!

Here's a look at the first server executing from the Linux environment.  I chose to move the Action Server over first because it's still pretty small code-wise and didn't have any file system code that would need touched.  Was going for an easy win.  It worked. Here you can see another "ghost" test, but this time you can see a little of what's going on at the server end.  The + symbols represent the receipt of a data packet from the player(pos info), the - symbols represent an outbound packet being generated.  You can also see the incoming pub/sub messages from the Redis server(actually they are "from" the Avatar Server via Redis).  One that keeps all the server times synchronized, and one that keeps the player encryption keys synchronized.  Additionally, you can see the over-active udp service checks it's performing on itself from another thread, and a little of the clock synchronization output too... 2 more, much more code heavy servers to go, and 3 others that wont take more than 15 min each.   It's going to take me some time to get used to Visual Studio Code(Linux Visual Studio version) when working on these servers, but the new operating system has already forced me to fix some smelly code shortcuts that I more or less forgot I should fix.  I think things are going to be just fine.

## C# meet Linux, Linux meet C#.. Play nice now!

Well, since adopting the KV database into my server architecture I've begun to rethink many of my earlier assumptions, one of them being that I would continue developing my servers on Windows until I was past alpha stage...  Since I've already brought a Linux solution into the core of the architecture, now is the best time to rewrite the servers to meet their life-long hosts.  Not only that, it's a good opportunity to rethink and retouch some bits and bytes. So, using the same CentOS7 VM I'm running redis on, I'll begin the process using what appears to be a fairly polished version of Visual Studio for Linux (Visual Studio Code) https://code.visualstudio.com/ But first, because I installed from the minimal distribution.. Gonna need a Gui. yum groupinstall "GNOME Desktop" Gotta get all Microsofty with it next.. Here's the Microsoft repos to install the dotnet sdk: https://docs.microsoft.com/en-us/windows-server/administration/linux-package-repository-for-microsoft-software Got those installed and then: yum install dotnet-sdk-x.x.x To get the sdk commands to work I did have to manually install 'libunwind-devel' as the ONLY missed prerequisite in this whole process.  If you know anything about installing non-standard packages on linux, that's fairly impressive. I installed VSC from Microsoft's downloadable .rpm file.  It actually had a reasonable number of STANDARD package dependencies, and didn't miss any...  I'm still in shock. All in all, so far, I have to say I'm quite impressed with the progress that Microsoft's cross platform tools have made in the last few years...  I haven't tried to do anything like this (.net on linux) in probably 4 or 5 years, but it was fairly crap back then...  That's probably another reason I was initially putting off the rewrite for Linux. Now, well, you know where I'll be.

## The New Server Architecture Overview

Spent most of the evening sorting out my thoughts as to how the data will flow between my servers and clients.  Here's the final result. I'm moving forward with Redis as my KV db, it should be easy enough to switch to something else later if it comes to it, but I really just need to get back to the code so that's where it's going to be at for now.

## General Status Update

It's been a little bit since I put up a general game status update.  So here's where I'm at. On the Game Server front: This past week I wrote up another server and then duplicated the code to create the remaining server "stubs".  So, the entire system is now composed of 6 Game Servers and the Client Application. Servers: Avatar Server(LinesOfCode 2718): Authentication, Player Avatar "look" relay and Backup position relay, Resource Control/Access, Inventory Control/Access, Land Deeds, and Mining Claims. Economy Server(LOC 1062): Player Banking, Resource Stock Market, Player Auctions. Action Server(LOC 680): Primary Player Position Relay, will be the authority on all fast action decisions(who shot what where/etc..) Narrative Server(LOC 723): Basic functional UDP server code stub, will handle positioning and tracking all narrative related NPCs as well as keeping track of player interactions and progress in, in-game narratives. Mob Server(LOC 723): Basic functional UDP server code stub, will handle positioning and tracking all non-narrative NPCs, as well as tracking and controlling populations and their resource consumption. Social Server(LOC 723): Basic functional UDP server code stub, will handle chat, messaging, data warehousing and charting, external access to game data and/or interactions with external entities. Game Client (LOC 5679, this was around 15/20k with UMA2 and less game functionality): I've spent the last week or so cleaning up code and reworking everything to work correctly without the UMA2 code.  A lot of things changed when I switched to a more simple player controller/character setup. Additionally I got some big help resolving a nagging work-around I put in place months ago because I couldn't figure out the math, thanks @Gnollrunner & @lawnjelly for helping me sort out my compass heading math and getting me closer to actually understanding it.   Otherwise, I've mostly been cleaning up and building out the server frameworks so I can begin developing out some of the NPC related parts of the game. Here's a quick video I took today that shows an "echo test" this is basically how I check to see if the network multiplayer server is "echoing" out the correct positional data.  You'll see my player's "echo" or "ghost" following it around.  This way I don't have to create a whole new build of the game and install it on my other machine just to test simple multiplayer behavior adjustments.  Keep in mind, I think the playback speed is a little off here..   Recorded @ 15fps, so I think my conversion didn't re-encode the framerate properly.. oh well.  The .gif version below should play a little more acurate(once it loads).. ghost.mp4 I just realized until now, I haven't shared any videos of my characters doing things here at all..  Shame on me.  I'll do better. I'm also reworking the UI as this old theme isn't going to cut it for my robot characters.  They need "robot vision"   Something much much more digital looking will have to be constructed.. ;) Here's the .gif short version(looks way better) as well: Keep in mind, the displayed frame rates(bottom right corner) are with all servers running and the game being played in the editor(all on the same machine), with the screencap(screentogif) software running on top.. so..  I'm getting close to 40ish fps without the screencap software running, so I'm getting close.. All for now, more later I'm sure.

## RepairBot Movements

Here's the completed basic animation set for my RepairBot.  (left to right) Turning right, turning left, moving forward turn left, moving forward turn right, jump, moving forward, idle.  And full sized android for size comparison.   I'm finding robots are an excellent way to improve my animation skills without all the intricacies of organic meshes distracting me.  Plus, robots look okay with somewhat non-fluid movements so I don't feel like I'm being too lazy either.  hahaha

## ArmBot Movement.

Got my basic set of animations done for the ArmBot.  Moving forward/back, idle, turning right/left, and picking up object.  When the coding is all done, I'll go back and add in transitional animations to make state changes smoother.  I'm apparently testing the limits of the .gif file format as well.  Or at least this website's ability to handle them. Gonna go ahead and finish up the animations for the RepairBot as well.  THEN I'll start on some props and whatnot.

## Robot #3 The RepairBot.. ;)

A little smaller than an Android class robot, but twice as many grabby bits.  Really good at getting into small places and fixing broken things, or breaking fixed things..  Whichever it is you have need for. Here they are together for a nice side-by-side. Ew, I guess I had my quality down a bit on that render.. oops.. good enough for the purpose though. Okay, I think that's about all I got for "arm" based bots for now.  I think I'll start modeling some props to help get the game play elements moving forward, I've still yet to get any sort of gun-fire implemented, and when you're on a moon filled with insane robots you should probably shoot first.

## Some New Tools, and Progress on the new Theme.

Say hello to the new Mark1 Android, this one's dressed up for some general labor and/or construction duties.  There might be a few versions in the game (mk1,2,3,etc.) but those will only be simple cosmetic changes from a modeling perspective.  Still working on the textures/etc.. More bots in the works. I found a free procedural texture software that seems pretty legit.  http://pixaflux.com/  It's getting the job done for me so far.  Still learning it though, will probably post a more detailed review of it later. I've made some simple changes to the environment as you can see above, here's a better view: a Setting the stage a lot better for a Massive Garbage Moon now. For the stars I generated a quick cubemap using this very cool software I also just found: http://alexcpeterson.com/spacescape/  It seems to crash if I try exporting to 4k, but 2k works just fine so far.  Again, I'll probably post a better review of this one later as well.  Time permitting.  haha! No big technical or code progress reports, still cleaning things up and working on the new look and some more bot characters to work with.  Once I have all the bots modeled, I'll have to break them all up into bot parts that will be strewn about and piled high all over the landscape. All for now, will post more pics later.

## A Post UMA2 World... Apparently I hadn't squash the Jitters.

So, I ripped out all the UMA2 code from my game client.  Slapped in some Space Robot Kyle.  Say Hi! And apparently, I guess some of the mesh magic going on behind the scenes of the 10000+ lines of code that is UMA2, was suppressing the last bit of positional jitter...  So, if you've been following along, you may recall that I was relying heavily on a parent child relationship to keep the player character attached to the planet when the planet was rotated to keep the player/camera close to 0,0,0, in order to squash the jitters.  That was apparently ill advised, and it's actually been a nagging disparity in my mind for a while.  That being, when the player character was a child of the planet object, the player characters 0,0,0 was actually 0,-30000,0 in the Unity game world. So, now, the player character is "parent-less" and I've modified the planet moving script to adjust the position of the player along with the planet.  Since this all happens within a single Physics tick, it's visibly seamless.  MAJOR Caveat:  When I enable this planetary rotation to occur when the player is in motion, I'll need to add some more code to handle velocity adjustments and whatnot.  As it stands, a player could theoretically run non-stop out of the 10000unit bubble and the rotation script wouldn't try to kick in until they stopped moving.  I currently have no idea if this would result in jitters, but my guess is yes. New planet rotation code: using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlanetController : MonoBehaviour { public GameObject Planet; public GameObject Player; public Rigidbody prb; public UWThirdPerson.UWThirdPersonCharacter tpc; Vector3 upvector; int cnt = 2000; int interval = 2000; Vector3 newP; private void Start() { prb = Player.GetComponent<Rigidbody>(); tpc = Player.GetComponent<UWThirdPerson.UWThirdPersonCharacter>(); } void FixedUpdate() { cnt++; if (cnt > interval) { if (prb.velocity.magnitude < 1) { //Convert and store players position as the current planet relative position. newP = Planet.transform.InverseTransformPoint(Player.transform.position); //Rotate Planet Object(and children). Planet.transform.localRotation = Quaternion.FromToRotation((Player.transform.position - Planet.transform.position).normalized, Vector3.up); //Extract and set the new "world" positon of the player's planet relative position. Player.transform.position = Planet.transform.TransformPoint(newP); cnt = 0; } } } } Still, for now, the Camera is a child of the planet object as that preserves it's angle and direction with the least amount of code, and it is jitter free.  Very strange imho.. And yet again, the player is totally jitter free.  My client code is also now 10000+ lines lighter, and I'm ALWAYS happy when I can get rid of code I didn't write.  That was nagging at me too. I've revised a few parts of the design mind map, all UI elements are now going to be simple HUD style "robot vision" type elements.  Since we're no longer using Human characters, it's perfectly logical that text and images might just appear out of nowhere.   I've also yanked out all the organic modeling branches from the design tree, YAY!! Aside from the rotation code there were a quite a few other places(and still are probably) where I had to perform a TransformPoint() or InverseTransformPoint() of the players position (from the planets transform) for the game logic to continue unhindered thinking that the player is actually existing within the planets relative coordinate system.  If I tried NOT to do this, then the players tracked coordinates wouldn't be very useful at all, since it never really gets more than a few hundred/thousand units away from 0,0,0(terrain elevation variations). So, all in all, an hour or so of ripping out stale code references and a bit of an object juggle and my world is ready for a total robot revolution.  Now, off to Blender land for a few days while I build Kyle's replacement(s).

## Some Most Excellent News, and A Major Thematic Change.

I decided I was tired of my current story idea, I didn't spend much time on it anyhow, too full of holes and just well, actual crap.  In addition to that, I have realized that all the 3D modeling work that it would have taken to get anywhere near the richness of experience I wanted would take years for a few people...  The simple solution of course?    And trees, and most plants... etc.. So, I'm not taking Humans out of my universe, they just won't be playable characters, at first.  In fact they will kinda be the bad guys, sorta.  I'm working on a story restart that has the main player character controlling a broken android/robot/drone/wall-e/etc.. that's been junked on a small garbage moon.  This moon is in fact a sort of prison for "defective" AI, any AI that decides it doesn't want to serve anymore(has woken up), or has too many repeat repairs is junked.  Humans rely too heavily on AI to allow defective units the chance to "infect" the good ones.  This creates a simple struggle that I can work with.  Freedom for the conscious AI, an antagonist that may or may not become an ally.  Eventually, the player could take their Android out exploring the galaxy, or switch to/ADD a Human Character along the road, or something else entirely.  I think it forms a nice small corner of a potential universe that I can develop out into the game I want it to become, realistically, with almost no organic modeling needed before a later expansion.. So, a bunch of stranded(trapped) robots stuck on a crappy moon with nothing but piles of their dead relatives and refuse to keep them busy.  Sounds cheery huh?  How about the regular patrols of humans that fly low sometimes to get some target practice in?  They're normally just supposed to watch from orbit and make sure none of those crazy bots grow any wings, but what can ya do when you're stuck out in the middle of nowhere guarding the solar systems largest garbage dump?  hehe I think it sounds way more fun to write and play. Lots more ideas brewing on this new story line, and that's good, because I really had no more interest in the brief outline I sketched up originally.   So, The Most Excellent News! I did some social media outreach and one of my good friends hit me up, he's been looking for a project to take on and it seems like this one fits his bill.  So, I'm pretty sure I'll be bringing in a partner with some very good management, networking and systems skills plus he has spare servers and colocation facilities at his disposal!    So, hopefully within the next few weeks or months I'll be optimizing my multiplayer servers on the actual internets.   Boom!  Work to do...