Fractal Softworks Forum

Please login or register.

Login with username, password and session length

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - LazyWizard

Pages: 1 ... 10 11 [12]
166
Modding Resources / Useful Java Code
« on: August 18, 2012, 11:17:36 AM »
I thought it might be useful to have a thread that contains example code for commonly needed mod features. Eventually I hope to have a long list of working code samples for modders to play around with.

First up, I have two examples of how to use SpawnPointPlugin to create a mod control object. The first example runs events at timed intervals (each day, week, month, and year):

EventManager.java
Code
package data.scripts.world;

import com.fs.starfarer.api.campaign.LocationAPI;
import com.fs.starfarer.api.campaign.SectorAPI;
import com.fs.starfarer.api.campaign.SpawnPointPlugin;
import java.util.GregorianCalendar;

public class EventManager implements SpawnPointPlugin
{
    private static final float BASE_INTERVAL = 1.0f;
    private static final int FIRST_DAY_IN_WEEK = GregorianCalendar.SUNDAY;
    private float heartbeatInterval;
    private long lastHeartbeat;
    private SectorAPI sector;
    private GregorianCalendar calendar = new GregorianCalendar();

    public EventManager(SectorAPI sector)
    {
        // Synch the heartbeat to the sector clock
        this.sector = sector;
        lastHeartbeat = sector.getClock().getTimestamp();
        // The first heartbeat should happen at the start of day 1
        heartbeatInterval = (1.0f
                - (sector.getClock().getHour() / 24f));
    }

    private void runDaily()
    {
        sector.addMessage("Daily");
        // Insert code here
    }

    private void runWeekly()
    {
        sector.addMessage("Weekly");
        // Insert code here
    }

    private void runMonthly()
    {
        sector.addMessage("Monthly");
        // Insert code here
    }

    private void runYearly()
    {
        sector.addMessage("Yearly");
        // Insert code here
    }

    private void doIntervalChecks(long time)
    {
        lastHeartbeat = time;

        runDaily();

        calendar.setTimeInMillis(time);

        if (calendar.get(GregorianCalendar.DAY_OF_WEEK) == FIRST_DAY_IN_WEEK)
        {
            runWeekly();
        }

        if (calendar.get(GregorianCalendar.DAY_OF_MONTH) == 1)
        {
            runMonthly();

            if (calendar.get(GregorianCalendar.DAY_OF_YEAR) == 1)
            {
                runYearly();
            }
        }
    }

    private void checkSynched()
    {
        // Compensate for day-synch code in constructor
        if (heartbeatInterval != BASE_INTERVAL)
        {
            heartbeatInterval = BASE_INTERVAL;
        }
    }

    @Override
    public void advance(SectorAPI sector, LocationAPI location)
    {
        // Events that run at set in-game intervals
        if (sector.getClock().getElapsedDaysSince(lastHeartbeat) >= heartbeatInterval)
        {
            doIntervalChecks(sector.getClock().getTimestamp());
            checkSynched();
        }
    }
}

The second example contains two classes, and will allow you to set scripts to run at any time you wish (either by timestamp, calendar date, or a set time from now):

TimedScriptManager.java
Code
package data.scripts.world;

import com.fs.starfarer.api.Script;
import com.fs.starfarer.api.campaign.LocationAPI;
import com.fs.starfarer.api.campaign.SectorAPI;
import com.fs.starfarer.api.campaign.SpawnPointPlugin;
import java.util.*;

public class TimedScriptManager implements SpawnPointPlugin
{
    // If an added script has already passed its target runtime, should it run?
    private static final boolean RUN_SCRIPTS_IF_ADDED_LATE = false;
    private static final boolean SHOW_DEBUG_MESSAGES = false;
    // Helps convert between Starfarer and RL time
    private static final long STARFARER_SPEED = 8640000l;
    // Holds all TimedScriptManagers for easy lookup and (theoretical)
    // multi-sector support; get current Manager with getManager(SectorAPI)
    private static Map allManagers = Collections.synchronizedMap(new HashMap());
    // The sector the current object manages
    private SectorAPI sector;
    // This stores our scripts in a sorted set for efficient per-frame checks.
    // Sets don't allow duplicates, so the scripts are stored in a container
    // object that does (if there are two containers with the same timestamp,
    // mergeScripts will be called to add one container's scripts to the other)
    private SortedSet runOnceScripts = new TreeSet();

    public TimedScriptManager(SectorAPI sector)
    {
        // Don't add this to the list of managers if the sector has one already
        if (allManagers.keySet().contains(sector))
        {
            sector.addMessage("Duplicate TimedScriptManager detected!");
            return;
        }

        this.sector = sector;
        allManagers.put(sector, this);
    }

