Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411431 Posts in 69363 Topics- by 58416 Members - Latest Member: JamesAGreen

April 20, 2024, 03:21:03 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityDevLogsLiSE - an engine for developing and playing life simulators
Pages: [1] 2 3
Print
Author Topic: LiSE - an engine for developing and playing life simulators  (Read 9885 times)
clayote
Level 0
***



View Profile
« on: August 06, 2013, 07:55:02 AM »





Latest release on GitHub

Standalone release on Itch

I'm developing LiSE, an app for developing sim games like The Sims, Dwarf Fortress, Kudos, um... Princess Maker... I guess it's not the best populated genre, which is one reason why I'm making this thing.

The idea is that, like Adventure Game Studio, RPG Maker, and RenPy, LiSE ought to provide a common interface and toolkit for this sort of game, so that the developer can get started without spending quite so much time wrapping their head around particular APIs and concepts in graph theory. This may provide an incidental benefit to players of such games: life sim user interfaces are wildly inconsistent, both with one another and within themselves, usually. A common UI standard would make that problem tractable at least.

The source code all the way back to the beginning is available on GitHub: https://github.com/LogicalDash/LiSE/

Quick features:
  • Graph-based map editor, which can make grid-shaped graphs if you want it to
  • Quick and easy pathfinding, and a bunch of other weird stuff courtesy of the networkx library.
  • History tracking: Rewind the game to an earlier state and do it differently, then change your mind and get back to where you were before you rewound
  • Database backend: autosaves everything, including your history, so there's little reason to keep multiple save files; only writes new stuff, so saving is nice and speedy; has integrity constraints to prevent save corruption; and you can query it directly, in case you want to get a handle on the world state without trying to play the game at the same time
  • API based on a rules engine--make events and their triggers alike using @decorators
  • Card-and-deck metaphor for scripting: encapsulate some event code in a trading card like from Magic the Gathering, then drag it into the decks for whatever situations it's supposed to run in
  • Written in Python
  • Free software under the AGPLv3

It's alpha. I've got it recording and replaying history but I've hit a rut trying to code a history browser that would make alternative timelines usable. It would probably be easier if I had a better background in graph theory.
« Last Edit: April 08, 2023, 12:30:12 PM by clayote » Logged
clayote
Level 0
***



View Profile
« Reply #1 on: August 07, 2013, 04:28:50 AM »

Here's a demo of the engine as it stands.





Here you can see me move a pawn from one spot to another, and have it find a path through the graph. Then I run the game a second time, and it does the same thing as last time, but I don't have to move it anywhere--it goes the same way it did last time.

Observe the calendar widget on the right, automagically updating itself to reflect where the pawn will be, once I've scheduled the movement via drag-and-drop. You can in theory have any number of columns in that calendar, reflecting the time-sensitive value of any game variable.

Everything is really buggy. This is still pre-alpha software. I spent a couple months writing the database connector before any of this history stuff came into the picture.
Logged
doihaveto
Level 2
**



View Profile
« Reply #2 on: August 07, 2013, 11:44:33 PM »

Interesting stuff!

