Factorio: implement EnergyLink

This commit is contained in:
Fabian Dill 2022-02-24 00:51:31 +01:00
parent 6e0165986f
commit 05fe423ef1
6 changed files with 118 additions and 11 deletions

View File

@ -441,7 +441,7 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
else:
args['players'].sort()
current_team = -1
logger.info('Players:')
logger.info('Connected Players:')
for network_player in args['players']:
if network_player.team != current_team:
logger.info(f' Team #{network_player.team + 1}')

View File

@ -19,7 +19,7 @@ if __name__ == "__main__":
Utils.init_logging("FactorioClient", exception_logger="Client")
from CommonClient import CommonContext, server_loop, console_loop, ClientCommandProcessor, logger, gui_enabled, \
get_base_parser
get_base_parser
from MultiServer import mark_raw
from NetUtils import NetworkItem, ClientStatus, JSONtoTextParser, JSONMessagePart
@ -62,6 +62,8 @@ class FactorioContext(CommonContext):
self.write_data_path = None
self.death_link_tick: int = 0 # last send death link on Factorio layer
self.factorio_json_text_parser = FactorioJSONtoTextParser(self)
self.energy_link_increment = 0
self.last_deplete = 0
async def server_auth(self, password_requested: bool = False):
if password_requested and not self.password:
@ -105,6 +107,15 @@ class FactorioContext(CommonContext):
if "checked_locations" in args and args["checked_locations"]:
self.rcon_client.send_commands({item_name: f'/ap-get-technology ap-{item_name}-\t-1' for
item_name in args["checked_locations"]})
elif cmd == "SetReply":
if args["key"] == "EnergyLink":
logger.info(f"Got EnergyLink package: {args}")
if self.energy_link_increment and args.get("last_deplete", -1) == self.last_deplete:
# it's our deplete request
gained = args["original_value"] - args["value"]
if gained:
logger.info(f"EnergyLink: Received {gained} Joules")
self.rcon_client.send_command(f"/ap-energylink {int(gained)}")
async def game_watcher(ctx: FactorioContext):
@ -113,7 +124,8 @@ async def game_watcher(ctx: FactorioContext):
next_bridge = time.perf_counter() + 1
try:
while not ctx.exit_event.is_set():
if ctx.awaiting_bridge and ctx.rcon_client and time.perf_counter() > next_bridge:
# TODO: restore on-demand refresh
if ctx.rcon_client and time.perf_counter() > next_bridge:
next_bridge = time.perf_counter() + 1
ctx.awaiting_bridge = False
data = json.loads(ctx.rcon_client.send_command("/ap-sync"))
@ -127,8 +139,7 @@ async def game_watcher(ctx: FactorioContext):
research_data = data["research_done"]
research_data = {int(tech_name.split("-")[1]) for tech_name in research_data}
victory = data["victory"]
if "death_link" in data: # TODO: Remove this if statement around version 0.2.4 or so
await ctx.update_death_link(data["death_link"])
await ctx.update_death_link(data["death_link"])
if not ctx.finished_game and victory:
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
@ -145,6 +156,29 @@ async def game_watcher(ctx: FactorioContext):
ctx.death_link_tick = death_link_tick
if "DeathLink" in ctx.tags:
await ctx.send_death()
if ctx.energy_link_increment:
in_world_bridges = data["energy_bridges"]
if in_world_bridges:
in_world_energy = data["energy"]
if in_world_energy < (ctx.energy_link_increment * in_world_bridges):
# attempt to refill
ctx.last_deplete = time.time()
asyncio.create_task(ctx.send_msgs([{
"cmd": "Set", "key": "EnergyLink", "operation": "deplete",
"value": -ctx.energy_link_increment * in_world_bridges,
"last_deplete": ctx.last_deplete
}]))
# Above Capacity - (len(Bridges) * ENERGY_INCREMENT)
elif in_world_energy > (in_world_bridges * ctx.energy_link_increment * 5) - \
ctx.energy_link_increment*in_world_bridges:
value = ctx.energy_link_increment * in_world_bridges
asyncio.create_task(ctx.send_msgs([{
"cmd": "Set", "key": "EnergyLink", "operation": "add",
"value": value
}]))
ctx.rcon_client.send_command(
f"/ap-energylink -{value}")
logger.info(f"EnergyLink: Sent {value} Joules")
await asyncio.sleep(0.1)
@ -239,6 +273,8 @@ async def get_info(ctx, rcon_client):
ctx.seed_name = info["seed_name"]
# 0.2.0 addition, not present earlier
death_link = bool(info.get("death_link", False))
ctx.energy_link_increment = info.get("energy_link", 0)
logger.debug(f"Energy Link Increment: {ctx.energy_link_increment}")
await ctx.update_death_link(death_link)

View File

@ -24,7 +24,7 @@ class Version(typing.NamedTuple):
build: int
__version__ = "0.2.5"
__version__ = "0.2.6"
version_tuple = tuplize_version(__version__)
from yaml import load, dump, SafeLoader

View File

@ -174,7 +174,7 @@ class Factorio(World):
return super(Factorio, self).collect_item(state, item, remove)
def get_required_client_version(self) -> tuple:
return max((0, 2, 1), super(Factorio, self).get_required_client_version())
return max((0, 2, 6), super(Factorio, self).get_required_client_version())
options = factorio_options

View File