    // Returns the manager associated with a sector
    public static TimedScriptManager getManager(SectorAPI sector)
    {
        // If we have this sector registered, find the associated manager
        if (allManagers.keySet().contains(sector))
        {
            return (TimedScriptManager) allManagers.get(sector);
        }

        // No such TimedScriptManager
        return null;
    }

    // Runs the scripts at the provided timestamp
    public void addScriptsAtTimestamp(long timestamp, Script[] scripts)
    {
        // If the target time has already passed, run the scripts instantly
        if (timestamp <= sector.getClock().getTimestamp())
        {
            // .. unless you don't want to, that is
            if (!RUN_SCRIPTS_IF_ADDED_LATE)
            {
                showDebug("Scripts skipped due to lateness.");
                return;
            }

            showDebug("Running scripts early.");

            // Run the scripts
            for (int x = 0; x < scripts.length; x++)
            {
                scripts[x].run();
            }

            return;
        }

        // Create a container for the scripts (lazy optimization)
        TimedScriptContainer tmp = new TimedScriptContainer(timestamp);
        tmp.addScripts(scripts);

        // Is there a container with this target time already?
        if (runOnceScripts.contains(tmp))
        {
            showDebug("Debug: Two script containers with same timestamp!");

            // Sets don't allow duplicates, so merge the two containers
            mergeScripts(tmp);
            return;
        }

        runOnceScripts.add(tmp);
    }

    // Same as above, but with a single script
    public void addScriptAtTimestamp(long timestamp, Script script)
    {
        addScriptsAtTimestamp(timestamp, new Script[]
                {
                    script
                });
    }

    // Runs the scripts at the provided in-game date
    public void addScriptsAtDate(GregorianCalendar date, Script[] scripts)
    {
        addScriptsAtTimestamp(date.getTimeInMillis(), scripts);
    }

    // Same as above, but with a single script
    public void addScriptAtDate(GregorianCalendar date, Script script)
    {
        addScriptsAtDate(date, new Script[]
                {
                    script
                });
    }

    // Runs the scripts timeFromNow seconds after this is called
    public void addScripts(float timeFromNow, Script[] scripts)
    {
        // Adjust time to compensate for Starfarer game speed
        long timeToAdd = sector.getClock().getTimestamp();
        timeToAdd += (long) (timeFromNow * STARFARER_SPEED);

        addScriptsAtTimestamp(timeToAdd, scripts);
    }

    // Same as above, but with a single script
    public void addScript(float timeFromNow, Script script)
    {
        addScripts(timeFromNow, new Script[]
                {
                    script
                });
    }

    // Sets don't allow duplicate elements, so if a container already exists
    // with that timestamp, we must manually merge the scripts
    private void mergeScripts(TimedScriptContainer container)
    {
        Iterator iter = runOnceScripts.iterator();
        TimedScriptContainer tmp;

        // Find the container that matches this container's timestamp
        while (iter.hasNext())
        {
            tmp = (TimedScriptContainer) iter.next();

            // Found it! Now combine our scripts with it
            if (tmp.equals(container))
            {
                Script[] scripts = container.getScriptsAsArray();
                tmp.addScripts(scripts);

                showDebug("Debug: Merge successful!");

                return;
            }
        }

        // No matching container found (shouldn't ever happen)
        showDebug("Debug: Merge failed!");
    }

    // Runs once per frame while there is at least one script container
    private void checkScripts(long time)
    {
        Iterator iter = runOnceScripts.iterator();
        TimedScriptContainer tmp;
        Script script;

        // Iterate through the script containers
        while (iter.hasNext())
        {
            tmp = (TimedScriptContainer) iter.next();

            // As the list of scripts is sorted, we only need
            // to check until we've exceeded the current time
            if (tmp.targetTime > time)
            {
                // This is extremely spammy (1 line per frame)
                // Only uncomment if you have a problem you need to track down
                //debugMsg("Debug: Ignoring " + tmp.targetTime
                //        + " for " + (tmp.targetTime - time));

                break;
            }

            showDebug("Running " + tmp.targetTime + " (currently " + time + ")");

            // Run all scripts in the container
            for (int x = 0; x < tmp.scripts.size(); x++)
            {
                script = (Script) tmp.scripts.get(x);
                script.run();
            }

            showDebug("Removing script container.");

            // Remove container after it's been run
            iter.remove();
        }
    }

    private void showDebug(String text)
    {
        if (SHOW_DEBUG_MESSAGES)
        {
            sector.addMessage(text);
        }
    }

