Skip to content

Commit

Permalink
Merge pull request #36 from Danielv123/universal-edges
Browse files Browse the repository at this point in the history
Universal edges
  • Loading branch information
Danielv123 authored Jun 10, 2024
2 parents 231d5ee + 26b8673 commit 9cb839c
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 178 deletions.
18 changes: 0 additions & 18 deletions controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,8 @@ class ControllerPlugin extends BaseControllerPlugin {
async onInstanceStatusChanged(instance) {
if (instance.status === "running") {
let instanceId = instance.config.get("instance.id");
let hostId = instance.config.get("instance.assigned_host");
let x = instance.config.get("gridworld.grid_x_position");
let y = instance.config.get("gridworld.grid_y_position");
let hostConnection = this.controller.wsServer.hostConnections.get(hostId);
let instances = [...this.controller.instances];
await this.controller.sendTo({ instanceId }, new messages.PopulateNeighborData({
instance_id: instanceId,
Expand All @@ -146,22 +144,6 @@ class ControllerPlugin extends BaseControllerPlugin {
}
}

async setInstanceConfigField(instanceId, field, value) {
// Code lifted from ControlConnection.js handleInstanceConfigSetFieldRequest(request)
let instance = this.controller.getRequestInstance(instanceId);
if (field === "instance.assigned_host") {
throw new lib.RequestError("instance.assigned_host must be set through the assign-host interface");
}

if (field === "instance.id") {
// XXX is this worth implementing? It's race condition galore.
throw new lib.RequestError("Setting instance.id is not supported");
}

instance.config.set(field, value, "control");
await this.controller.instanceConfigUpdated(instance);
}

onControlConnectionEvent(connection, event) {
if (event === "close") {
let index = this.subscribedControlLinks.indexOf(sub => sub.link === connection);
Expand Down
31 changes: 10 additions & 21 deletions docs/worldgen/factionGrid/generate server.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ The server generation function takes care of the following:
2. Assign to a host with free capacity
3. Create a new save
4. Apply gridworld configuration options
5. Apply edge transports configuration
6. Apply edge transports configuration to neighboring servers
7. Start the server
8. Run world border creation scripts
5. Apply universal edges configuration
6. Start the server
7. Run world border creation scripts

## Gridworld configuration options

Expand All @@ -25,22 +24,12 @@ The following settings are set on the instance:
| `gridworld.grid_x_size` | The x size of the grid in the world |
| `gridworld.grid_y_size` | The y size of the grid in the world |

## Edge transports configuration
## Universal edges configuration

The following settings are set on the instance:
As of version 0.6 gridworld uses [universal_edges](https://github.com/Danielv123/universal_edges) instead of [edge_transports](https://github.com/clusterio/edge_transports). Universal edges is a typescript rewrite that uses a new configuration system and has support for more connector types (fluids, power, trains).

Edges allow for setting up connectors to transport items/fluids/power/trains between servers. They are automatically configured during server creation. Edges can be inspected/modified using the universal_edges web UI. There are a few peculiarities to how edges are set up with gridworld:

| Setting | Description |
| -------------------------- | ----------------------------- |
| `edge_transports.internal` | Edge transports configuration |

The edge transports configuration is an object like `{edges: []}`. Each edge has the following properties:

| Property | Description |
| ----------------- | ----------------------------------------------------------------------------------------------- |
| `id` | edge ID |
| `origin` | [x,y] |
| `surface` | Target surface index, always 1 for gridworld |
| `direction` | Factorio cardinal direction index. The border is drawn as a beam with the IO on the right side. |
| `length` | Length of border |
| `target_instance` | Instance ID of target server |
| `target_edge` | Corresponding edge ID on the target server |
1. Edge IDs are not random, but based on the grid square the edge connects. `edge_${from}_${to}` where `from` and `to` are x,y coordinates.
2. At least during initial develpment, edges are refreshed on each instance start. This reduces the need for migrations, but means manual changes to the edge config can be unstable.
3. Unlike the old edge transports integration, gridworld no longer overwrites edges it did not create. This allows for custom topologies.
1 change: 1 addition & 0 deletions instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class InstancePlugin extends BaseInstancePlugin {
await this.sendRcon(`/sc gridworld.create_spawn("${data.x_size}","${data.y_size}","${data.world_x}","${data.world_y}", false)`, true);
// Update neighboring nodes for edge_transports
await sleep(1000);
// TODO: The following command can be disabled once edge creation during instance creation is stable
await this.instance.sendTo("controller", new messages.UpdateEdgeTransportEdges({
instance_id: this.instance.config.get("instance.id"),
}));
Expand Down
18 changes: 0 additions & 18 deletions messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,24 +74,6 @@ module.exports = {
items: { type: "number" },
},
},
edges: {
type: "array",
items: {
type: "object",
properties: {
id: { type: "integer" },
origin: {
type: "array",
items: { type: "integer" },
},
surface: { type: "integer" },
direction: { type: "integer" },
length: { type: "integer" },
target_instance: { type: "integer" },
target_edge: { type: "integer" },
},
},
},
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"repository": "Danielv123/gridworld",
"scripts": {
"prepare": "webpack-cli --env production && husky install",
"cloc": "cloc --exclude-dir=node_modules,dist .",
"lint": "eslint \"*.js\" src web --fix",
"luacheck": "luacheck module/",
"test": "spaces-to-tabs -s 4 module/**.lua module/**/**.lua module/**/**/**.lua module/**/**/**/**.lua module/**/**/**/**/**.lua && npm run lint && npm run luacheck"
Expand Down Expand Up @@ -41,7 +42,6 @@
},
"devDependencies": {
"@clusterio/web_ui": "^2.0.0-alpha.0",
"@codecov/webpack-plugin": "0.0.1-beta.6",
"@react-leaflet/core": "^2.1.0",
"@swc/core": "^1.4.0",
"antd": "^5.13.0",
Expand Down
1 change: 1 addition & 0 deletions src/request_handlers/claimServerRequestHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = async function claimServerRequestHandler(message) {
message: "Faction does not exist",
};
}
// TODO: Method no longer exists
this.setInstanceConfigField(message.data.instance_id, "gridworld.claimed_by_faction", message.data.faction_id);
return {
ok: true,
Expand Down
1 change: 0 additions & 1 deletion src/request_handlers/getMapDataRequestHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ module.exports = async function getMapDataRequestHandler({ grid_id }) {
instance[1].config.get("gridworld.grid_y_size"),
],
],
edges: instance[1].config.get("edge_transports.internal").edges,
})),
};
};
1 change: 1 addition & 0 deletions src/request_handlers/unclaimServerRequestHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = async function unclaimServerRequestHandler(message) {
// instance_id: 1,
// };

// TODO: Method no longer exists
this.setInstanceConfigField(message.data.instance_id, "gridworld.claimed_by_faction", "-");
return {
ok: true,
Expand Down
63 changes: 3 additions & 60 deletions src/request_handlers/updateEdgeTransportEdgesRequestHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

const mapFind = require("../util/mapFind");
const getEdges = require("../worldgen/getEdges");
const { edge_target_position_offsets } = require("../worldgen/factionGrid/edge_target_position_offsets");

/**
* Update edge transports edges for a grid square instance
Expand Down Expand Up @@ -39,68 +38,12 @@ module.exports = async function updateEdgeTransportsEdges(message) {
y,
instances: this.controller.instances,
grid_id,
instanceId: message.data.instance_id,
});

// Find neighboring instances and update edge target instance ID
for (const edge of edges) {
const target_position = [
x + edge_target_position_offsets[edge.id][0],
y + edge_target_position_offsets[edge.id][1],
];
const target_instance = this.controller.instances.get(edge.target_instance);
if (
target_instance.config.get("gridworld.grid_id") === grid_id
&& target_instance.config.get("gridworld.grid_x_position") === target_position[0]
&& target_instance.config.get("gridworld.grid_y_position") === target_position[1]
) {
// Update target instance edge configuration
const edge_transports_config = JSON.parse(JSON.stringify(target_instance.config.get("edge_transports.internal")));
const target_edge = edge_transports_config.edges.find(e => e.id === edge.target_edge);
if (target_edge) {
target_edge.target_instance = message.data.instance_id;
await this.setInstanceConfigField(edge.target_instance, "edge_transports.internal", edge_transports_config);
this.logger.info(`Updated edge ${target_edge.id} on existing instance ${edge.target_instance} to target ${message.data.instance_id}`);
} else {
// Add new edge
const target_x_size = target_instance.config.get("gridworld.grid_x_size");
const target_y_size = target_instance.config.get("gridworld.grid_y_size");
const target_x = target_instance.config.get("gridworld.grid_x_position");
const target_y = target_instance.config.get("gridworld.grid_y_position");

const worldfactor_x = (target_x - 1) * target_x_size;
const worldfactor_y = (target_y - 1) * target_y_size;

const origins = [
[worldfactor_x, worldfactor_y],
[target_x_size + worldfactor_x, worldfactor_y],
[target_x_size + worldfactor_x, target_y_size + worldfactor_y],
[worldfactor_x, target_y_size + worldfactor_y],
];

let length = target_x_size;
if (edge.direction % 2 === 0) {
length = target_y_size;
}

const new_edge = {
id: edge.target_edge,
origin: origins[edge.target_edge - 1],
surface: 1,
direction: (edge.direction + 4) % 8,
length,
target_instance: message.data.instance_id,
target_edge: edge.id,
};
edge_transports_config.edges.push(new_edge);
await this.setInstanceConfigField(edge.target_instance, "edge_transports.internal", edge_transports_config);
this.logger.info(`Created new edge on existing instance ${edge.target_instance}`);
}
}
}

// Set config
this.logger.info(`Set edges on new instance ${message.data.instance_id}`);
await this.setInstanceConfigField(message.data.instance_id, "edge_transports.internal", {
edges: edges,
edges.forEach(edge => {
this.controller.plugins.get("universal_edges").handleSetEdgeConfigRequest({ edge });
});
};
35 changes: 35 additions & 0 deletions src/util/direction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"use strict";
/**
* If edge direction is 4 (West), that means the belts enter going north to south.
* The right hand side of the edge is always the entrance/exit
*/
const directions = [
"East",
"South-east",
"South",
"South-west",
"West",
"North-west",
"North",
"North-east",
];

function direction_to_string(direction) {
if (direction === undefined) {
return "";
}
if (typeof direction !== "number" || direction < 0 || direction >= 8) {
return "unknown";
}
return directions[direction % 8];
}

function string_to_direction(string) {
return directions.indexOf(string);
}

module.exports = {
direction_to_string,
string_to_direction,
directions,
};
15 changes: 15 additions & 0 deletions src/worldgen/factionGrid/createServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ module.exports = async function createServer({
plugin.controller.config.get("gridworld.gridworld_map_exchange_string")
);

// Update edges
let edges = getEdges({
x,
y,
x_size,
y_size,
instances: plugin.controller.instances,
grid_id: grid_id,
includeMissing: false, // Create edges for instances that are not generated yet
instanceId,
});
edges.forEach(edge => {
plugin.controller.plugins.get("universal_edges").handleSetEdgeConfigRequest({ edge });
});

return {
instanceId,
};
Expand Down
Loading

0 comments on commit 9cb839c

Please sign in to comment.