@ -11,6 +11,7 @@ TRAP_EVO_FACTOR = {{ evolution_trap_increase }} / 100
MAX_SCIENCE_PACK = {{ max_science_pack }}
GOAL = {{ goal }}
ARCHIPELAGO_DEATH_LINK_SETTING = "archipelago-death-link-{{ slot_player }}-{{ seed_name }}"
ENERGY_INCREMENT = 1000000
if settings.global[ARCHIPELAGO_DEATH_LINK_SETTING].value then
DEATH_LINK = 1
@ -20,6 +21,40 @@ end
CURRENTLY_DEATH_LOCK = 0
function on_check_energy_link(event)
--- assuming 1 MJ increment and 5MJ battery:
--- first 2 MJ request fill, last 2 MJ push energy, middle 1 MJ does nothing
if event.tick % 60 == 30 then
local surface = game.get_surface(1)
local force = "player"
local bridges = surface.find_entities_filtered({name="ap-energy-bridge", force=force})
local bridgecount = table_size(bridges)
global.forcedata[force].energy_bridges = bridgecount
if global.forcedata[force].energy == nil then
global.forcedata[force].energy = 0
end
if global.forcedata[force].energy < ENERGY_INCREMENT * bridgecount * 5 then
for i, bridge in ipairs(bridges) do
if bridge.energy > ENERGY_INCREMENT*3 then
global.forcedata[force].energy = global.forcedata[force].energy + ENERGY_INCREMENT
bridge.energy = bridge.energy - ENERGY_INCREMENT
end
end
end
for i, bridge in ipairs(bridges) do
if global.forcedata[force].energy < ENERGY_INCREMENT then
break
end
if bridge.energy < ENERGY_INCREMENT*2 and global.forcedata[force].energy > ENERGY_INCREMENT then
global.forcedata[force].energy = global.forcedata[force].energy - ENERGY_INCREMENT
bridge.energy = bridge.energy + ENERGY_INCREMENT
end
end
game.print("Bridges: " .. bridgecount .. " With: " .. global.forcedata["player"].energy)
end
end
script.on_event(defines.events.on_tick, on_check_energy_link)
{% if not imported_blueprints -%}
function set_permissions()
local group = game.permissions.get_group("Default")
@ -69,6 +104,8 @@ function on_force_created(event)
data['earned_samples'] = {{ dict_to_lua(starting_items) }}
data["victory"] = 0
data["death_link_tick"] = 0
data["energy"] = 0
data["energy_bridges"] = 0
global.forcedata[event.force] = data
{%- if silo == 2 %}
check_spawn_silo(force)
@ -434,11 +471,14 @@ commands.add_command("ap-sync", "Used by the Archipelago client to get progress
force = game.players[call.player_index].force
end
local research_done = {}
local forcedata = chain_lookup(global, "forcedata", force.name)
local data_collection = {
["research_done"] = research_done,
["victory"] = chain_lookup(global, "forcedata", force.name, "victory"),
["death_link_tick"] = chain_lookup(global, "forcedata", force.name, "death_link_tick"),
["death_link"] = DEATH_LINK
["victory"] = chain_lookup(forcedata, "victory"),
["death_link_tick"] = chain_lookup(forcedata, "death_link_tick"),
["death_link"] = DEATH_LINK,
["energy"] = chain_lookup(forcedata, "energy"),
["energy_bridges"] = chain_lookup(forcedata, "energy_bridges"),
}
for tech_name, tech in pairs(force.technologies) do
@ -515,7 +555,12 @@ end)
commands.add_command("ap-rcon-info", "Used by the Archipelago client to get information", function(call)
rcon.print(game.table_to_json({["slot_name"] = SLOT_NAME, ["seed_name"] = SEED_NAME, ["death_link"] = DEATH_LINK}))
rcon.print(game.table_to_json({
["slot_name"] = SLOT_NAME,
["seed_name"] = SEED_NAME,
["death_link"] = DEATH_LINK,
["energy_link"] = ENERGY_INCREMENT
}))
end)
@ -533,6 +578,11 @@ commands.add_command("ap-deathlink", "Kill all players", function(call)
game.print("Death was granted by " .. source)
end)
commands.add_command("ap-energylink", "Used by the Archipelago client to manage Energy Link", function(call)
local change = tonumber(call.parameter or "0")
local force = "player"
global.forcedata[force].energy = global.forcedata[force].energy + change
end)
-- data
progressive_technologies = {{ dict_to_lua(progressive_technology_table) }}

View File

@ -1,4 +1,25 @@
{% from "macros.lua" import dict_to_lua %}
local energy_bridge = table.deepcopy(data.raw["accumulator"]["accumulator"])
energy_bridge.name = "ap-energy-bridge"
energy_bridge.minable.result = "ap-energy-bridge"
energy_bridge.localised_name = "Archipelago EnergyLink Bridge"
data.raw["accumulator"]["ap-energy-bridge"] = energy_bridge
local energy_bridge_item = table.deepcopy(data.raw["item"]["accumulator"])
energy_bridge_item.name = "ap-energy-bridge"
energy_bridge_item.localised_name = "Archipelago EnergyLink Bridge"
energy_bridge_item.place_result = energy_bridge.name
data.raw["item"]["ap-energy-bridge"] = energy_bridge_item
local energy_bridge_recipe = table.deepcopy(data.raw["recipe"]["accumulator"])
energy_bridge_recipe.name = "ap-energy-bridge"
energy_bridge_recipe.result = energy_bridge_item.name
energy_bridge_recipe.energy_required = 1
energy_bridge_recipe.ingredients = { {# {type="item", name="iron-plate", amount=1} TODO: randomized recipe #} }
energy_bridge_recipe.enabled = true
energy_bridge_recipe.localised_name = "Archipelago EnergyLink Bridge"
data.raw["recipe"]["ap-energy-bridge"] = energy_bridge_recipe
data.raw["map-gen-presets"].default["archipelago"] = {{ dict_to_lua({"default": False, "order": "a", "basic_settings": world_gen["basic"], "advanced_settings": world_gen["advanced"]}) }}
if mods["science-not-invited"] then
local weights = {