    @Override
    public void advance(SectorAPI sector, LocationAPI location)
    {
        // Only bother with the check if there are scripts to be run!
        if (!runOnceScripts.isEmpty())
        {
            checkScripts(sector.getClock().getTimestamp());
        }
    }
}

TimedScriptContainer.java
Code
package data.scripts.world;

import com.fs.starfarer.api.Script;
import java.util.*;

public class TimedScriptContainer implements Comparable
{
    public final long targetTime;
    protected ArrayList scripts;

    public TimedScriptContainer(long targetTime)
    {
        this.targetTime = targetTime;
        scripts = new ArrayList();
    }

    public void addScript(Script toAdd)
    {
        scripts.add(toAdd);
    }

    public void addScripts(Script[] toAdd)
    {
        scripts.addAll(Arrays.asList(toAdd));
    }

    // For now, there should be no way to modify scripts once set
    // I might change this later, when I have more time to debug
    public final List getScripts()
    {
        return Collections.unmodifiableList(scripts);
    }

    public final Script[] getScriptsAsArray()
    {
        return (Script[]) scripts.toArray(new Script[scripts.size()]);
    }

    // Prevents containers with duplicate targetTimes from being added to a set
    @Override
    public boolean equals(Object obj)
    {
        if (obj == null)
        {
            return false;
        }
        if (obj == this)
        {
            return true;
        }
        if (!(obj instanceof TimedScriptContainer))
        {
            return false;
        }
        TimedScriptContainer tmp = (TimedScriptContainer) obj;
        return (targetTime == tmp.targetTime);
    }

    // Used by the SortedSet in TimedScriptManager to sort the containers
    public int compareTo(Object obj)
    {
        TimedScriptContainer tmp = (TimedScriptContainer) obj;
        return ((Long) targetTime).compareTo((Long) tmp.targetTime);
    }
}

Here's a zip containing a mod using these examples: link


I'm also working on a mini-tutorial on advanced Script usage. That will probably come later, though. I have some Caelus stuff to work on. :)

While I'm cleaning up these scripts for general use, are there any other examples anyone wants me to include? If it's a code-related problem, I can probably post a prototype for you. :)

Inspiration: this post, which made me realize how non-obvious some of the solutions we take for granted are.

167
Suggestions / Hullmod improvements
« on: August 06, 2012, 09:28:09 AM »
I've been playing around with hullmods recently, and I have a few suggestions for improvements I think the API could use.

  • The existing hullmod API methods run any time the ship is displayed or modified. We could use a method that only runs when a hullmod is added, and a similar one for when it is removed. This would allow us to add non-stat related code, like removing or adding a cargo item (for making hullmods that require an item).
  • If you give a hullmod a negative OP cost (for hullmods that weaken your ship in return for a few more build points), the player can remove them and go over the OP limit. Removing hullmods with negative costs should be blocked if doing so would put you over max OP.
  • The game seems to create a new ship object every time anything on the ship is changed. Could we have a ShipAPI method that returns a unique identifier for each ship, so we can keep track of ships with certain hullmods?
  • On a related note, would it be possible to have a method that returns a list of hullmods on a ship? It would help to block nonsensical combinations of hullmods, like light and heavy armor.

168
Modding / NetBeans users: if the new API hooks aren't showing up for you
« on: August 05, 2012, 09:26:10 AM »
If you are using NetBeans for your mod's code and the new API methods introduced in .53 aren't showing up for you, the likely culprit is NetBean's aggressive caching behavior. It will occasionally continue to use an old cached version of a library instead of recognizing the new one.

If you're not sure if you have this problem:
Spoiler
A quick way to test if you are affected is to import com.fs.starfarer.api.Global, then somewhere in your code type
Code
    Global.getFactory().

If the auto-complete defaults to createPerson() instead of createFleetMember(), you've been hit with the cache bug.
[close]

Removing and re-adding the library won't help, nor will creating a new project and copying over your files. The only way to fix this is to clear your cache. To do so, close NetBeans and delete the following folder:

For NetBeans 7.2+
Windows: %USERPROFILE%\AppData\Local\NetBeans\Cache\<version>
Mac: $HOME/Library/Caches/NetBeans/<version>
Linux: ~/.cache/netbeans/<version>

Older versions
Windows: %USERPROFILE%\.netbeans\<version>\var\cache
Mac/Linux: $HOME/.netbeans/<version>/var/cache


NetBeans will rebuild the cache the next time you start the IDE, and afterwards it should recognize the new library changes.

169
Mods / [0.8.1a] Simulator Overhaul v1.4 (released 2017-06-21)
« on: August 04, 2012, 02:03:24 PM »

Simulator opponent unlocking is disabled when playing with DynaSector due to that mod's randomized variants. All other features are still enabled, however.

