diff --git a/resources/iw2/_codxe/codxe.json b/_codxe/iw2/codxe.json similarity index 100% rename from resources/iw2/_codxe/codxe.json rename to _codxe/iw2/codxe.json diff --git a/resources/iw2/_codxe/mods/example/maps/_minefields.gsc b/_codxe/iw2/mods/example/maps/_minefields.gsc similarity index 100% rename from resources/iw2/_codxe/mods/example/maps/_minefields.gsc rename to _codxe/iw2/mods/example/maps/_minefields.gsc diff --git a/resources/iw2/_codxe/mods/example/maps/custom.gsc b/_codxe/iw2/mods/example/maps/custom.gsc similarity index 100% rename from resources/iw2/_codxe/mods/example/maps/custom.gsc rename to _codxe/iw2/mods/example/maps/custom.gsc diff --git a/resources/iw2/_codxe/mods/example/maps/mp/gametypes/_clientids.gsc b/_codxe/iw2/mods/example/maps/mp/gametypes/_clientids.gsc similarity index 100% rename from resources/iw2/_codxe/mods/example/maps/mp/gametypes/_clientids.gsc rename to _codxe/iw2/mods/example/maps/mp/gametypes/_clientids.gsc diff --git a/resources/iw2/_codxe/mods/example/maps/mp/gametypes/custom_mp.gsc b/_codxe/iw2/mods/example/maps/mp/gametypes/custom_mp.gsc similarity index 100% rename from resources/iw2/_codxe/mods/example/maps/mp/gametypes/custom_mp.gsc rename to _codxe/iw2/mods/example/maps/mp/gametypes/custom_mp.gsc diff --git a/resources/iw3/_codxe/internal/maps/ac130.d3dbsp.ents b/_codxe/iw3/internal/maps/ac130.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/ac130.d3dbsp.ents rename to _codxe/iw3/internal/maps/ac130.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/ac130.gsc b/_codxe/iw3/internal/maps/ac130.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/ac130.gsc rename to _codxe/iw3/internal/maps/ac130.gsc diff --git a/resources/iw3/_codxe/internal/maps/aftermath.d3dbsp.ents b/_codxe/iw3/internal/maps/aftermath.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/aftermath.d3dbsp.ents rename to _codxe/iw3/internal/maps/aftermath.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/aftermath.gsc b/_codxe/iw3/internal/maps/aftermath.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/aftermath.gsc rename to _codxe/iw3/internal/maps/aftermath.gsc diff --git a/resources/iw3/_codxe/internal/maps/airlift.d3dbsp.ents b/_codxe/iw3/internal/maps/airlift.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/airlift.d3dbsp.ents rename to _codxe/iw3/internal/maps/airlift.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/airlift.gsc b/_codxe/iw3/internal/maps/airlift.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/airlift.gsc rename to _codxe/iw3/internal/maps/airlift.gsc diff --git a/resources/iw3/_codxe/internal/maps/airplane.d3dbsp.ents b/_codxe/iw3/internal/maps/airplane.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/airplane.d3dbsp.ents rename to _codxe/iw3/internal/maps/airplane.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/airplane.gsc b/_codxe/iw3/internal/maps/airplane.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/airplane.gsc rename to _codxe/iw3/internal/maps/airplane.gsc diff --git a/resources/iw3/_codxe/internal/maps/ambush.d3dbsp.ents b/_codxe/iw3/internal/maps/ambush.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/ambush.d3dbsp.ents rename to _codxe/iw3/internal/maps/ambush.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/ambush.gsc b/_codxe/iw3/internal/maps/ambush.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/ambush.gsc rename to _codxe/iw3/internal/maps/ambush.gsc diff --git a/resources/iw3/_codxe/internal/maps/armada.d3dbsp.ents b/_codxe/iw3/internal/maps/armada.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/armada.d3dbsp.ents rename to _codxe/iw3/internal/maps/armada.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/armada.gsc b/_codxe/iw3/internal/maps/armada.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/armada.gsc rename to _codxe/iw3/internal/maps/armada.gsc diff --git a/resources/iw3/_codxe/internal/maps/blackout.d3dbsp.ents b/_codxe/iw3/internal/maps/blackout.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/blackout.d3dbsp.ents rename to _codxe/iw3/internal/maps/blackout.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/blackout.gsc b/_codxe/iw3/internal/maps/blackout.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/blackout.gsc rename to _codxe/iw3/internal/maps/blackout.gsc diff --git a/resources/iw3/_codxe/internal/maps/bog_a.d3dbsp.ents b/_codxe/iw3/internal/maps/bog_a.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/bog_a.d3dbsp.ents rename to _codxe/iw3/internal/maps/bog_a.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/bog_a.gsc b/_codxe/iw3/internal/maps/bog_a.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/bog_a.gsc rename to _codxe/iw3/internal/maps/bog_a.gsc diff --git a/resources/iw3/_codxe/internal/maps/bog_b.d3dbsp.ents b/_codxe/iw3/internal/maps/bog_b.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/bog_b.d3dbsp.ents rename to _codxe/iw3/internal/maps/bog_b.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/bog_b.gsc b/_codxe/iw3/internal/maps/bog_b.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/bog_b.gsc rename to _codxe/iw3/internal/maps/bog_b.gsc diff --git a/resources/iw3/_codxe/internal/maps/cargoship.d3dbsp.ents b/_codxe/iw3/internal/maps/cargoship.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/cargoship.d3dbsp.ents rename to _codxe/iw3/internal/maps/cargoship.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/cargoship.gsc b/_codxe/iw3/internal/maps/cargoship.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/cargoship.gsc rename to _codxe/iw3/internal/maps/cargoship.gsc diff --git a/resources/iw3/_codxe/internal/maps/coup.d3dbsp.ents b/_codxe/iw3/internal/maps/coup.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/coup.d3dbsp.ents rename to _codxe/iw3/internal/maps/coup.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/coup.gsc b/_codxe/iw3/internal/maps/coup.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/coup.gsc rename to _codxe/iw3/internal/maps/coup.gsc diff --git a/resources/iw3/_codxe/internal/maps/hunted.d3dbsp.ents b/_codxe/iw3/internal/maps/hunted.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/hunted.d3dbsp.ents rename to _codxe/iw3/internal/maps/hunted.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/hunted.gsc b/_codxe/iw3/internal/maps/hunted.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/hunted.gsc rename to _codxe/iw3/internal/maps/hunted.gsc diff --git a/resources/iw3/_codxe/internal/maps/icbm.d3dbsp.ents b/_codxe/iw3/internal/maps/icbm.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/icbm.d3dbsp.ents rename to _codxe/iw3/internal/maps/icbm.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/icbm.gsc b/_codxe/iw3/internal/maps/icbm.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/icbm.gsc rename to _codxe/iw3/internal/maps/icbm.gsc diff --git a/resources/iw3/_codxe/internal/maps/jeepride.d3dbsp.ents b/_codxe/iw3/internal/maps/jeepride.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/jeepride.d3dbsp.ents rename to _codxe/iw3/internal/maps/jeepride.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/jeepride.gsc b/_codxe/iw3/internal/maps/jeepride.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/jeepride.gsc rename to _codxe/iw3/internal/maps/jeepride.gsc diff --git a/resources/iw3/_codxe/internal/maps/killhouse.d3dbsp.ents b/_codxe/iw3/internal/maps/killhouse.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/killhouse.d3dbsp.ents rename to _codxe/iw3/internal/maps/killhouse.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/killhouse.gsc b/_codxe/iw3/internal/maps/killhouse.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/killhouse.gsc rename to _codxe/iw3/internal/maps/killhouse.gsc diff --git a/resources/iw3/_codxe/internal/maps/launchfacility_a.d3dbsp.ents b/_codxe/iw3/internal/maps/launchfacility_a.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/launchfacility_a.d3dbsp.ents rename to _codxe/iw3/internal/maps/launchfacility_a.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/launchfacility_a.gsc b/_codxe/iw3/internal/maps/launchfacility_a.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/launchfacility_a.gsc rename to _codxe/iw3/internal/maps/launchfacility_a.gsc diff --git a/resources/iw3/_codxe/internal/maps/launchfacility_b.d3dbsp.ents b/_codxe/iw3/internal/maps/launchfacility_b.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/launchfacility_b.d3dbsp.ents rename to _codxe/iw3/internal/maps/launchfacility_b.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/launchfacility_b.gsc b/_codxe/iw3/internal/maps/launchfacility_b.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/launchfacility_b.gsc rename to _codxe/iw3/internal/maps/launchfacility_b.gsc diff --git a/resources/iw3/_codxe/internal/maps/scoutsniper.d3dbsp.ents b/_codxe/iw3/internal/maps/scoutsniper.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/scoutsniper.d3dbsp.ents rename to _codxe/iw3/internal/maps/scoutsniper.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/scoutsniper.gsc b/_codxe/iw3/internal/maps/scoutsniper.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/scoutsniper.gsc rename to _codxe/iw3/internal/maps/scoutsniper.gsc diff --git a/resources/iw3/_codxe/internal/maps/sniperescape.d3dbsp.ents b/_codxe/iw3/internal/maps/sniperescape.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/sniperescape.d3dbsp.ents rename to _codxe/iw3/internal/maps/sniperescape.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/sniperescape.gsc b/_codxe/iw3/internal/maps/sniperescape.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/sniperescape.gsc rename to _codxe/iw3/internal/maps/sniperescape.gsc diff --git a/resources/iw3/_codxe/internal/maps/village_assault.d3dbsp.ents b/_codxe/iw3/internal/maps/village_assault.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/village_assault.d3dbsp.ents rename to _codxe/iw3/internal/maps/village_assault.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/village_assault.gsc b/_codxe/iw3/internal/maps/village_assault.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/village_assault.gsc rename to _codxe/iw3/internal/maps/village_assault.gsc diff --git a/resources/iw3/_codxe/internal/maps/village_defend.d3dbsp.ents b/_codxe/iw3/internal/maps/village_defend.d3dbsp.ents similarity index 100% rename from resources/iw3/_codxe/internal/maps/village_defend.d3dbsp.ents rename to _codxe/iw3/internal/maps/village_defend.d3dbsp.ents diff --git a/resources/iw3/_codxe/internal/maps/village_defend.gsc b/_codxe/iw3/internal/maps/village_defend.gsc similarity index 100% rename from resources/iw3/_codxe/internal/maps/village_defend.gsc rename to _codxe/iw3/internal/maps/village_defend.gsc diff --git a/resources/iw3/_codxe/mods/codjumper/README.md b/_codxe/iw3/mods/codjumper/README.md similarity index 100% rename from resources/iw3/_codxe/mods/codjumper/README.md rename to _codxe/iw3/mods/codjumper/README.md diff --git a/resources/iw3/_codxe/mods/codjumper/buttons_default.cfg b/_codxe/iw3/mods/codjumper/buttons_default.cfg similarity index 100% rename from resources/iw3/_codxe/mods/codjumper/buttons_default.cfg rename to _codxe/iw3/mods/codjumper/buttons_default.cfg diff --git a/resources/iw3/_codxe/mods/codjumper/fixed_fps.cfg b/_codxe/iw3/mods/codjumper/fixed_fps.cfg similarity index 100% rename from resources/iw3/_codxe/mods/codjumper/fixed_fps.cfg rename to _codxe/iw3/mods/codjumper/fixed_fps.cfg diff --git a/resources/iw3/_codxe/mods/codjumper/images/~weapon_rpg7_spec-rgb&weapon_~06163c5b.dds b/_codxe/iw3/mods/codjumper/images/~weapon_rpg7_spec-rgb&weapon_~06163c5b.dds similarity index 100% rename from resources/iw3/_codxe/mods/codjumper/images/~weapon_rpg7_spec-rgb&weapon_~06163c5b.dds rename to _codxe/iw3/mods/codjumper/images/~weapon_rpg7_spec-rgb&weapon_~06163c5b.dds diff --git a/resources/iw3/_codxe/mods/codjumper/maps/mp/gametypes/_globallogic.gsc b/_codxe/iw3/mods/codjumper/maps/mp/gametypes/_globallogic.gsc similarity index 100% rename from resources/iw3/_codxe/mods/codjumper/maps/mp/gametypes/_globallogic.gsc rename to _codxe/iw3/mods/codjumper/maps/mp/gametypes/_globallogic.gsc diff --git a/resources/iw3/_codxe/mods/codjumper/maps/mp/gametypes/_rank.gsc b/_codxe/iw3/mods/codjumper/maps/mp/gametypes/_rank.gsc similarity index 100% rename from resources/iw3/_codxe/mods/codjumper/maps/mp/gametypes/_rank.gsc rename to _codxe/iw3/mods/codjumper/maps/mp/gametypes/_rank.gsc diff --git a/resources/iw3/_codxe/mods/codjumper/maps/mp/gametypes/cj.gsc b/_codxe/iw3/mods/codjumper/maps/mp/gametypes/cj.gsc similarity index 100% rename from resources/iw3/_codxe/mods/codjumper/maps/mp/gametypes/cj.gsc rename to _codxe/iw3/mods/codjumper/maps/mp/gametypes/cj.gsc diff --git a/resources/iw3/_codxe/mods/codjumper/maps/mp/gametypes/dm.gsc b/_codxe/iw3/mods/codjumper/maps/mp/gametypes/dm.gsc similarity index 100% rename from resources/iw3/_codxe/mods/codjumper/maps/mp/gametypes/dm.gsc rename to _codxe/iw3/mods/codjumper/maps/mp/gametypes/dm.gsc diff --git a/resources/iw3/_codxe/mods/codjumper/maps/mp/gametypes/war.gsc b/_codxe/iw3/mods/codjumper/maps/mp/gametypes/war.gsc similarity index 100% rename from resources/iw3/_codxe/mods/codjumper/maps/mp/gametypes/war.gsc rename to _codxe/iw3/mods/codjumper/maps/mp/gametypes/war.gsc diff --git a/resources/iw3/_codxe/mods/codjumper/pc_fps.cfg b/_codxe/iw3/mods/codjumper/pc_fps.cfg similarity index 100% rename from resources/iw3/_codxe/mods/codjumper/pc_fps.cfg rename to _codxe/iw3/mods/codjumper/pc_fps.cfg diff --git a/resources/iw3/_codxe/mods/example/maps/_cagedchickens.gsc b/_codxe/iw3/mods/example/maps/_cagedchickens.gsc similarity index 100% rename from resources/iw3/_codxe/mods/example/maps/_cagedchickens.gsc rename to _codxe/iw3/mods/example/maps/_cagedchickens.gsc diff --git a/resources/iw3/_codxe/mods/example/maps/example.gsc b/_codxe/iw3/mods/example/maps/example.gsc similarity index 100% rename from resources/iw3/_codxe/mods/example/maps/example.gsc rename to _codxe/iw3/mods/example/maps/example.gsc diff --git a/resources/iw4/_codxe/codxe.json b/_codxe/iw4/codxe.json similarity index 100% rename from resources/iw4/_codxe/codxe.json rename to _codxe/iw4/codxe.json diff --git a/resources/iw4/_codxe/mods/codjumper/maps/_names.gsc b/_codxe/iw4/mods/codjumper/maps/_names.gsc similarity index 100% rename from resources/iw4/_codxe/mods/codjumper/maps/_names.gsc rename to _codxe/iw4/mods/codjumper/maps/_names.gsc diff --git a/resources/iw4/_codxe/mods/codjumper/maps/cj.gsc b/_codxe/iw4/mods/codjumper/maps/cj.gsc similarity index 100% rename from resources/iw4/_codxe/mods/codjumper/maps/cj.gsc rename to _codxe/iw4/mods/codjumper/maps/cj.gsc diff --git a/resources/iw4/_codxe/mods/codjumper/maps/codxe_utility.gsc b/_codxe/iw4/mods/codjumper/maps/codxe_utility.gsc similarity index 100% rename from resources/iw4/_codxe/mods/codjumper/maps/codxe_utility.gsc rename to _codxe/iw4/mods/codjumper/maps/codxe_utility.gsc diff --git a/resources/iw4/_codxe/mods/codjumper/maps/mp/gametypes/_codxe_utility.gsc b/_codxe/iw4/mods/codjumper/maps/mp/gametypes/_codxe_utility.gsc similarity index 100% rename from resources/iw4/_codxe/mods/codjumper/maps/mp/gametypes/_codxe_utility.gsc rename to _codxe/iw4/mods/codjumper/maps/mp/gametypes/_codxe_utility.gsc diff --git a/resources/iw4/_codxe/mods/codjumper/maps/mp/gametypes/cj_hud.gsc b/_codxe/iw4/mods/codjumper/maps/mp/gametypes/cj_hud.gsc similarity index 100% rename from resources/iw4/_codxe/mods/codjumper/maps/mp/gametypes/cj_hud.gsc rename to _codxe/iw4/mods/codjumper/maps/mp/gametypes/cj_hud.gsc diff --git a/resources/iw4/_codxe/mods/codjumper/maps/mp/gametypes/cj_mp.gsc b/_codxe/iw4/mods/codjumper/maps/mp/gametypes/cj_mp.gsc similarity index 100% rename from resources/iw4/_codxe/mods/codjumper/maps/mp/gametypes/cj_mp.gsc rename to _codxe/iw4/mods/codjumper/maps/mp/gametypes/cj_mp.gsc diff --git a/resources/iw4/_codxe/mods/codjumper/maps/mp/gametypes/menu.gsc b/_codxe/iw4/mods/codjumper/maps/mp/gametypes/menu.gsc similarity index 100% rename from resources/iw4/_codxe/mods/codjumper/maps/mp/gametypes/menu.gsc rename to _codxe/iw4/mods/codjumper/maps/mp/gametypes/menu.gsc diff --git a/resources/iw4/_codxe/mods/codjumper/maps/mp/gametypes/war.gsc b/_codxe/iw4/mods/codjumper/maps/mp/gametypes/war.gsc similarity index 100% rename from resources/iw4/_codxe/mods/codjumper/maps/mp/gametypes/war.gsc rename to _codxe/iw4/mods/codjumper/maps/mp/gametypes/war.gsc diff --git a/resources/iw4/_codxe/mods/example/maps/_cagedchickens.gsc b/_codxe/iw4/mods/example/maps/_cagedchickens.gsc similarity index 100% rename from resources/iw4/_codxe/mods/example/maps/_cagedchickens.gsc rename to _codxe/iw4/mods/example/maps/_cagedchickens.gsc diff --git a/resources/iw4/_codxe/mods/example/maps/codxe_utility.gsc b/_codxe/iw4/mods/example/maps/codxe_utility.gsc similarity index 100% rename from resources/iw4/_codxe/mods/example/maps/codxe_utility.gsc rename to _codxe/iw4/mods/example/maps/codxe_utility.gsc diff --git a/resources/iw4/_codxe/mods/example/maps/example_sp.gsc b/_codxe/iw4/mods/example/maps/example_sp.gsc similarity index 100% rename from resources/iw4/_codxe/mods/example/maps/example_sp.gsc rename to _codxe/iw4/mods/example/maps/example_sp.gsc diff --git a/resources/iw5/_codxe/codxe.json b/_codxe/iw5/codxe.json similarity index 100% rename from resources/iw5/_codxe/codxe.json rename to _codxe/iw5/codxe.json diff --git a/resources/iw5/_codxe/mods/codjumper/maps/mp/gametypes/cj.gsc b/_codxe/iw5/mods/codjumper/maps/mp/gametypes/cj.gsc similarity index 100% rename from resources/iw5/_codxe/mods/codjumper/maps/mp/gametypes/cj.gsc rename to _codxe/iw5/mods/codjumper/maps/mp/gametypes/cj.gsc diff --git a/resources/iw5/_codxe/mods/codjumper/maps/mp/gametypes/cj.gscbin b/_codxe/iw5/mods/codjumper/maps/mp/gametypes/cj.gscbin similarity index 100% rename from resources/iw5/_codxe/mods/codjumper/maps/mp/gametypes/cj.gscbin rename to _codxe/iw5/mods/codjumper/maps/mp/gametypes/cj.gscbin diff --git a/resources/iw5/_codxe/mods/codjumper/maps/mp/gametypes/war.gsc b/_codxe/iw5/mods/codjumper/maps/mp/gametypes/war.gsc similarity index 100% rename from resources/iw5/_codxe/mods/codjumper/maps/mp/gametypes/war.gsc rename to _codxe/iw5/mods/codjumper/maps/mp/gametypes/war.gsc diff --git a/resources/iw5/_codxe/mods/codjumper/maps/mp/gametypes/war.gscbin b/_codxe/iw5/mods/codjumper/maps/mp/gametypes/war.gscbin similarity index 100% rename from resources/iw5/_codxe/mods/codjumper/maps/mp/gametypes/war.gscbin rename to _codxe/iw5/mods/codjumper/maps/mp/gametypes/war.gscbin diff --git a/resources/qos/_codxe/codxe.json b/_codxe/qos/codxe.json similarity index 100% rename from resources/qos/_codxe/codxe.json rename to _codxe/qos/codxe.json diff --git a/resources/qos/_codxe/mods/example/maps/mp/gametypes/_clientids.gsc b/_codxe/qos/mods/example/maps/mp/gametypes/_clientids.gsc similarity index 100% rename from resources/qos/_codxe/mods/example/maps/mp/gametypes/_clientids.gsc rename to _codxe/qos/mods/example/maps/mp/gametypes/_clientids.gsc diff --git a/resources/qos/_codxe/mods/example/maps/mp/gametypes/example_mp.gsc b/_codxe/qos/mods/example/maps/mp/gametypes/example_mp.gsc similarity index 100% rename from resources/qos/_codxe/mods/example/maps/mp/gametypes/example_mp.gsc rename to _codxe/qos/mods/example/maps/mp/gametypes/example_mp.gsc diff --git a/resources/t4/_codxe/codxe.json b/_codxe/t4/codxe.json similarity index 100% rename from resources/t4/_codxe/codxe.json rename to _codxe/t4/codxe.json diff --git a/resources/t4/_codxe/mods/codjumper/maps/mp/gametypes/cj.gsc b/_codxe/t4/mods/codjumper/maps/mp/gametypes/cj.gsc similarity index 100% rename from resources/t4/_codxe/mods/codjumper/maps/mp/gametypes/cj.gsc rename to _codxe/t4/mods/codjumper/maps/mp/gametypes/cj.gsc diff --git a/resources/t4/_codxe/mods/codjumper/maps/mp/gametypes/menu.gsc b/_codxe/t4/mods/codjumper/maps/mp/gametypes/menu.gsc similarity index 100% rename from resources/t4/_codxe/mods/codjumper/maps/mp/gametypes/menu.gsc rename to _codxe/t4/mods/codjumper/maps/mp/gametypes/menu.gsc diff --git a/resources/t4/_codxe/mods/codjumper/maps/mp/gametypes/tdm.gsc b/_codxe/t4/mods/codjumper/maps/mp/gametypes/tdm.gsc similarity index 100% rename from resources/t4/_codxe/mods/codjumper/maps/mp/gametypes/tdm.gsc rename to _codxe/t4/mods/codjumper/maps/mp/gametypes/tdm.gsc diff --git a/resources/t4/_codxe/mods/example/maps/_music.gsc b/_codxe/t4/mods/example/maps/_music.gsc similarity index 100% rename from resources/t4/_codxe/mods/example/maps/_music.gsc rename to _codxe/t4/mods/example/maps/_music.gsc diff --git a/resources/t4/_codxe/mods/example/maps/custom.gsc b/_codxe/t4/mods/example/maps/custom.gsc similarity index 100% rename from resources/t4/_codxe/mods/example/maps/custom.gsc rename to _codxe/t4/mods/example/maps/custom.gsc diff --git a/resources/t4/_codxe/mods/example/maps/mp/gametypes/_clientids.gsc b/_codxe/t4/mods/example/maps/mp/gametypes/_clientids.gsc similarity index 100% rename from resources/t4/_codxe/mods/example/maps/mp/gametypes/_clientids.gsc rename to _codxe/t4/mods/example/maps/mp/gametypes/_clientids.gsc diff --git a/resources/t4/_codxe/mods/example/maps/mp/gametypes/custom.gsc b/_codxe/t4/mods/example/maps/mp/gametypes/custom.gsc similarity index 100% rename from resources/t4/_codxe/mods/example/maps/mp/gametypes/custom.gsc rename to _codxe/t4/mods/example/maps/mp/gametypes/custom.gsc diff --git a/resources/t5/_codxe/codxe.json b/_codxe/t5/codxe.json similarity index 100% rename from resources/t5/_codxe/codxe.json rename to _codxe/t5/codxe.json diff --git a/resources/t5/_codxe/mods/example/maps/mp/gametypes/_clientids.gsc b/_codxe/t5/mods/example/maps/mp/gametypes/_clientids.gsc similarity index 100% rename from resources/t5/_codxe/mods/example/maps/mp/gametypes/_clientids.gsc rename to _codxe/t5/mods/example/maps/mp/gametypes/_clientids.gsc diff --git a/resources/t5/_codxe/mods/example/maps/mp/gametypes/example_mp.gsc b/_codxe/t5/mods/example/maps/mp/gametypes/example_mp.gsc similarity index 100% rename from resources/t5/_codxe/mods/example/maps/mp/gametypes/example_mp.gsc rename to _codxe/t5/mods/example/maps/mp/gametypes/example_mp.gsc diff --git a/build.py b/build.py index 4fefd013..722c560f 100644 --- a/build.py +++ b/build.py @@ -9,6 +9,7 @@ BINARY_PATH = r"build\Release\bin\codxe.xex" STAGING_DIR = r"build\staging" RESOURCES_PATH = r"resources" +DATA_PATH = r"_codxe" VERSION_HEADER_PATH = r"build\Release\obj\git_version.h" @@ -56,6 +57,13 @@ def read_git_version(): print(f"Resources directory not found at {RESOURCES_PATH}") exit(1) +if os.path.isdir(DATA_PATH): + shutil.copytree(DATA_PATH, os.path.join(STAGING_DIR, "_codxe"), dirs_exist_ok=True) + print("CoD Xe data directory copied successfully") +else: + print(f"CoD Xe data directory not found at {DATA_PATH}") + exit(1) + print("Copying binary to all title ID directories...") plugins_dir = os.path.join(STAGING_DIR, "xenia", "plugins") if os.path.exists(plugins_dir): diff --git a/codxe.vcxproj b/codxe.vcxproj index 902aba34..a2a1bfa4 100644 --- a/codxe.vcxproj +++ b/codxe.vcxproj @@ -85,6 +85,7 @@ + @@ -235,6 +236,7 @@ + diff --git a/docs/features.md b/docs/features.md index 36e67186..5f262317 100644 --- a/docs/features.md +++ b/docs/features.md @@ -6,7 +6,13 @@ The raw GSC loader enables loading `.gsc` scripts directly from the mod director ### Setup -Create a `_codxe\mods` folder in your game directory, and place a `codxe.json` in `_codxe` to define which mod is active. +Create a `_codxe\\mods` folder in your game directory, and place a `codxe.json` in `_codxe\` to define which mod is active. Use `iw2`, `iw3`, `iw4`, `iw5`, `t4`, `t5`, or `qos` for the game ID. + +The repository and release archive contain one top-level [`_codxe`](/_codxe) folder with a subdirectory for each game. Copy that folder into your game directory or a USB/HDD root, preserving `_codxe\\...`. All supported games that use CoD Xe data share this layout. Title updates and Xenia files remain separate from the game data. + +CoD Xe selects one data root at startup. If `_codxe\` exists, all config, mod, fastfile, usermap, internal asset, dump, and player stats paths use that root. Missing files never fall back to the legacy `_codxe` root. The old layout remains supported when the nested directory does not exist. Keep all data for a game together when migrating. + +On Xbox hardware, when neither local directory exists, CoD Xe searches `Usb0:\_codxe\` through `Usb4:\_codxe\`, then `Hdd1:\_codxe\`. The first existing directory becomes the only active root for reads and writes. USB/HDD roots only accept the nested layout. If no existing root is found, new files use the local `_codxe\` directory. Xenia uses the local directories. In `codxe.json`, set `"active_mod"` to the name of your mod folder: @@ -19,7 +25,7 @@ In `codxe.json`, set `"active_mod"` to the name of your mod folder: Once configured, the engine will redirect script lookups to: ```text -game:\_codxe\mods\my_mod\ +game:\_codxe\\mods\my_mod\ ``` Example tree structure: @@ -27,14 +33,15 @@ Example tree structure: ```text game:. `-- _codxe - |-- codxe.json - `-- mods - `-- my_mod - `-- maps - `-- mp - `-- gametypes - |-- _callbacksetup.gsc - `-- custom_logic.gsc + `-- + |-- codxe.json + `-- mods + `-- my_mod + `-- maps + `-- mp + `-- gametypes + |-- _callbacksetup.gsc + `-- custom_logic.gsc ``` The underscore keeps the folder at the top of file listings and separates CoD Xe system files from the game's core content. @@ -46,7 +53,7 @@ The loader operates using a virtual filesystem. All `.gsc` scripts, whether load For example: - A file in `common_mp.ff/maps/mp/gametypes/_callbacksetup.gsc` -- Can be overridden by `game:\_codxe\mods\my_mod\maps\mp\gametypes\_callbacksetup.gsc` +- Can be overridden by `game:\_codxe\\mods\my_mod\maps\mp\gametypes\_callbacksetup.gsc` Your version will take precedence over the copy embedded in the original fastfile. You can also add new scripts and call them from overridden entry points such as `_callbacksetup.gsc`. diff --git a/docs/t4.md b/docs/t4.md index c817d595..834bdbb8 100644 --- a/docs/t4.md +++ b/docs/t4.md @@ -220,7 +220,7 @@ self.god = false; ## Example Mods -Example T4 mods are available under [`resources/t4/_codxe/mods`](/resources/t4/_codxe/mods): +Example T4 mods are available under [`_codxe/t4/mods`](/_codxe/t4/mods): - `example` - Basic script examples for singleplayer and multiplayer. - `codjumper` - Codjumper-oriented scripts and menu examples. diff --git a/src/common/config.cpp b/src/common/config.cpp index f780173a..a30f30f2 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -9,35 +9,18 @@ #define INVALID_FILE_SIZE ((DWORD) - 1) #endif -const char *CONFIG_PATH = "game:\\_codxe\\codxe.json"; -const char *MOD_DIR = "game:\\_codxe\\mods"; -const char *DUMP_DIR = "game:\\_codxe\\dump"; - // Default values char Config::active_mod[MAX_PATH] = {}; bool Config::dump_rawfile = false; bool Config::dump_map_ents = false; -char Config::mod_base_path[MAX_PATH] = {}; std::string Config::data_root; -bool Config::shared_layout_enabled = false; std::vector Config::mounted_links; namespace { const char *CONFIG_DEVICE_LINK_NAME = "codxe:"; const char *CONFIG_DEVICE_LINK_PATH = "codxe:\\"; - -const char *GetGameDirectoryName(Config::GameId gameId) -{ - switch (gameId) - { - case Config::GAME_T4: - return "t4"; - case Config::GAME_NONE: - default: - return nullptr; - } -} +const char *const DEVICE_LINK_NAMESPACES[] = {"\\System??\\", "\\??\\"}; bool StartsWith(const std::string &value, const char *prefix) { @@ -65,30 +48,41 @@ bool TryGetDeviceRoot(const std::string &path, std::string &device_root) return true; } -bool MountDevice(const char *link_name, const char *device_path) +void UnmountDevice(const char *link_name) { - const DWORD process_type = KeGetCurrentProcessType(); - const std::string link_path = std::string(process_type == PROC_TYPE_SYSTEM ? "\\System??\\" : "\\??\\") + link_name; + for (size_t i = 0; i < ARRAYSIZE(DEVICE_LINK_NAMESPACES); ++i) + { + const std::string link_path = std::string(DEVICE_LINK_NAMESPACES[i]) + link_name; + STRING link = {}; + RtlInitAnsiString(&link, link_path.c_str()); + ObDeleteSymbolicLink(&link); + } +} - STRING link = {}; +bool MountDevice(const char *link_name, const char *device_path) +{ STRING device = {}; - RtlInitAnsiString(&link, link_path.c_str()); RtlInitAnsiString(&device, device_path); - const NTSTATUS delete_status = ObDeleteSymbolicLink(&link); - const NTSTATUS create_status = ObCreateSymbolicLink(&link, &device); - UNREFERENCED_PARAMETER(delete_status); - - return NT_SUCCESS(create_status); -} + // Plugin setup runs in the system process; game reads and writes run in the title process. + // DOS device links are namespace-specific, so both must point to the same selected device. + for (size_t i = 0; i < ARRAYSIZE(DEVICE_LINK_NAMESPACES); ++i) + { + const std::string link_path = std::string(DEVICE_LINK_NAMESPACES[i]) + link_name; + STRING link = {}; + RtlInitAnsiString(&link, link_path.c_str()); + ObDeleteSymbolicLink(&link); + const NTSTATUS status = ObCreateSymbolicLink(&link, &device); + if (!NT_SUCCESS(status)) + { + DbgPrint("[codxe][Config] Failed to mount %s -> %s: status=0x%08X\n", link_path.c_str(), device_path, + status); + UnmountDevice(link_name); + return false; + } + } -void UnmountDevice(const char *link_name) -{ - const DWORD process_type = KeGetCurrentProcessType(); - const std::string link_path = std::string(process_type == PROC_TYPE_SYSTEM ? "\\System??\\" : "\\??\\") + link_name; - STRING link = {}; - RtlInitAnsiString(&link, link_path.c_str()); - ObDeleteSymbolicLink(&link); + return true; } bool BuildMountedConfigPath(const std::string &device_config_path, std::string &mounted_config_path) @@ -166,14 +160,12 @@ bool ReadFileToString(const char *path, std::string &outString) return true; } -Config::Config(GameId gameId) +Config::Config(GameId::Type gameId) { data_root = "game:\\_codxe"; mounted_links.clear(); - const char *gameDirectoryName = GetGameDirectoryName(gameId); - shared_layout_enabled = gameDirectoryName != nullptr; - - std::string config_path = CONFIG_PATH; + const char *gameDirectoryName = GameId::ToString(gameId); + std::string config_path = filesystem::JoinPath(data_root.c_str(), "codxe.json"); if (xbox::GetEnvironment() != xbox::ENVIRONMENT_XENIA) { @@ -192,7 +184,7 @@ Config::Config(GameId gameId) if (slash != std::string::npos) { // On hardware Config is constructed before game: is retargeted to the new title. - // Only the config file load needs this early executable-relative path. + // Root selection and config loading need this early executable-relative path. config_path = full_path.substr(0, slash) + "\\_codxe\\codxe.json"; std::string mounted_config_path; @@ -207,7 +199,7 @@ Config::Config(GameId gameId) } } - if (shared_layout_enabled) + if (gameDirectoryName != nullptr) { // Config loads before game: is retargeted on hardware, so inspect the // executable-relative path while choosing the single active root. @@ -225,7 +217,9 @@ Config::Config(GameId gameId) } else { - data_root.clear(); + // If no existing root is found, new files use the local nested layout. + data_root = std::string("game:\\_codxe\\") + gameDirectoryName; + config_path = filesystem::JoinPath(nested_local_directory.c_str(), "codxe.json"); if (xbox::GetEnvironment() != xbox::ENVIRONMENT_XENIA) { // Only the game directory accepts the legacy layout. @@ -275,11 +269,9 @@ Config::~Config() { // Reset to defaults on cleanup active_mod[0] = '\0'; - mod_base_path[0] = '\0'; dump_rawfile = false; dump_map_ents = false; data_root.clear(); - shared_layout_enabled = false; for (size_t i = 0; i < mounted_links.size(); ++i) UnmountDevice(mounted_links[i].c_str()); mounted_links.clear(); @@ -341,13 +333,6 @@ bool Config::LoadFromJson(const char *jsonBuffer, DWORD bufferSize) DbgPrint(" Dump Raw Scripts: %s\n", dump_rawfile ? "true" : "false"); DbgPrint(" Dump Map Entities: %s\n", dump_map_ents ? "true" : "false"); - if (active_mod[0] != '\0') - { - // Config loads before game: is guaranteed to point at the new executable root on hardware. - // Keep the intended path and let later game-lifecycle file accesses validate it naturally. - _snprintf_s(mod_base_path, ARRAYSIZE(mod_base_path), _TRUNCATE, "%s\\%s", MOD_DIR, active_mod); - } - return true; } @@ -373,16 +358,19 @@ const char *Config::GetActiveMod() std::string Config::ResolveModPath(const char *relativePath) { - if (!relativePath || !*relativePath || !mod_base_path[0]) + if (!relativePath || !*relativePath || !active_mod[0]) return std::string(); - if (shared_layout_enabled) - { - const std::string mod_path = filesystem::JoinPath("mods", active_mod); - return ResolveDataPath(filesystem::JoinPath(mod_path.c_str(), relativePath).c_str()); - } + const std::string mod_path = filesystem::JoinPath("mods", active_mod); + return BuildDataPath(filesystem::JoinPath(mod_path.c_str(), relativePath).c_str()); +} + +std::string Config::BuildDataPath(const char *relativePath) +{ + if (!relativePath || data_root.empty()) + return std::string(); - return filesystem::JoinPath(mod_base_path, relativePath); + return filesystem::JoinPath(data_root.c_str(), relativePath); } std::string Config::ResolveDataPath(const char *relativePath) @@ -390,7 +378,7 @@ std::string Config::ResolveDataPath(const char *relativePath) if (!relativePath || !*relativePath || data_root.empty()) return std::string(); - const std::string path = filesystem::JoinPath(data_root.c_str(), relativePath); + const std::string path = BuildDataPath(relativePath); return filesystem::FileExists(path.c_str()) ? path : std::string(); } @@ -399,7 +387,7 @@ std::string Config::ResolveDataDirectory(const char *relativePath) if (!relativePath || !*relativePath || data_root.empty()) return std::string(); - const std::string path = filesystem::JoinPath(data_root.c_str(), relativePath); + const std::string path = BuildDataPath(relativePath); return filesystem::DirectoryExists(path.c_str()) ? path : std::string(); } diff --git a/src/common/config.h b/src/common/config.h index b94a509a..9a0fcbd2 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -1,23 +1,14 @@ #pragma once #include "pch.h" - -extern const char *CONFIG_PATH; -extern const char *MOD_DIR; -extern const char *DUMP_DIR; +#include "game_id.h" bool ReadFileToString(const char *path, std::string &outString); class Config : public Module { public: - enum GameId - { - GAME_NONE, - GAME_T4, - }; - - explicit Config(GameId gameId = GAME_NONE); + explicit Config(GameId::Type gameId); ~Config(); static bool dump_rawfile; @@ -25,15 +16,15 @@ class Config : public Module static const char *GetActiveMod(); static std::string ResolveModPath(const char *relativePath); + // Build paths within the root selected at startup, including files that do not exist yet. + static std::string BuildDataPath(const char *relativePath); static std::string ResolveDataPath(const char *relativePath); static std::string ResolveDataDirectory(const char *relativePath); static std::string ResolveDataPathForGameFile(const char *relativePath); private: static char active_mod[MAX_PATH]; - static char mod_base_path[MAX_PATH]; static std::string data_root; - static bool shared_layout_enabled; static std::vector mounted_links; bool LoadFromJson(const char *jsonBuffer, DWORD bufferSize); diff --git a/src/common/game_id.cpp b/src/common/game_id.cpp new file mode 100644 index 00000000..357aad11 --- /dev/null +++ b/src/common/game_id.cpp @@ -0,0 +1,28 @@ +#include "pch.h" +#include "game_id.h" + +namespace GameId +{ +const char *ToString(Type gameId) +{ + switch (gameId) + { + case IW2: + return "iw2"; + case IW3: + return "iw3"; + case IW4: + return "iw4"; + case IW5: + return "iw5"; + case T4: + return "t4"; + case T5: + return "t5"; + case QOS: + return "qos"; + default: + return nullptr; + } +} +} // namespace GameId diff --git a/src/common/game_id.h b/src/common/game_id.h new file mode 100644 index 00000000..c2064aae --- /dev/null +++ b/src/common/game_id.h @@ -0,0 +1,17 @@ +#pragma once + +namespace GameId +{ +enum Type +{ + IW2, + IW3, + IW4, + IW5, + T4, + T5, + QOS, +}; + +const char *ToString(Type gameId); +} // namespace GameId diff --git a/src/common/gsc_loader.cpp b/src/common/gsc_loader.cpp index 0043cd5e..967f3e91 100644 --- a/src/common/gsc_loader.cpp +++ b/src/common/gsc_loader.cpp @@ -52,7 +52,7 @@ void DumpSource(const char *scriptPath, const char *contents) if (!scriptPath || !contents) return; - const std::string dumpPath = filesystem::JoinPath(DUMP_DIR, scriptPath); + const std::string dumpPath = Config::BuildDataPath(filesystem::JoinPath("dump", scriptPath).c_str()); if (dumpPath.empty()) return; diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 8d1c6732..890844f4 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -43,12 +43,10 @@ void CreateDirectories(const char *path) NormalizePathSeparators(&directory[0]); char *p = &directory[0]; - const bool hasDrivePrefix = directory.size() >= 3 && p[1] == ':' && p[2] == '\\'; - const bool hasGamePrefix = directory.size() >= 6 && strncmp(p, "game:\\", 6) == 0; - - // Skip leading drive letter (e.g., "C:\") or "game:\" prefix - if (hasDrivePrefix || hasGamePrefix) - p += (hasDrivePrefix ? 3 : 6); // Move past "C:\" or "game:\" + const size_t rootSeparator = directory.find('\\'); + // Skip the device root, including multi-character links such as game: and codxeusb0:. + if (rootSeparator != std::string::npos && rootSeparator > 0 && directory[rootSeparator - 1] == ':') + p += rootSeparator + 1; for (; *p; p++) { @@ -75,10 +73,9 @@ void CreateParentDirectories(const char *path) if (lastSeparator == std::string::npos) return; - const bool isDriveRoot = lastSeparator == 2 && directory.size() > 1 && directory[1] == ':'; - const bool isGameRoot = - lastSeparator == 5 && directory.size() >= 6 && strncmp(directory.c_str(), "game:\\", 6) == 0; - if (isDriveRoot || isGameRoot) + const bool isDeviceRoot = + lastSeparator > 0 && directory[lastSeparator - 1] == ':' && directory.find('\\') == lastSeparator; + if (isDeviceRoot) { return; } diff --git a/src/game/iw2/mp/main.cpp b/src/game/iw2/mp/main.cpp index 7626f32f..211c0ee9 100644 --- a/src/game/iw2/mp/main.cpp +++ b/src/game/iw2/mp/main.cpp @@ -11,7 +11,7 @@ namespace mp IW2_MP_Plugin::IW2_MP_Plugin() { - RegisterModule(new Config()); + RegisterModule(new Config(GameId::IW2)); RegisterModule(new GSC()); RegisterModule(new scr_parser()); RegisterModule(new PlayerMovement()); diff --git a/src/game/iw2/sp/main.cpp b/src/game/iw2/sp/main.cpp index f1f31740..2463753f 100644 --- a/src/game/iw2/sp/main.cpp +++ b/src/game/iw2/sp/main.cpp @@ -9,7 +9,7 @@ namespace sp IW2_SP_Plugin::IW2_SP_Plugin() { - RegisterModule(new Config()); + RegisterModule(new Config(GameId::IW2)); RegisterModule(new scr_parser()); } diff --git a/src/game/iw3/mp/components/cmds.cpp b/src/game/iw3/mp/components/cmds.cpp index 797ec078..ac920405 100644 --- a/src/game/iw3/mp/components/cmds.cpp +++ b/src/game/iw3/mp/components/cmds.cpp @@ -16,7 +16,7 @@ void Cmd_Dumpraw_f() for (int i = 0; i < count; i++) { auto rawfile = files[i].rawfile; - const std::string dumpPath = filesystem::JoinPath(DUMP_DIR, rawfile->name); + const std::string dumpPath = Config::BuildDataPath(filesystem::JoinPath("dump", rawfile->name).c_str()); filesystem::WriteFileToDisk(dumpPath.c_str(), rawfile->buffer, rawfile->len); } } diff --git a/src/game/iw3/mp/components/fastfiles.cpp b/src/game/iw3/mp/components/fastfiles.cpp index f7697b90..c64db992 100644 --- a/src/game/iw3/mp/components/fastfiles.cpp +++ b/src/game/iw3/mp/components/fastfiles.cpp @@ -14,8 +14,8 @@ const char *const MOD_ZONE = "mod"; const char *const MOD_FASTFILE = "mod.ff"; const char *const CODXE_COMMON_ZONE = "codxe_common_mp"; const char *const CODXE_UI_ZONE = "codxe_ui_mp"; -const char *const CODXE_ZONE_DIRECTORY = "game:\\_codxe\\zone"; -const char *const USERMAPS_DIRECTORY = "game:\\_codxe\\usermaps"; +const char *const CODXE_ZONE_DIRECTORY = "zone"; +const char *const USERMAPS_DIRECTORY = "usermaps"; const char *const FASTFILE_EXTENSION = ".ff"; bool IsSafeZoneName(const char *name) @@ -39,7 +39,7 @@ std::string GetCodxeZoneFastfilePath(const char *zoneName) return std::string(); const std::string filename = std::string(zoneName) + FASTFILE_EXTENSION; - return filesystem::JoinPath(CODXE_ZONE_DIRECTORY, filename.c_str()); + return Config::BuildDataPath(filesystem::JoinPath(CODXE_ZONE_DIRECTORY, filename.c_str()).c_str()); } bool ContainsZone(const XZoneInfo *zoneInfo, unsigned int zoneCount, const char *name) @@ -109,9 +109,9 @@ std::string FastFiles::GetModFastfilePath() return ModList::ResolvePath(MOD_FASTFILE); } -const char *FastFiles::GetUsermapsDirectory() +std::string FastFiles::GetUsermapsDirectory() { - return USERMAPS_DIRECTORY; + return Config::BuildDataPath(USERMAPS_DIRECTORY); } std::string FastFiles::GetUsermapFastfilePath(const char *zoneName) @@ -128,7 +128,7 @@ std::string FastFiles::GetUsermapFastfilePath(const char *zoneName) directory.erase(directory.length() - 5); const std::string usermapDirectory = filesystem::JoinPath(USERMAPS_DIRECTORY, directory.c_str()); - return filesystem::JoinPath(usermapDirectory.c_str(), (filename + ".ff").c_str()); + return Config::BuildDataPath(filesystem::JoinPath(usermapDirectory.c_str(), (filename + ".ff").c_str()).c_str()); } int FastFiles::DB_BuildOSPath_Hook(const char *zoneName, unsigned int size, char *filename) diff --git a/src/game/iw3/mp/components/fastfiles.h b/src/game/iw3/mp/components/fastfiles.h index 6ef3fc3d..5c44d2bf 100644 --- a/src/game/iw3/mp/components/fastfiles.h +++ b/src/game/iw3/mp/components/fastfiles.h @@ -12,7 +12,7 @@ class FastFiles : public Module FastFiles(); ~FastFiles(); - static const char *GetUsermapsDirectory(); + static std::string GetUsermapsDirectory(); static std::string GetUsermapFastfilePath(const char *zoneName); static void ReloadModZone(); diff --git a/src/game/iw3/mp/components/image_loader.cpp b/src/game/iw3/mp/components/image_loader.cpp index 77203175..9f0a626d 100644 --- a/src/game/iw3/mp/components/image_loader.cpp +++ b/src/game/iw3/mp/components/image_loader.cpp @@ -412,7 +412,7 @@ std::string GetImageDumpPath(const char *imageName) sanitizedName.erase(std::remove_if(sanitizedName.begin(), sanitizedName.end(), [](char c) { return c == '*'; }), sanitizedName.end()); const std::string relativePath = GetImageRelativePath(sanitizedName.c_str()); - return filesystem::JoinPath(DUMP_DIR, relativePath.c_str()); + return Config::BuildDataPath(filesystem::JoinPath("dump", relativePath.c_str()).c_str()); } bool ReadBinaryFile(const std::string &path, std::vector *data) @@ -685,7 +685,7 @@ void Cmd_imagedump() ImageList imageList; R_GetImageList(&imageList); - const std::string imageDumpDirectory = filesystem::JoinPath(DUMP_DIR, "images"); + const std::string imageDumpDirectory = Config::BuildDataPath(filesystem::JoinPath("dump", "images").c_str()); filesystem::CreateDirectories(imageDumpDirectory.c_str()); for (unsigned int i = 0; i < imageList.count; ++i) diff --git a/src/game/iw3/mp/components/mods.cpp b/src/game/iw3/mp/components/mods.cpp index 8c614cf9..d7627eb7 100644 --- a/src/game/iw3/mp/components/mods.cpp +++ b/src/game/iw3/mp/components/mods.cpp @@ -11,7 +11,6 @@ namespace mp namespace { const float MODS_FEEDER_ID = 9.0f; -const char *const MODS_DIRECTORY = "game:\\_codxe\\mods"; const char *const FS_GAME_PREFIX = "mods/"; bool IsSafeModName(const char *name) @@ -85,7 +84,7 @@ std::string ModList::GetActiveName() std::string ModList::GetActivePath() { const std::string name = GetActiveName(); - return name.empty() ? std::string() : filesystem::JoinPath(MODS_DIRECTORY, name.c_str()); + return name.empty() ? std::string() : Config::BuildDataPath(filesystem::JoinPath("mods", name.c_str()).c_str()); } std::string ModList::ResolvePath(const char *relativePath) @@ -102,7 +101,7 @@ bool ModList::RunMod(const char *name) if (!fs_game || !IsSafeModName(name)) return false; - const std::string modPath = filesystem::JoinPath(MODS_DIRECTORY, name); + const std::string modPath = Config::BuildDataPath(filesystem::JoinPath("mods", name).c_str()); if (!filesystem::DirectoryExists(modPath.c_str())) { Com_PrintError(CON_CHANNEL_ERROR, "Mod directory does not exist: %s\n", modPath.c_str()); @@ -139,12 +138,13 @@ void ModList::ScanMods() ModsScanned = true; UIFeeder::SetSelectedIndex(MODS_FEEDER_ID, CurrentMod); - const std::string searchPattern = filesystem::JoinPath(MODS_DIRECTORY, "*"); + const std::string modsDirectory = Config::BuildDataPath("mods"); + const std::string searchPattern = filesystem::JoinPath(modsDirectory.c_str(), "*"); WIN32_FIND_DATAA findData; HANDLE findHandle = FindFirstFileA(searchPattern.c_str(), &findData); if (findHandle == INVALID_HANDLE_VALUE) { - DbgPrint("[codxe][IW3][ModList] Mod directory is unavailable: %s\n", MODS_DIRECTORY); + DbgPrint("[codxe][IW3][ModList] Mod directory is unavailable: %s\n", modsDirectory.c_str()); return; } @@ -156,7 +156,7 @@ void ModList::ScanMods() FeederEntry entry; entry.name = name; - const std::string directory = filesystem::JoinPath(MODS_DIRECTORY, name.c_str()); + const std::string directory = Config::BuildDataPath(filesystem::JoinPath("mods", name.c_str()).c_str()); entry.displayName = ReadDisplayName(filesystem::JoinPath(directory.c_str(), "description.txt"), name); Mods.push_back(entry); } while (FindNextFileA(findHandle, &findData) != 0); @@ -176,7 +176,8 @@ void ModList::ScanMods() UIFeeder::SetSelectedIndex(MODS_FEEDER_ID, CurrentMod); - DbgPrint("[codxe][IW3][ModList] Found %u mod(s) in %s\n", static_cast(Mods.size()), MODS_DIRECTORY); + DbgPrint("[codxe][IW3][ModList] Found %u mod(s) in %s\n", static_cast(Mods.size()), + modsDirectory.c_str()); } void ModList::EnsureModsScanned() diff --git a/src/game/iw3/mp/components/mpsp.cpp b/src/game/iw3/mp/components/mpsp.cpp index 5cdd45db..0a32a47b 100644 --- a/src/game/iw3/mp/components/mpsp.cpp +++ b/src/game/iw3/mp/components/mpsp.cpp @@ -114,7 +114,7 @@ namespace Asset std::string get_load_dir() { - return "game:\\_codxe\\internal"; + return Config::BuildDataPath("internal"); } namespace MapEnts_ { diff --git a/src/game/iw3/mp/components/stats.cpp b/src/game/iw3/mp/components/stats.cpp index 6ff68b63..af285b17 100644 --- a/src/game/iw3/mp/components/stats.cpp +++ b/src/game/iw3/mp/components/stats.cpp @@ -398,7 +398,7 @@ std::string GetStatsPath(unsigned int controllerIndex) _snprintf_s(filename, ARRAYSIZE(filename), _TRUNCATE, "controller_%u.stat", controllerIndex); } - return filesystem::JoinPath("game:\\_codxe\\players", filename); + return Config::BuildDataPath(filesystem::JoinPath("players", filename).c_str()); } bool LoadStats(unsigned int controllerIndex) diff --git a/src/game/iw3/mp/components/ui_feeder.cpp b/src/game/iw3/mp/components/ui_feeder.cpp index 51310abc..021b848f 100644 --- a/src/game/iw3/mp/components/ui_feeder.cpp +++ b/src/game/iw3/mp/components/ui_feeder.cpp @@ -78,14 +78,14 @@ void ScanUsermaps() usermapsScanned = true; UIFeeder::SetSelectedIndex(USERMAPS_FEEDER_ID, selectedUsermap); - const char *usermapsDirectory = FastFiles::GetUsermapsDirectory(); - const std::string searchPattern = filesystem::JoinPath(usermapsDirectory, "*"); + const std::string usermapsDirectory = FastFiles::GetUsermapsDirectory(); + const std::string searchPattern = filesystem::JoinPath(usermapsDirectory.c_str(), "*"); WIN32_FIND_DATAA findData; HANDLE findHandle = FindFirstFileA(searchPattern.c_str(), &findData); if (findHandle == INVALID_HANDLE_VALUE) { UpdateUsermapCounter(); - DbgPrint("[codxe][IW3][UIFeeder] Usermap directory is unavailable: %s\n", usermapsDirectory); + DbgPrint("[codxe][IW3][UIFeeder] Usermap directory is unavailable: %s\n", usermapsDirectory.c_str()); return; } @@ -104,7 +104,7 @@ void ScanUsermaps() FeederEntry entry; entry.name = name; - const std::string directory = filesystem::JoinPath(usermapsDirectory, name.c_str()); + const std::string directory = filesystem::JoinPath(usermapsDirectory.c_str(), name.c_str()); entry.displayName = ReadDisplayName(filesystem::JoinPath(directory.c_str(), "description.txt"), name); usermaps.push_back(entry); } while (FindNextFileA(findHandle, &findData) != 0); @@ -126,7 +126,7 @@ void ScanUsermaps() UpdateUsermapCounter(); DbgPrint("[codxe][IW3][UIFeeder] Found %u usermap(s) in %s\n", static_cast(usermaps.size()), - usermapsDirectory); + usermapsDirectory.c_str()); } void EnsureUsermapsScanned() diff --git a/src/game/iw3/mp/main.cpp b/src/game/iw3/mp/main.cpp index a59008cd..0b8132d3 100644 --- a/src/game/iw3/mp/main.cpp +++ b/src/game/iw3/mp/main.cpp @@ -38,6 +38,7 @@ IW3_MP_Plugin::IW3_MP_Plugin() // Special modules need to be registered first RegisterModule(new Patches()); + RegisterModule(new Config(GameId::IW3)); RegisterModule(new Events()); RegisterModule(new command()); RegisterModule(new UIScript()); diff --git a/src/game/iw3/sp/main.cpp b/src/game/iw3/sp/main.cpp index c90a2da6..7fbd73e8 100644 --- a/src/game/iw3/sp/main.cpp +++ b/src/game/iw3/sp/main.cpp @@ -84,7 +84,7 @@ void Load_MapEntsPtr_Hook() // Dump stock map ents if enabled (numEntityChars includes the null terminator, which is not written) if (Config::dump_map_ents && mapEnts->numEntityChars > 0) { - const std::string dumpPath = map_ents::BuildPath(DUMP_DIR, mapEnts->name); + const std::string dumpPath = map_ents::BuildPath(Config::BuildDataPath("dump").c_str(), mapEnts->name); if (!dumpPath.empty()) { filesystem::WriteFileToDisk(dumpPath.c_str(), mapEnts->entityString, mapEnts->numEntityChars - 1); @@ -138,7 +138,7 @@ void Cmd_Dumpraw_f() for (int i = 0; i < count; i++) { auto rawfile = files[i].rawfile; - const std::string dumpPath = filesystem::JoinPath(DUMP_DIR, rawfile->name); + const std::string dumpPath = Config::BuildDataPath(filesystem::JoinPath("dump", rawfile->name).c_str()); filesystem::WriteFileToDisk(dumpPath.c_str(), rawfile->buffer, rawfile->len); } } @@ -146,7 +146,7 @@ void Cmd_Dumpraw_f() IW3_SP_Plugin::IW3_SP_Plugin() { DbgPrint("IW3 SP: Plugin loaded\n"); - RegisterModule(new Config()); + RegisterModule(new Config(GameId::IW3)); RegisterModule(new Events()); RegisterModule(new command()); RegisterModule(new scr_parser()); diff --git a/src/game/iw4/mp/components/fastfiles.cpp b/src/game/iw4/mp/components/fastfiles.cpp index 1a9bfe18..fe4c02d9 100644 --- a/src/game/iw4/mp/components/fastfiles.cpp +++ b/src/game/iw4/mp/components/fastfiles.cpp @@ -8,16 +8,8 @@ namespace mp namespace { const char *const CODXE_PATCH_ZONE = "codxe_patch_mp"; -const char *const CODXE_PATCH_FILENAME = "codxe_patch_mp.ff"; -const char *const CODXE_PATCH_RELATIVE_PATH = "_codxe\\zone\\codxe_patch_mp.ff"; -const char *const CODXE_PATCH_PATH = "game:\\_codxe\\zone\\codxe_patch_mp.ff"; const char *const CODXE_UI_ZONE = "codxe_ui_mp"; -const char *const CODXE_UI_FILENAME = "codxe_ui_mp.ff"; -const char *const CODXE_UI_RELATIVE_PATH = "_codxe\\zone\\codxe_ui_mp.ff"; -const char *const CODXE_UI_PATH = "game:\\_codxe\\zone\\codxe_ui_mp.ff"; -const char *const CODXE_ZONE_RELATIVE_DIRECTORY = "_codxe\\zone\\"; const char *const CODXE_IMAGEFILE_FILENAME = "imagefile5.pak"; -const char *const GAME_DEVICE_PREFIX = "game:\\"; const char *const FASTFILE_EXTENSION = ".ff"; const unsigned int MAX_ZONE_COUNT = 32; @@ -79,8 +71,8 @@ bool IsSafeFastfileName(const char *filename) void DB_LoadXAssets_Hook(XZoneInfo *zoneInfo, unsigned int zoneCount, int sync) { auto original = DB_LoadXAssets_Detour.GetOriginal(); - const bool patchFileExists = filesystem::FileExists(CODXE_PATCH_PATH); - const bool uiFileExists = filesystem::FileExists(CODXE_UI_PATH); + const bool patchFileExists = !Config::ResolveDataPath("zone\\codxe_patch_mp.ff").empty(); + const bool uiFileExists = !Config::ResolveDataPath("zone\\codxe_ui_mp.ff").empty(); const XZoneInfo *stockPatchZone = FindZone(zoneInfo, zoneCount, "patch_mp"); const XZoneInfo *stockUiZone = FindZone(zoneInfo, zoneCount, "ui_mp"); const bool injectPatch = patchFileExists && stockPatchZone; @@ -126,28 +118,18 @@ int Sys_CreateFile_Hook(const char *dir, const char *filename) { auto original = Sys_CreateFile_Detour.GetOriginal(); - if (filename && std::strcmp(filename, CODXE_PATCH_FILENAME) == 0) - return original(dir, CODXE_PATCH_RELATIVE_PATH); - - if (filename && std::strcmp(filename, CODXE_UI_FILENAME) == 0) - return original(dir, CODXE_UI_RELATIVE_PATH); - - if (filename && std::strcmp(filename, CODXE_IMAGEFILE_FILENAME) == 0) + if (filename && (std::strcmp(filename, CODXE_IMAGEFILE_FILENAME) == 0 || IsSafeFastfileName(filename))) { - const std::string relativePath = std::string(CODXE_ZONE_RELATIVE_DIRECTORY) + filename; - const std::string devicePath = std::string(GAME_DEVICE_PREFIX) + relativePath; - - if (filesystem::FileExists(devicePath.c_str())) - return original(dir, relativePath.c_str()); - } - - if (IsSafeFastfileName(filename)) - { - const std::string relativePath = std::string(CODXE_ZONE_RELATIVE_DIRECTORY) + filename; - const std::string devicePath = std::string(GAME_DEVICE_PREFIX) + relativePath; - - if (filesystem::FileExists(devicePath.c_str())) - return original(dir, relativePath.c_str()); + const std::string path = Config::ResolveDataPath(filesystem::JoinPath("zone", filename).c_str()); + // Sys_CreateFile prepends the title directory, so pass a title-relative filename. + if (path.compare(0, 6, "game:\\") == 0) + return original(dir, path.substr(6).c_str()); + + // External roots use a device link directly, with the stock async/unbuffered read flags. + if (!path.empty()) + return reinterpret_cast(CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, + nullptr)); } return original(dir, filename); diff --git a/src/game/iw4/mp/main.cpp b/src/game/iw4/mp/main.cpp index d5844ee3..5198da6b 100644 --- a/src/game/iw4/mp/main.cpp +++ b/src/game/iw4/mp/main.cpp @@ -13,6 +13,7 @@ namespace mp IW4_MP_Plugin::IW4_MP_Plugin() { + RegisterModule(new Config(GameId::IW4)); RegisterModule(new Events()); RegisterModule(new fastfiles()); RegisterModule(new Branding()); diff --git a/src/game/iw4/mp_tu6/components/fastfiles.cpp b/src/game/iw4/mp_tu6/components/fastfiles.cpp index 24c1c816..29c6b41f 100644 --- a/src/game/iw4/mp_tu6/components/fastfiles.cpp +++ b/src/game/iw4/mp_tu6/components/fastfiles.cpp @@ -8,16 +8,8 @@ namespace mp_tu6 namespace { const char *const CODXE_PATCH_ZONE = "codxe_patch_mp"; -const char *const CODXE_PATCH_FILENAME = "codxe_patch_mp.ff"; -const char *const CODXE_PATCH_RELATIVE_PATH = "_codxe\\zone\\codxe_patch_mp.ff"; -const char *const CODXE_PATCH_PATH = "game:\\_codxe\\zone\\codxe_patch_mp.ff"; const char *const CODXE_UI_ZONE = "codxe_ui_mp"; -const char *const CODXE_UI_FILENAME = "codxe_ui_mp.ff"; -const char *const CODXE_UI_RELATIVE_PATH = "_codxe\\zone\\codxe_ui_mp.ff"; -const char *const CODXE_UI_PATH = "game:\\_codxe\\zone\\codxe_ui_mp.ff"; -const char *const CODXE_ZONE_RELATIVE_DIRECTORY = "_codxe\\zone\\"; const char *const CODXE_IMAGEFILE_FILENAME = "imagefile5.pak"; -const char *const GAME_DEVICE_PREFIX = "game:\\"; const char *const FASTFILE_EXTENSION = ".ff"; const unsigned int MAX_ZONE_COUNT = 32; @@ -86,8 +78,8 @@ bool IsSafeFastfileName(const char *filename) void DB_LoadXAssets_Hook(XZoneInfo *zoneInfo, unsigned int zoneCount, int sync) { auto original = DB_LoadXAssets_Detour.GetOriginal(); - const bool patchFileExists = filesystem::FileExists(CODXE_PATCH_PATH); - const bool uiFileExists = filesystem::FileExists(CODXE_UI_PATH); + const bool patchFileExists = !Config::ResolveDataPath("zone\\codxe_patch_mp.ff").empty(); + const bool uiFileExists = !Config::ResolveDataPath("zone\\codxe_ui_mp.ff").empty(); const XZoneInfo *stockPatchZone = FindZone(zoneInfo, zoneCount, "patch_mp"); const XZoneInfo *stockUiZone = FindZone(zoneInfo, zoneCount, "ui_mp"); const bool injectPatch = patchFileExists && stockPatchZone; @@ -133,28 +125,21 @@ SysFile Sys_CreateFile_Hook(const char *dir, const char *filename) { auto original = Sys_CreateFile_Detour.GetOriginal(); - if (filename && std::strcmp(filename, CODXE_PATCH_FILENAME) == 0) - return original(dir, CODXE_PATCH_RELATIVE_PATH); - - if (filename && std::strcmp(filename, CODXE_UI_FILENAME) == 0) - return original(dir, CODXE_UI_RELATIVE_PATH); - - if (filename && std::strcmp(filename, CODXE_IMAGEFILE_FILENAME) == 0) - { - const std::string relativePath = std::string(CODXE_ZONE_RELATIVE_DIRECTORY) + filename; - const std::string devicePath = std::string(GAME_DEVICE_PREFIX) + relativePath; - - if (filesystem::FileExists(devicePath.c_str())) - return original(dir, relativePath.c_str()); - } - - if (IsSafeFastfileName(filename)) + if (filename && (std::strcmp(filename, CODXE_IMAGEFILE_FILENAME) == 0 || IsSafeFastfileName(filename))) { - const std::string relativePath = std::string(CODXE_ZONE_RELATIVE_DIRECTORY) + filename; - const std::string devicePath = std::string(GAME_DEVICE_PREFIX) + relativePath; + const std::string path = Config::ResolveDataPath(filesystem::JoinPath("zone", filename).c_str()); + // Sys_CreateFile prepends the title directory, so pass a title-relative filename. + if (path.compare(0, 6, "game:\\") == 0) + return original(dir, path.substr(6).c_str()); - if (filesystem::FileExists(devicePath.c_str())) - return original(dir, relativePath.c_str()); + // External roots use a device link directly, with the stock async/unbuffered read flags. + if (!path.empty()) + { + SysFile file = {CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, nullptr), + 0}; + return file; + } } return original(dir, filename); diff --git a/src/game/iw4/mp_tu6/main.cpp b/src/game/iw4/mp_tu6/main.cpp index 28585c60..873088fd 100644 --- a/src/game/iw4/mp_tu6/main.cpp +++ b/src/game/iw4/mp_tu6/main.cpp @@ -22,7 +22,7 @@ namespace mp_tu6 IW4_MP_TU6_Plugin::IW4_MP_TU6_Plugin() { - RegisterModule(new Config()); + RegisterModule(new Config(GameId::IW4)); RegisterModule(new Events()); // Must be registered first to ensure hooks are in place RegisterModule(new fastfiles()); RegisterModule(new cg()); diff --git a/src/game/iw4/sp/components/clipmap.cpp b/src/game/iw4/sp/components/clipmap.cpp index 4e295b3f..ee025d96 100644 --- a/src/game/iw4/sp/components/clipmap.cpp +++ b/src/game/iw4/sp/components/clipmap.cpp @@ -20,7 +20,7 @@ void Load_clipMap_t_Hook(bool atStreamStart) // Dump map entities if enabled if (Config::dump_map_ents) { - const std::string dumpPath = map_ents::BuildPath(DUMP_DIR, mapEnts->name); + const std::string dumpPath = map_ents::BuildPath(Config::BuildDataPath("dump").c_str(), mapEnts->name); if (!dumpPath.empty()) { filesystem::WriteFileToDisk(dumpPath.c_str(), mapEnts->entityString, mapEnts->numEntityChars - 1); diff --git a/src/game/iw4/sp/main.cpp b/src/game/iw4/sp/main.cpp index a5aaebaa..48e472aa 100644 --- a/src/game/iw4/sp/main.cpp +++ b/src/game/iw4/sp/main.cpp @@ -33,7 +33,7 @@ IW4_SP_Plugin::IW4_SP_Plugin() RemoveIdleGunSway(); - RegisterModule(new Config()); + RegisterModule(new Config(GameId::IW4)); RegisterModule(new cg()); RegisterModule(new clipmap()); RegisterModule(new GSCFields()); diff --git a/src/game/iw5/mp/main.cpp b/src/game/iw5/mp/main.cpp index ccf809da..f5bf38c7 100644 --- a/src/game/iw5/mp/main.cpp +++ b/src/game/iw5/mp/main.cpp @@ -219,7 +219,7 @@ bool DB_IsXAssetDefault_Hook(XAssetType type, const char *name) IW5_MP_Plugin::IW5_MP_Plugin() { - RegisterModule(new Config()); + RegisterModule(new Config(GameId::IW5)); RegisterModule(new Events()); RegisterModule(new Branding()); RegisterModule(new patches()); diff --git a/src/game/qos/mp/main.cpp b/src/game/qos/mp/main.cpp index c9f14f9c..98705e67 100644 --- a/src/game/qos/mp/main.cpp +++ b/src/game/qos/mp/main.cpp @@ -14,7 +14,7 @@ namespace mp QOS_MP_Plugin::QOS_MP_Plugin() { DbgPrint("QOS SP: Registering modules\n"); - RegisterModule(new Config()); + RegisterModule(new Config(GameId::QOS)); RegisterModule(new Events()); RegisterModule(new clipmap()); RegisterModule(new GSC()); diff --git a/src/game/qos/sp/main.cpp b/src/game/qos/sp/main.cpp index 844b9e8a..761495e8 100644 --- a/src/game/qos/sp/main.cpp +++ b/src/game/qos/sp/main.cpp @@ -9,7 +9,7 @@ namespace sp QOS_SP_Plugin::QOS_SP_Plugin() { DbgPrint("QOS SP: Registering modules\n"); - RegisterModule(new Config()); + RegisterModule(new Config(GameId::QOS)); RegisterModule(new scr_parser()); } diff --git a/src/game/t4/mp/components/map.cpp b/src/game/t4/mp/components/map.cpp index ed120e0c..273832f4 100644 --- a/src/game/t4/mp/components/map.cpp +++ b/src/game/t4/mp/components/map.cpp @@ -68,7 +68,7 @@ void Load_clipMap_t_Hook(bool atStreamStart) // Dump map entities if enabled if (Config::dump_map_ents) { - const std::string dumpPath = map_ents::BuildPath(DUMP_DIR, mapEnts->name); + const std::string dumpPath = map_ents::BuildPath(Config::BuildDataPath("dump").c_str(), mapEnts->name); if (!dumpPath.empty()) { filesystem::WriteFileToDisk(dumpPath.c_str(), mapEnts->entityString, mapEnts->numEntityChars - 1); diff --git a/src/game/t4/mp/main.cpp b/src/game/t4/mp/main.cpp index 80db9204..67b9863b 100644 --- a/src/game/t4/mp/main.cpp +++ b/src/game/t4/mp/main.cpp @@ -27,7 +27,7 @@ T4_MP_Plugin::T4_MP_Plugin() RegisterModule(new Debug()); #endif - RegisterModule(new Config()); + RegisterModule(new Config(GameId::T4)); RegisterModule(new Events()); // Must be registered before modules that subscribe to engine events. RegisterModule(new Branding()); RegisterModule(new BrushCollision()); diff --git a/src/game/t4/sp/components/clipmap.cpp b/src/game/t4/sp/components/clipmap.cpp index c07da257..23d6cd17 100644 --- a/src/game/t4/sp/components/clipmap.cpp +++ b/src/game/t4/sp/components/clipmap.cpp @@ -68,7 +68,7 @@ void Load_clipMap_t_Hook(bool atStreamStart) // Dump map entities if enabled if (Config::dump_map_ents) { - const std::string dumpPath = map_ents::BuildPath(DUMP_DIR, mapEnts->name); + const std::string dumpPath = map_ents::BuildPath(Config::BuildDataPath("dump").c_str(), mapEnts->name); if (!dumpPath.empty()) { filesystem::WriteFileToDisk(dumpPath.c_str(), mapEnts->entityString, mapEnts->numEntityChars - 1); diff --git a/src/game/t4/sp/main.cpp b/src/game/t4/sp/main.cpp index 375607b6..84ed9200 100644 --- a/src/game/t4/sp/main.cpp +++ b/src/game/t4/sp/main.cpp @@ -61,7 +61,7 @@ T4_SP_Plugin::T4_SP_Plugin() // Default ui_autoContinue on so level loads do not wait for input in solo or split-screen. *(volatile uint8_t *)0x82279B07 = 0x01; - RegisterModule(new Config(Config::GAME_T4)); + RegisterModule(new Config(GameId::T4)); RegisterModule(new Events()); // Must be registered before modules that subscribe to engine events. RegisterModule(new FastFiles()); RegisterModule(new clipmap()); diff --git a/src/game/t5/mp/main.cpp b/src/game/t5/mp/main.cpp index bfb0dec3..0f604ec4 100644 --- a/src/game/t5/mp/main.cpp +++ b/src/game/t5/mp/main.cpp @@ -10,7 +10,7 @@ namespace mp T5_MP_Plugin::T5_MP_Plugin() { DbgPrint("T5 MP: Registering modules\n"); - RegisterModule(new Config()); + RegisterModule(new Config(GameId::T5)); RegisterModule(new scr_parser()); } diff --git a/src/game/t5/sp/main.cpp b/src/game/t5/sp/main.cpp index dcb73bd3..27a53ac2 100644 --- a/src/game/t5/sp/main.cpp +++ b/src/game/t5/sp/main.cpp @@ -10,7 +10,7 @@ namespace sp T5_SP_Plugin::T5_SP_Plugin() { DbgPrint("T5 SP: Registering modules\n"); - RegisterModule(new Config()); + RegisterModule(new Config(GameId::T5)); RegisterModule(new scr_parser()); }