The top-down 2D is neat, reminds me a lot of how the gameplay in The Sims 3 was prototyped using 2D prototypes, while the 3D engine was in development (http://www.gamesindustry.biz/articles/prototyping-the-sims-3).

What's your thinking about how the AI will plug into this - will there be an API? I imagine that higher-level behavior is the part that people will want to write themselves, and rely on the engine for pathing, world model, etc.
Logged

nikki
Level 10
*****


View Profile
« Reply #3 on: August 08, 2013, 01:07:22 AM »

cool plan! are you making a game as you go with your engine ?

@doihaveto : interssting link, I remember reading somewhere that the sims3 team, during development, were playing dwarf fortress alot , now that makes even more sense
Logged
clayote
Level 0
***



View Profile
« Reply #4 on: August 08, 2013, 03:43:23 AM »

What's your thinking about how the AI will plug into this - will there be an API? I imagine that higher-level behavior is the part that people will want to write themselves, and rely on the engine for pathing, world model, etc.

It is essentially already written for me! Most of what you want from "AI" is in fact graph algorithms, and the python-igraph library has so many graph algorithms ready to call it's just ridiculous. So, check out python-igraph if you want a peek at the AI API.

That said, I intend to at least write wrappers for igraph's functions to the effect of "run this, then apply it to these characters at these times". That's already how the pathfinding function works.

cool plan! are you making a game as you go with your engine ?

Not yet, I'm afraid, as I consider time travel to be a fundamental feature, and it's not really working at the moment. But here's the high concept:

Dungeon University casts you as the head(master|mistress|eunuch|golem) of a magic school. It takes place in the general vicinity of the Dungeon Crawl Stone Soup universe... partly because that's where I got the tiles from... anyway, there's no masquerade, you don't have to keep the existence of wizardry secret, all you have to do is run an educational and research institution, and you are doing it in one of those infinitely deep dungeons popping up all over the place because the real estate is cheap down there, many of your students already live there, and if you can train and hire some good dungeon explorers, your research material is down there. Who will find the buried city of the ancients? It could be you! or the guy you paid to do it anyway.

The gameplay cycle is, er, significantly inspired by Dwarf Fortress, but the bulk of the characters you have to worry about are students, and you can only expect paid faculty to follow your orders. For the rest you need to offer incentives to get them to behave how you want, and indeed to attend your school at all. This will work a bit like the game Majesty, where you attached bounties to monsters you needed killed, or places you needed explored.

There are still lots of monsters trying to eat you, and you still have to produce your own food, or at any rate pizza delivery to dungeons is super expensive. Don't go genocidal on those monsters, though. Some of them might turn out to be prospective students.
« Last Edit: August 17, 2013, 07:17:47 PM by LogicalDash » Logged
clayote
Level 0
***



View Profile
« Reply #5 on: August 10, 2013, 02:31:25 AM »

I refactored the UI code a bunch and then squashed the inevitable bugs this introduced. This means it will be easier to repurpose the board rendering code for the history browser.

The idea with the history browser is it displays a decision tree composed of actual decisions the player-developer has made. You can click on past decision nodes to go back to the very tick of game-time when you made that decision, perhaps so you can make another one.
Logged
clayote
Level 0
***



View Profile
« Reply #6 on: August 17, 2013, 07:11:47 PM »

You know how Papers, Please presents its savegames? That is how branching timelines are going to look. They are probably going to flow from top to bottom rather than left to right (hence mousewheel friendly), and you can click thereupon whenever you want to do the time warp
« Last Edit: January 17, 2015, 02:42:50 PM by LogicalDash » Logged
clayote
Level 0
***



View Profile
« Reply #7 on: November 02, 2013, 12:01:00 PM »

I've more or less finished porting LiSE to Kivy (http://kivy.org/), a widget kit that's more platform-agnostic than the hackjob I was doing in Pyglet, as well as better performing. It's probably for the better that I've done the port before finishing the UI all the way, because it turns out that I had a big oversight in my requirements.

Instead of a traditional save/load interface, LiSE autosaves everything you do, and also presents a calendar widget with a line on top indicating the present time. If you want to return the game to an earlier state, you drag that line where you want it, and the game world will appear as it did back then. Multiple branches of history are possible--those show up as extra columns in the calendar.

This functionality is more or less present in the current prototype, although instead of properly dragging the timeline you use buttons to tell it where to go. However, in my attempts to dynamically resize the calendar widget, I ran up against some limitations in Kivy's ScrollView widget, preventing me from keeping the new parts of the calendar on the screen. Consultation with #kivy on freenode revealed that it was in fact a deliberate limitation of the ScrollView that kept it from changing its size very often, because that operation is computationally expensive, and gets moreso when the contents get enormous.

This calendar widget is going to get enormous. So I'd better avoid constructing the whole thing at once, and instead construct bits of it according to where the user is scrolling at the moment.

That's a rewrite.
Logged
clayote
Level 0
***



View Profile
« Reply #8 on: April 04, 2014, 06:11:59 PM »

I'm not dead! Got a job, though. Development has been sporadic since then.

The port to Kivy was a mess, but not in a way that I noticed until I tried to make a few changes to the data structures that the UI represented, then tried to tweak the UI to match, and could not navigate my own code. I've rewritten a bunch and improved the documentation somewhat. It's not really functional, partly because I'm still hammering out the basics of the data model. Everything would have been easier if I'd decided on that stuff before going in, but I'm not sure that'd be realistic for a project like this.

Here's what I've decided on regarding the data model.

Every time a game variable gets a value assigned, it goes in a database record. Precisely which table the record goes in may vary, but all of them have two fields in common: branch and tick. These indicate when, in game-time, the variable's value took effect. Once you set a value for a variable in a particular branch and tick, it's permanent--but you can override it in a different branch and tick. If it's the same branch, but a later tick, the player will experience this as if the variable stayed at value A for some number of ticks (seconds, perhaps--the length of a tick is up to you) before changing to value B. If it's a different branch, the player won't see the new value at all until you put them onto that branch yourself.

To a player, a branch is a save file. To a developer, branches are much the same as those things you use in version control systems to keep different versions of your work. In LiSE, you don't precisely merge branches, but when you're writing diegetic events, you are free to look up information in branches that the player isn't on. This provides a simple way to write AI behaviors that rely on hypotheticals.

"Diegetic events" are what I'm calling the kind of event that happens in the game world and not, eg., in the input handling infrastructure. They may be triggered whenever the current branch or tick changes. The triggers for diegetic events observe the world state and, if it merits the event's being triggered, return a map of parameters that will be supplied to the event. It's probably a bad idea to run all the triggers on everything in the world every tick, so instead, they are attached to Characters and Facades.

A Character is simply a subset of the data in the world model. They're preferentially organized into Things (which have locations), Places (where things go), and Portals (where things go through), but you can actually put whatever data you want here. Information in a Character is considered objective, ie., it gets the last word when deciding where something is, how heavy it is, and generally the type of thing that's not socially constructed. This is where you hang triggers for physical effects--burglar alarms, avalanches, that kind of thing.

A Facade is a view onto a Character that may have been filtered or even deliberately distorted. It is used to simulate the impression that one Character has of another. Subclasses of Facade may simulate various sense organs or even ways of thinking. I'd like to make Facade recursive, so that you can filter and distort the same underlying reality through many layers of postmodernism, but I'll hold off on implementing that till I can simulate a civil conversation followed by a swordfight or something.

So anyway, when time advances, the diegetic event handler goes through all the Characters and Facades, and calls each of their triggers, passing in the current branch and tick, along with the Character or Facade itself. The trigger should operate only on that particular Character or Facade to decide if it's been fired, though it is certainly possible to access the entire world state from inside a trigger if you really want to. If they trigger an event, they return a mapping that's passed into the event constructor along with the arguments to the trigger.

Events resolve themselves however they like, and present the results in the form of more database records. Those get set into the database with everything else. I want the event handler to throw exceptions if you're trying to alter some (branch, tick) that's already been handled, since it only handles each point in time once, but otherwise you have complete freedom to set records far in the future, in an alternative universe that might only be used as a problem-space for a particular AI player.

You can move the (branch, tick) cursor wherever you want, by the way. The fact of moving it is what cues the event handler to go through the triggers.
« Last Edit: April 06, 2014, 09:21:47 AM by LogicalDash » Logged
doihaveto
Level 2
**



View Profile
« Reply #9 on: April 05, 2014, 06:13:51 PM »

I'm really liking what you're proposing about branches and save files. It reminds me a lot of what version control systems do on one hand, and then on the other hand, what journaling filesystems and databases do with data changes that get queued up and commited into the database. Database journal entries are just a linear list, but turning them into a tree could represent "alternate realities" of the data model pretty well... (Like git does with branches, only branches get merged, and in this case they probably wouldn't.)

Anyway, just bringing up journaling because that might be a more familiar metaphor for CS people. Smiley

So it sounds like your event structure is kind of like a rule engine? In particular: 1. an event triggers if some conditions it needs are satisfied, and 2. once triggered, it modifies the world model (by appending new knowledge to the journal)? That sounds like a very general and powerful model, and the addition of ever-growing trees to query and modify would allow for some interesting functionality.

I'd definitely encourage you to experiment with building it, and making a game that uses this functionality! System design is definitely important to start with, but I'm always amazed after I jump into implementing something (usually bottom up, too), how often it informs and clarifies the design!

Good luck!
Logged

clayote
Level 0
***



View Profile
« Reply #10 on: April 06, 2014, 01:43:54 PM »

Thanks!

I guess you could say that triggers and events between them form a rule system. At some point it should even be possible to perform something like process modeling by having events that trigger when things go places, and drawing portals between those places to describe the process you want. But I'm not making a special modeling language for that stuff. If it's easy to write the process you want in Python, it should be easy to subclass Event and do it that way.

I didn't want to describe the log-like data model as "journaling" because SQLite has actual, file-level journaling, and you might have occasion to use that if your game crashes. The model here is meant to make it trivial to rewind the game to any state it was previously in, including those that have "unhappened"; the idea being that you can emulate whatever save system you want by adding restrictions to this one.
« Last Edit: April 06, 2014, 02:27:19 PM by LogicalDash » Logged
clayote
Level 0
***



View Profile
« Reply #11 on: June 01, 2014, 10:43:56 AM »

I'm in the process of changing the architecture so that there's a GUI-less backend library that you use to access the database and arrange your rulesets and so-forth, separate from the graphical tools I'm developing to work with it. I had originally wanted to avoid such a structure, thinking that making an API would be difficult and unnecessary, but I've come to thinking it really is necessary. For one thing, it makes it possible to do unit tests like this one, which hopefully illustrates the API concept adequately.

https://github.com/LogicalDash/LiSE/blob/master/examples/sickle.py
« Last Edit: February 05, 2015, 06:42:46 AM by LogicalDash » Logged
clayote
Level 0
***



View Profile
« Reply #12 on: June 23, 2014, 04:20:22 AM »

The main LiSE repository won't be seeing any activity for a while, because I have split the engine's object-relational mapper into its own project, gorm. It holds graph data structures in a conventional relational database, allowing it to implement the branch-and-tick version control described in a previous post.

gorm doesn't use the iGraph library for its graph structure; it uses networkx, a pure-Python library, which makes it a lot easier to override the default data storage mechanism with my own thing. It might be slower; if it makes a difference, I can add an iGraph translation layer later on.
Logged
clayote
Level 0
***



View Profile
« Reply #13 on: July 14, 2014, 05:50:39 AM »

I seem to have got the rules engine working! I updated the code sample above to match what actually runs.

Basically, a rule is built from two lists of functions, the actions that the rule does and the prereqs that it has. Prereqs have to be Boolean functions, and shouldn't change the world, but only decide if it's the right time to execute the rule; all prereqs must pass before the rule runs. Actions can return whatever you want and do whatever you want to the world, including changing the future in this instance. The lise.advance() function tries to run one rule every time you call it, but resets the game-time after every function call. But it will only run each rule once per tick, and when it runs out, it will advance to the next tick.
Logged
clayote
Level 0
***



View Profile
« Reply #14 on: January 17, 2015, 08:28:13 AM »

Still plugging away at this...



In this screenshot you can see the IDE as it presently exists. This is a separate module from the engine proper; you can run LiSE headless if you've got your own ideas about GUIs.

Dragging those wee sprites in the bar on the right onto the map will create places (in the case of the blue dot) or put things into places (in the case of the white silhouette). Toggle the button with the arrow on it, and you can draw portals (directed edges that things might travel thru) between places.

Clicking an entity will make its stats show up on the left. They can be made to look all kinds of ways, like the sliders and toggles in the pic, but under the hood, editing a stat just means adding a record to the database. Each and every change you make gets added to the active transaction and committed when you close the app, so there's no need for saving or loading. If you want to keep multiple alternative versions of your work, you enter a new branch into the text box by that name. At some point there'll be a nice, visual way of organizing the revision tree, but this is adequate for the time being.

Not yet implemented: someplace to type code. Right now, if you want your meeples to do anything on their own, you need to put some decorated functions in a .py file and run it to initialize the database -- and then play with it in the IDE. You'll always be able to program your game that way if you want, but I want it to be as simple as possible to come up with a wee snippet of event code, type it in, and see how it performs right away.
« Last Edit: January 17, 2015, 02:43:49 PM by LogicalDash » Logged
clayote
Level 0
***



View Profile
« Reply #15 on: February 05, 2015, 06:01:18 AM »



Assembling a character graphic in ELiDE.

Right now the RLTiles are hard-coded into the app. It's possible to use other graphics, but you have to type the file names into the database--I'll make it easier to use your own spritesheets later on.
« Last Edit: February 05, 2015, 06:19:42 AM by LogicalDash » Logged
clayote
Level 0
***



View Profile
« Reply #16 on: March 09, 2015, 10:06:30 AM »

Alpha build posted. Not indicated for the easily confused.

All the development is taking place on Ubuntu, but Kivy's packaging system is scattered -- the Windows version is the only one that (a) runs standalone and (b) supports Python 3. If you feel comfortable installing Python eggs on the command line I can help you set it up that way.
Logged
clayote
Level 0
***



View Profile
« Reply #17 on: March 25, 2015, 05:21:40 AM »

I've written a suite of proxy classes that allow LiSE to run in a subprocess, making GUI hiccups much rarer and possibly opening the door to having multiple views of the simulation at different points in time.

I want to implement rudimentary, visual novel style prompts for the player's input, and then I think I'll be ready to do another alpha release, and start work on Dungeon University.
Logged
clayote
Level 0
***



View Profile
« Reply #18 on: March 31, 2015, 01:40:27 PM »



The rule editor.

Currently, the Action tab is selected, so you're changing what the selected rule ("kill") does.

The user is dragging the "wander" card from the right stack to the left stack to enable it. Cards get evaluated from top to bottom and you can reorder them by dragging them in the stack.

Right now the cards just show their Python function. I'm planning on making it so they show the function's docstring only, if there is one.

You'll be able to assign illustrations to cards to make them look just like Magic cards if you like. I think I'll let you choose their colors as well.
« Last Edit: April 03, 2015, 09:11:27 AM by LogicalDash » Logged
clayote
Level 0
***



View Profile
« Reply #19 on: April 03, 2015, 09:05:36 AM »

Alpha 2 released for Windows, Mac, and Linux

I forgot to post about Alpha 1 here. Sorry
Logged
Pages: [1] 2 3
Print
Jump to:  

Theme orange-lt created by panic