This is a simple mod that changes the behavior of the refit simulator. With this mod installed, only ships you've personally fought against or alongside will be present in the campaign simulator, and simulation reserves are infinitely replenished for both sides in all simulator battles.

In addition, this mod provides several optional plugins that you can toggle in data/config/simulator/sim_settings.json, such as healing/restocking the player ship when all sim opponents are defeated, periodically deleting old hulks from the battle map, infinite CR for the player's ships and more.

Only stock variants will be added to the campaign simulator, and you must actively participate in a fight with them to unlock them. Merely having ships in a fleet doesn't give the simulator any useful combat data to work with. Gotta catch 'em all!

Please let me know if you find any bugs. :)

Changelog:
Spoiler
Quote
1.4 (June 21, 2017)
=====================
Blocked simlist opponents changed from unboardable ships to ones hidden in codex
Adjusted hulk cleaner plugin:
 - Hulks are directly removed from the battle map instead of destroyed
 - Ship pieces are cleaned up properly now
Added "includeHiddenInCodex" setting:
 - Disabled by default, this setting will allow ships such as [REDACTED] to
   be unlocked for simulator battles
Added "includeStations" setting:
 - Disabled by default, allows stations to be unlocked for simulator battles
 - Requires "includeHiddenInCodex" to be enabled
Default opponent CR bumped up to 70% (was 60%)

 1.3 (June 06, 2017)
=====================
Updated to be compatible with Starsector 0.8.1a
Fighter wings are no longer supported:
 - Renamed "id" column of starting_sim_opponents.csv to "variant id"; all mods
   that include this file should change this (and also remove any wings)
Starting unlocked sim opponents changed to a Hound (P) and Kite (P)
Civilian ships are sorted at the end of their respective hull size categories

 1.2c (March 16, 2017)
=======================
Switched version file hosting to Bitbucket

 1.2b (April 28, 2016)
=======================
Compatibility patch for DynaSector
Added AllSimOpponents console command, unlocks all possible simulator opponents

 1.2 (November 19, 2015)
=========================
Updated to be compatible with Starsector 0.7a
Combined unlocked ships and wings into one notification (less spammy)
Fixed issues with reserves not regenerating after using F8 in devmode
Changes to SimMaster:
 - Added getDefaultOpponents(), returns starting sim list
 - Added resetSimList(), resets list to only include default opponents

 1.1b (October 23, 2015)
=========================
Fixed missing variant crash after using F8 in devmode
 - Ships will still be missing from the list after using F8, just doesn't crash

 1.1 (October 03, 2015)
========================
Rewrite of reserve respawning logic to be much more efficient
Unexported custom variants in player's fleet now respawn properly
Hulls are sorted at the very end of the sim opponent list
Moved configuration files to data/config/simulator
Added "cleanUpHulks" setting, deletes hulks in sim after 30 seconds if true
Added "infiniteCR" setting, gives ships in sim infinite combat readiness if true
Added "healOnVictory" setting, restores player ship when all enemies are dead
Added "includeHulls" setting, adds all known hulls to sim opponent list if true
Added "useVanillaSimListWithStarsector+" setting, defaults to true
Added starting_sim_opponents.csv:
 - Allows other mods to add ships/wings to the starting sim list without having
   to be unlocked by fighting them first
 - Does nothing if Starsector+ is activated as unlocking is disabled with that
   mod active

 1.0c (November 11, 2014)
==========================
Re-enabled infinite reserves and sorted opponent lists for Starsector+
(ship unlocking is still disabled when playing SS+ due to its random variants)

 1.0b (November 11, 2014)
==========================
Fix for crash when you allow your second in command to fight a battle
Use sim_opponents.csv and vanilla behavior when Starsector+ is installed

 1.0 (November 11, 2014)
=========================
Renamed mod to Simulator Overhaul (was All Ships in Refit Battles)
Mod now requires LazyLib to function
Changes since alpha:
 - Added config file sim_settings.json, can customize how the mod works here
 - Newly unlocked campaign sim opponents will be announced after battle is over
 - Full opponent list appears at the start of a simulation (you don't need to
   close and reopen the opponents list for all known ships to show up)
 - Allied reserves are infinitely respawnable in campaign simulations
   (known bug: replacement allies don't benefit from fleet-wide skill effects)
   (known bug: replacement allies have 60% CR regardless of original value)
 - Mission simulation reserves now infinite, sorted, uses sim_opponents.csv
 - Changed how persistent data is handled (will automatically import old data)
 - Minor optimizations and code cleanup
[close]

170
Bug Reports & Support / Ship systems sold in stores?
« on: August 03, 2012, 06:31:49 AM »
It seems the convoys sometimes deliver them.

Image:
Spoiler
[close]

171
Suggestions / Split the Modding section into its own subforum
« on: June 23, 2012, 10:40:49 PM »
The Modding section is getting a bit too crowded these days. There are a few stickied threads to aid navigation, but they are reliant on already-busy moderators to stay up to date, and the pace of mod development is only going to increase as the game matures. I think Modding should be expanded into an entire categorized subforum. This would place the burden of keeping things organized on the individual posters and make finding things much simpler.

I'm imagining something along these lines:

    Modding -
    • Modding Resources - This would be where all of the tools, tutorials, free ship sprites, etc would go
    • Completed Mods - Exactly what it says, an easy way for a newcomer to get straight to the stable downloads
    • In Development - Progress reports on mods that are still being worked on, or beta releases that aren't entirely stable yet
    • Help Wanted - Assemble your mod team here, or just ask for assistance squashing a tricky bug
    • Mod Ideas - A place to request mods, or for modders to test the waters with their concepts
    • Modding Discussion - Everything not covered by other categories

    (If that's too many boards, the last three could probably be combined)

    Thoughts?

    172
    Modding Resources / Tutorial: Syncing your mod with Dropbox
    « on: June 15, 2012, 08:01:10 AM »
    I'll try to keep this tutorial as simple as possible so that anyone can follow along, regardless of tech savvyness.

    One of the most devastating things that can happen to a developer is data loss. It happens all the time: computer theft, component failure, power surge, fires, etc. If you want to protect yourself from such things, you'll want to have an offsite backup. Dropbox is by far the simplest solution. Here's how to use it.


    What is Dropbox?

    Basically, Dropbox is a program that runs on your computer, constantly scanning a directory you set up when you installed it. Whenever anything changes in that directory (adding, removing, renaming, or otherwise modifying files), it uploads the changes to your private storage on the central server. You can access all the files on your account through linked computers, a web interface, or even from a smartphone. Dropbox gives you two gigabytes of storage (which can be expanded by 500 megabytes for every person you successfully refer to the service), and allows you to share folders with other people. It's excellent for small mod teams. And it's free!


    Why not just use a real source code management system like Git, SVN, or Mercurial?

    Well, if you know what those are then this tutorial isn't really for you. For most users, though, the headache of setting up and using a repository isn't worth it, and they would be overkill for small projects anyway.


    So how do I set up Dropbox?

    First, you need to download the client from the Dropbox website. Run the installer, follow the instructions and create an account. It's extremely user-friendly.

    If you want to share a specific folder with others (like mod team members), go here and right click on the folder you want to share and select "invite to folder" (if it's already shared, this will be replaced with "shared folder options"). You will either need the other person's e-mail address, or if you hooked in your Facebook account, to be friends with them.

    Keep note of where your Dropbox sync directory is (right click on the Dropbox tray icon and click Preferences). Any files you place in this directory will be uploaded to the Dropbox servers. Any changes you make to them will also be synched. Don't worry about constantly uploading tiny changes, Dropbox gives you something crazy like 30 gigabytes of bandwidth per day.


    But my mod files need to be in the Starfarer directory to work! Won't constantly copying the files over to Dropbox be a huge pain in the ass?

    Ah, this is where the magic begins. We're going to use the mklink command to create a directory junction. In laymans terms, we're going to tell the operating system to make it so the same directory can be in two different places at the same time. This way, the mod files will be in both the Starfarer directory and the Dropbox directory.

    Note that the method I'm using only works in Vista and above. You can do this in XP, but the command is different. I'll do some research and add that method into the post later.


    mklink? Junctions? This techno-wizardry isn't going to fry my computer, is it?

    Don't worry, it's perfectly safe*. The junction is completely invisible to programs; it functions identically to a normal folder in both locations. A common use for junctions is to move Steam games (which are otherwise unmoveable) onto another hard drive when you are getting low on space. I personally have about a dozen junctions in use on my system right now, and I've never had a problem.

    *Note: in versions of Windows before Vista, deleting a junction point deletes the original folder as well. You have to remove the link manually from a command prompt to avoid this. I'll edit in instructions for that later as well. If this does happen to you, Dropbox stores all file changes within the last thirty days, so you can easily recover any lost files.


    OK, I'm convinced. How do I do this?

    First, move (not copy) your mod folder into a folder in the Dropbox sync directory. The Dropbox files will be the real thing from now on, and Starfarer will be using the junction to reach them. Keep note of BOTH directory paths: the one you just moved from, and the one you moved to. For example, I would have moved the folder "C:\Users\Rob\Programs\Starfarer\mods\LW Personal Mod" to the new path "C:\Users\Rob\Dropbox\Starfarer\LW Personal Mod". Paste your paths into Notepad or something, you'll need them soon.

    Next, we'll need an elevated command prompt. To do this, open the Start menu and type "cmd" into the search bar. You should see a cmd.exe appear; right click it and hit "Run as administrator". If you don't see it here (or turned off the search bar), you can find cmd.exe in C:\Windows\System32.

    The syntax you will need to use is "mklink /J <old folder path> <new folder path>", replacing the bracketed bits with the actual paths. Both paths must be enclosed in quotation marks.

    For example, here's the command I used (your paths will be different, obviously):
    Code
    mklink /J "C:\Users\Rob\Programs\Starfarer\mods\LW Personal Mod" "C:\Users\Rob\Dropbox\Starfarer\LW Personal Mod"

    If all went as planned, your prompt window should look something like this:


    Your folder should have reappeared in its old Starfarer location with a shortcut icon overlayed over it, and you should be able to double click the folder in either location and get to the same place. Congratulations, you don't have to worry about losing your mod files anymore!

    If something went wrong, post in the comments and I'll try to help you out.

    173
    Prior to today I had been coding my mods in NotePad++, occasionally calling the java compiler from the command line when I needed more detailed error messages. Not exactly ideal. So I decided to pick up a real Java IDE, and ended up choosing NetBeans. It's been such a massive improvement that I figured I would help pave the way for any others who want to try it out. Here's a tutorial to get an existing mod working in NetBeans. If I explained something poorly, click the spoiler tag underneath that paragraph for pictures.

    (Keep in mind I've only been using NetBeans for a few hours and figured it out as I wrote this tutorial, so it's likely some of this information might be wrong. Code at your own risk! :))

    "This looks like a really difficult tutorial. I mean, it's like four pages long. Is this really worth it?"

    It's not as hard as it looks, I'm just terrible at writing tutorials ;). Plus, it has lots of pretty pictures to look at :P. As for why you would want to work in a real IDE, there are a few benefits: most importantly, you will get instant feedback on any bugs you make. If you've been editing the java files in Notepad++ or something so far, you're probably intimately familiar with the following: trying to launch Starfarer, having it crash, then reading the end of a logfile to get a uselessly cryptic error message about what went wrong. With NetBeans you get real error messages, ones you can Google for help with, and you get them as you type. Bugs become much easier to squash. It also has a host of other features that I won't bore you with.

    Let's begin. First up, you will need the Java Development Kit if you don't already have it (if you have to ask, you probably don't have it). That can be downloaded here (it's the download called JDK, if that wasn't obvious). Java 6 or 7, doesn't really matter. Compatability isn't an issue since you won't be using what you compile with NetBeans (Starfarer compiles the mods itself when it launches); NetBeans just makes working with the source files a lot easier.

    Next, you'll need NetBeans itself. NetBeans can be downloaded from netbeans.org. It's up to you if you grab the beta version or not; I've tried both and either should work just fine. You only need the Java SE version for making Starfarer mods.

    Once you've installed and run the program, this is close to what you should see (I've already customized my windows, sorry!):
    Spoiler
    [close]

    Go to File - New Project. Make sure the category is set to Java and select "Java Project with Existing Sources" in the Projects box. Hit Next. Name your project anything you like, and put it anywhere except in your mod folder. We're not interested in the project files NetBeans generates.
    Spoiler

    [close]

    You'll now see two empty boxes. We're interested in the top one, Source Package Folders. Hit "Add Folder" to the right of this box. Browse to the mods directory and select your mod folder (ignore the image below showing the data folder, it's wrong). Hit OK, then Next.
    Spoiler


    [close]

    Now we come to the Includes & Excludes menu. Chances are that your mod isn't pure code, so we'll have do to a bit of work here. Change the text in the Includes box from "**" to "**/*.java". If you did this right, only your .java files are in the Included Files box now, with everything else under Excluded Files. Hit Finish.
    Spoiler

    (Ignore the background in this one. I forgot to take a screenshot, so had to go back later.
    [close]

    You should now be able to see your project's folder structure under the Projects tab on the left of the main IDE screen. But what's with all the red exclamation point signs?
    Spoiler
    [close]

    Well, you're still missing something very important. Your code is referencing all these Starfarer APIs, but NetBeans has no idea what you are talking about. To fix this, we need to add the Starfarer API to the Project Libraries. Right click on Libraries in the Project tab, and select "Add Jar/Folder". Navigate to the Starfarer install directory, and enter the folder starfarer-core. Find starfarer.api.jar and select it. You might also want to add lwjgl_util.jar, as that is where the Vector2f class is defined.
    Spoiler

    [close]

    Note that at this point you're probably still going to have a bunch of compile errors due to missing dependencies. Remember, Starfarer mods work by adding your mod on top of what's in starfarer-core, and NetBeans doesn't know about those files. The laziest easiest way to fix this is to just look at the compile errors, find out what files are missing, and copy them over from the Starfarer/starfarer-core/data directory (for most current mods, BaseSpawnPoint will be the big one). After you're done, go to Source - Scan for External Changes. That should allow NetBeans to notice the files you just added. Don't worry about cluttering up your mod, you should only need a few files; even if you did somehow require every core file for compatability, it would add less than 100 kilobytes to your mod size. I'm sure there's a better way of doing this, does anyone who uses NetBeans know of one? I'm aware that you can add starfarer-core to your project source, but then you run the risk of editing core files.

    Most of the compile error warnings should have vanished now (you might still have to do a bit of cleanup), and as an added bonus you can now browse the API at your leisure in the Libraries tree.
    Spoiler
    [close]

    Although you might notice something strange...
    Spoiler
    [close]

    You're looking at a generated source file. Not very intuitive, is it? Don't worry, we can fix this. Right click on starfarer.api.jar in your Projects tab, and click Edit. Hit the Browse button next to Sources and head back to starfarer-core. This time, select starfarer.api.zip.
    Spoiler

    [close]

    You might have to reload the file before any changes show up, but it should now look something like this:
    Spoiler
    [close]

    Isn't this:
    Code
    SectorEntityToken addPlanet(SectorEntityToken focus, String name, String type,
    float angle, float radius, float orbitRadius, float orbitDays);
    Much more intuitive than this:
    Code
    public SectorEntityToken addPlanet(SectorEntityToken set, String string, String string1, float f, float f1, float f2, float f3);

    You're pretty much ready to go at this point. Happy coding!

    (If this tutorial was missing anything, let me know and I'll fix it)

    174
    Mods / Economy Mod (yes, it's still in development)
    « on: June 14, 2012, 02:16:29 AM »
    LazyWizard's Economy Mod

    What will be included:

    First and foremost, trade convoys will serve a purpose other than bringing the player new toys. They will also be the primary money-makers for factions (there might be other ways for a faction to earn credits, depending on balance needs). While there won't be direct player control over the economy, you will be able to hunt down and destroy these fleets to weaken a faction, with the possibility of eventually driving them out of the sector if you are aggressive enough. Alternatively, you could protect these fleets, leading to more and better supplies showing up in stations. It's up to you.

    And because not every player wants to end up the sole survivor in a dead sector, I'm also planning on including ways to resurrect dead factions.

    What might be included:

    The big idea is dynamic fleets. Instead of creating their fleets from a static file somewhere, the faction will build a custom fleet based on available funds, technology, and need.

    There are other ideas floating around, but I hate getting people's hopes up. Really, the plan is to include whatever I can get working. If you have any requests, I'd love to hear them.

    What won't be included:

    Player trading. Sorry, but there's no efficient way to monitor that right now. If this changes, I'll let you know.


    For a more detailed look at the various components of this mod, as well as the current progress on each, see the next post in this thread.


    Mod compatibility:

    Unfortunately, this won't be compatible with most other mods right out of the box. However, any mod maker who wants to integrate these systems into their own mod has my full permission to do so, though they should keep in mind they will have to tear it out once the real economy arrives. I've tried to keep this all easy to implement, though there is some work involved. I'll go into detail on that some other time.

    Screenshots:
    Spoiler
    [close]

    ---------------

    Original post:
    Spoiler
    I got bored yesterday and decided to throw a mod together. There's not much to show yet, but I'd like to officially introduce:

    LazyWizard's Economy Mod

    (note: this wall of text is temporary. I'll replace it with something more coherent as the mod progresses)

    So what will this mod actually do?

    Exactly what it says: add an in-game economy. It will also optionally add an endgame to Starfarer; more on that in a bit.

    The current plan (subject to change as I explore what is possible with the API) is to give each faction a limited amount of funds to buy ships, weapons, and supplies with. Funds will be spent buying trading fleets, and lost when those fleets are destroyed. Trading fleets will get greater inventories as their available funds increase. This gives players a choice: you can protect these fleets so the station will be stocked with more goods and ships (and future fleets will carry higher-tech stuff). Or you can destroy them to damage a faction's economy and weaken their future fleets. Factions who are taking massive damage to their economy will start spawning fewer, larger fleets - this is so a low-level player can't take a faction out singlehandedly - as well as fast-but-powerful fleets to hunt down attackers (two Odysseys with Augmented Engines and a dozen fighter wings? Hell yes!). If a player manages to continue their piracy despite this, they can leave the faction unable to afford replacement ships, and thus effectively defeated - hence, an endgame.

    I plan on releasing two versions of this mod. One will be as described above. The other will provide a constant flow of resources from out-of-sector to poor factions (representing support from back home), preventing permanent annihilation for those who don't want their game to end.


    Why are you making this? You do know Alex is going to add a real economy to the game later, right?

    Yes, I do know that. I fully expect this mod to be completely overshadowed and abandoned once the real thing materializes. This whole mod is actually an excuse: an excuse to learn the Starfarer API, an excuse to re-learn Java after letting my skills rot in favor of C#, an excuse to code something interesting. Usually when I make something like this I keep it to myself, but I've read that others want a more dynamic Corvus and I figured I could help.

    And if I run into some missing API functions and nudge Alex about them, well, it's all for the benefit of the rest of the modding community, right? (sorry in advance, Alex! :D)


    Will this be compatible with other mods?

    With the way I have it set up now, only with extremely simple mods like ship tweaks. Corvus.java is extensively modified, and I plan on completely revamping the spawn points as well. Eventually I'll have to rewrite almost all of the faction data unless I can get direct fleet building to work (other modders: is there an API hook to add/remove ships from a fleet directly?).

    However, if after I release this any enterprising modder wants to add my systems to their existing mod, feel free! Just remember it will eventually be obsoleted. ;)


    So what do you have so far?

    Mostly a headache ;). Like I said, it's been a long time since I touched Java, and that was Java 1.6. Janino is 1.4 with a few 1.5 features bolted on. Half my time is spent being frustrated at what I can't remember anymore, or at features Java lacks that C# has; the other half is being #!% that what I do remember isn't implemented in Janino. Progress should speed up as I re-acclimatize myself.

    However, I do have a very basic economy server up and running. At the moment it's less than 300 lines of code, but the basics are there: it stores the necessary information on a faction's economy, can register new factions and look up existing ones, add/subtract funds, and prints out a nice financial report every in-game week. Right now it's running dummy data (it isn't hooked into Corvus yet beyond creating the economy server and filling it with faction data), but my next task is to start getting hooks into events going on in the sector (mainly tracking the status of trade fleets for now). The current short-term goal is to have trade fleets earn money for their faction upon delivery. Next I want them to base their cargo on how much that faction can afford. I'm taking this one step at a time.


    When will you release a working version?

    I honestly don't know. Probably not soon. I've been able to make cheap hacks to get around current limitations in the API. It's entirely possible that I'll run into a brick wall where the API hooks for something I absolutely need don't exist yet, and I'll have to wait for the next release.

    If I do release soon, it won't be even slightly balanced, playable, or fun. I'm mostly concerned with getting the basic systems in place, not making sure all the math works out. That part requires extensive testing, and that's what you all are for. :D


    If it won't be released for a while, why bother putting up a post now?

    Simple. I needed a break feedback. Comments, ideas, awed praise, that sort of thing. And if another modder spots something in my description that will give me a headache implementing, it'd be nice to know now so I can redesign.


    And finally, for anyone who cares (and somehow made it through that massive wall of text):

    Who the heck are you? What experience do you have?

    I'm just some guy, nobody special. You'll probably see me around the forums sometime. I don't post often, but when I do, I make them way longer and more technical than I need to. (Case in point! ;))

    As for my experience, I'm a hobbyist game developer. I've also made game mods for my own personal use for over a decade. As for real experience, I was a programmer on a MUD (proto-MMO) for six years. Not much else to tell.


    Wait, you make us read that massive novel and don't even give us a screenshot?

    What, really? It's an economy mod, it has the most boring screenshots in...

    You know what? Fine. Whiner. :)
    Spoiler
    [close]
    [close]

    175
    Suggestions / Avoiding accidents by travelling slowly
    « on: March 26, 2012, 06:10:07 PM »
    From the 0.52a patch notes:

    • Added "Accidents" mechanic to handle fleets over various limits
      ..
    • Fixed bug where holding down the left mouse button to move in the campaign screen would not give the fleet its maximum speed unless the cursor was far enough away

    I didn't even know #2 was a bug; I think it would work as an official feature. I use it all the time, as the extra precision helps to get into position to 'bounce' faster enemies against System Defense fleets, which is practically the only way to reliably catch anything when you have a slow fleet.

    I also like the idea of reducing the risk of accidents by travelling below your maximum speed. I don't think it would be too unbalancing, as doing so means you're a sitting duck for any enemy that comes along, and the extra time it takes to get home will rack up the penalties for when you do need to speed away.

    Pages: 1 ... 10 11 [12]